I have recently tried to upload a package to PyPI with 2FA enabled and would like to share my experience.
More or less at random, I elected to use
hatch for this package. However, using
hatch publish gave mystifying errors (it doesn’t help that
hatch seems to use home-grown mechanisms to store credentials?).
I then switched to
twine, which gave me a slightly more helpful error message…
User XXX has two factor auth enabled, an API Token or Trusted Publisher must be used to upload in place of password.
… but only slightly, since it didn’t tell me how to actually use an API token (it also didn’t tell me how to create a token, but I figured that must be done from the PyPI account settings).
I then created an API token, and thought that I could try
hatch publish again, just by pasting the API token in the “credentials” prompt instead of my PyPI password (by the way why does it say “credentials” instead of a more explicit “password” or “token”?). Which didn’t work.
twine again, I copied the snippet from the API token creation results into my
.pypirc and manually changed the required information such as the project name (a tedious operation, I have to say). I also noticed that the special username
__token__ was used for that purpose instead of my regular username.
Now I can upload using
twine upload -r my_project_name ..., which works, but I have to remember to pass
-r my_project_name. The project name actually refers to an entry in
.pypirc that contains the project-specific API token, and pretends to be a separate repository entry…
However, I still don’t know how I could do all the above using
hatch instead (should I have gone with something else from the start?).
I would add that neither
hatch publish ever mention 2FA in their respective command-line helps. The
hatch online docs revolve around classic password auth (I admit I haven’t checked the
twine online docs). This is unfortunate since 2FA is strongly recommended these days.
Side note: at first I had to create an account-wide API token, since the project I wanted to upload didn’t exist yet. Once I managed to create the project by uploading, I deleted the account-wide API token and created project-specific one. I then had to reconfigure
.pypirc a second time…
Side note #2: I just wanted to actually register the project so as to reserve the name. It is obviously not possible (why?), so I had to upload a version and immediately delete it…