In this post, I want to go through using Python's test package index and then deploying a pre-release version to the actual Python index.
First, I changed the version. The development release was discouraged, so I am going with an alpha pre-release.
0.0.1.a1 (Python later changed this to
It could easily have been
1.0.1.a1. However, it doesn't seem unusual to use the
This wasn't the last change that I had to make to the project since the last article, so let's work through a few more.
We're going back to the documentation on packaging Python projects.
I added a
pyproject.toml per the documentation. This code is pulled straight from the docs and doesn't use anything custom. The file is in the root folder at the top level.
[build-system] requires = [ "setuptools>=42", "wheel" ] build-backend = "setuptools.build_meta"
Previously, the project has a
setup.py file. However, it's not recommended to use that type of file because the values can be dynamic. A static setup file is preferred.
This other static setup file,
setup.cfg, has many of the same inputs as
setup.py. It's short, and the syntax is a little different (no quotation marks), but the information is fundamental.
[metadata] name = beasy version = 0.0.1.a1 url = https://github.com/jdretz/simple-bea-client author = Jarrett Retz author_email = firstname.lastname@example.org classifiers = Programming Language :: Python :: 3 License :: OSI Approved :: MIT License Operating System :: OS Independent description = Simple Python API client for accessing data on the Bureau of Economic Analysis application programming interface. long_description = file: README.md long_description_content_type = text/markdown [options] python_requires = >=3.6 here = pathlib.Path(__file__).parent.resolve() # Get the long description from the README file long_description = (here / 'README.md').read_text(encoding='utf-8')
Next, we can generate the distribution archive files. We'll need the latest version of Python's
build module. We can run the command below:
python3 -m pip install --upgrade build
Then, in our project root directory, we can run the build command to generate the files.
python -m build
After executing the build command, I got the following output.
Collecting wheel Using cached wheel-0.36.2-py2.py3-none-any.whl (35 kB) Collecting setuptools>=42 Using cached setuptools-53.0.0-py3-none-any.whl (784 kB) Installing collected packages: wheel, setuptools Successfully installed setuptools-53.0.0 wheel-0.36.2 WARNING: You are using pip version 20.3.3; however, version 21.0.1 is available. You should consider upgrading via the '/Library/Frameworks/Python.framework/Versions/3.9/bin/python3 -m pip install --upgrade pip' command. /private/var/folders/qw/yqqx13kn74v_mjyknjykpm2h0000gn/T/build-env-39ze5cdf/lib/python3.9/site-packages/setuptools/dist.py:461: UserWarning: Normalizing '0.0.1.a1' to '0.0.1a1' warnings.warn(tmpl.format(**locals())) running sdist running egg_info writing beasy.egg-info/PKG-INFO writing dependency_links to beasy.egg-info/dependency_links.txt writing requirements to beasy.egg-info/requires.txt writing top-level names to beasy.egg-info/top_level.txt reading manifest file 'beasy.egg-info/SOURCES.txt' writing manifest file 'beasy.egg-info/SOURCES.txt' running check creating beasy-0.0.1a1 creating beasy-0.0.1a1/beasy.egg-info copying files to beasy-0.0.1a1... copying README.md -> beasy-0.0.1a1 copying pyproject.toml -> beasy-0.0.1a1 copying setup.cfg -> beasy-0.0.1a1 copying setup.py -> beasy-0.0.1a1 copying beasy.egg-info/PKG-INFO -> beasy-0.0.1a1/beasy.egg-info copying beasy.egg-info/SOURCES.txt -> beasy-0.0.1a1/beasy.egg-info copying beasy.egg-info/dependency_links.txt -> beasy-0.0.1a1/beasy.egg-info copying beasy.egg-info/requires.txt -> beasy-0.0.1a1/beasy.egg-info copying beasy.egg-info/top_level.txt -> beasy-0.0.1a1/beasy.egg-info Writing beasy-0.0.1a1/setup.cfg Creating tar archive removing 'beasy-0.0.1a1' (and everything under it) /private/var/folders/qw/yqqx13kn74v_mjyknjykpm2h0000gn/T/build-env-39ze5cdf/lib/python3.9/site-packages/setuptools/dist.py:461: UserWarning: Normalizing '0.0.1.a1' to '0.0.1a1' warnings.warn(tmpl.format(**locals())) running bdist_wheel running build installing to build/bdist.macosx-10.9-x86_64/wheel running install running install_egg_info running egg_info writing beasy.egg-info/PKG-INFO writing dependency_links to beasy.egg-info/dependency_links.txt writing requirements to beasy.egg-info/requires.txt writing top-level names to beasy.egg-info/top_level.txt reading manifest file 'beasy.egg-info/SOURCES.txt' writing manifest file 'beasy.egg-info/SOURCES.txt' Copying beasy.egg-info to build/bdist.macosx-10.9-x86_64/wheel/beasy-0.0.1a1-py3.9.egg-info running install_scripts adding license file "LICENSE" (matched pattern "LICEN[CS]E*") creating build/bdist.macosx-10.9-x86_64/wheel/beasy-0.0.1a1.dist-info/WHEEL creating '/Users/jarrettretz/Programming/bea/dist/tmp6jhwb_pj/beasy-0.0.1a1-py3-none-any.whl' and adding 'build/bdist.macosx-10.9-x86_64/wheel' to it adding 'beasy-0.0.1a1.dist-info/LICENSE' adding 'beasy-0.0.1a1.dist-info/METADATA' adding 'beasy-0.0.1a1.dist-info/WHEEL' adding 'beasy-0.0.1a1.dist-info/top_level.txt' adding 'beasy-0.0.1a1.dist-info/RECORD' removing build/bdist.macosx-10.9-x86_64/wheel
It appears that things worked!
New files were created in the project. The project structure can be represented as:
. ├── LICENSE ├── Pipfile ├── Pipfile.lock ├── README.md ├── beasy │ ├── __init__.py │ ├── base.py │ ├── beasy.py │ └── tables │ └── tables.py ├── beasy.egg-info │ ├── PKG-INFO │ ├── SOURCES.txt │ ├── dependency_links.txt │ ├── requires.txt │ └── top_level.txt ├── build │ └── bdist.macosx-10.9-x86_64 ├── dist │ ├── beasy-0.0.1a1-py3-none-any.whl │ └── beasy-0.0.1a1.tar.gz ├── pyproject.toml ├── setup.cfg ├── setup.py └── tests
The two new folders are:
Publishing to Test Python Index
Python has a useful test package index. It's called Test PyPI. The first thing you’ll need to do is register an account on Test PyPI.
Then, create an API token for uploading to the test index.
Next, we can make sure that we have
twine installed and in its latest version.
python3 -m pip install --upgrade twine
Once installed, run Twine to upload all of the archives under
python3 -m twine upload --repository testpypi dist/*
You will be prompted for a username and password. For the username, use
__token__. For the password, use the API token value, including the
jarrettretz@MacBook-Pro bea % python3 -m twine upload --repository testpypi dist/* Uploading distributions to https://test.pypi.org/legacy/ Enter your username: __token__ Enter your password: Uploading beasy-0.0.1a1-py3-none-any.whl 100%|██████████████████████████████████████| 7.49k/7.49k [00:01<00:00, 6.25kB/s] Uploading beasy-0.0.1a1.tar.gz 100%|██████████████████████████████████████| 9.55k/9.55k [00:01<00:00, 8.70kB/s] View at: https://test.pypi.org/project/beasy/0.0.1a1/
Success, again! I was able to view the package online!
You can also install the packages on the test index. However, it's not guarantee how long they will be available. To install the test package, I ran:
pip install -i --no-deps --index-url https://test.pypi.org/simple/ beasy==0.0.1a1
jarrettretz@MacBook-Pro ~ % conda activate base (base) jarrettretz@MacBook-Pro ~ % pip install -i --no-deps --index-url https://test.pypi.org/simple/ beasy==0.0.1a1 Looking in indexes: https://test.pypi.org/simple/ Requirement already satisfied: beasy==0.0.1a1 in ./Programming/bea (0.0.1a1) Requirement already satisfied: requests in /opt/anaconda3/lib/python3.8/site-packages (from beasy==0.0.1a1) (2.25.0) Requirement already satisfied: chardet<4,>=3.0.2 in /opt/anaconda3/lib/python3.8/site-packages (from requests->beasy==0.0.1a1) (3.0.4) Requirement already satisfied: idna<3,>=2.5 in /opt/anaconda3/lib/python3.8/site-packages (from requests->beasy==0.0.1a1) (2.10) Requirement already satisfied: certifi>=2017.4.17 in /opt/anaconda3/lib/python3.8/site-packages (from requests->beasy==0.0.1a1) (2020.11.8) Requirement already satisfied: urllib3<1.27,>=1.21.1 in /opt/anaconda3/lib/python3.8/site-packages (from requests->beasy==0.0.1a1) (1.25.11) WARNING: You are using pip version 21.0; however, version 21.0.1 is available. You should consider upgrading via the '/opt/anaconda3/bin/python -m pip install --upgrade pip' command. (base) jarrettretz@MacBook-Pro ~ % python Python 3.8.3 (default, Jul 2 2020, 11:26:31) [Clang 10.0.0 ] :: Anaconda, Inc. on darwin Type "help", "copyright", "credits" or "license" for more information. >>> from beasy.beasy import Bea >>>
Now that we know the package works, we can try to publish it to the real index.
Publish to PyPI
As I mentioned, we now need to create an account on PyPI. The credentials aren't shared. Additionally, we need a token for the actual index.
We already created the distribution files. Therefore, we need to publish these to PyPI using
In the root project folder, run:
twine upload dist/*
Enter __token__ for username and the new API token for the password.
jarrettretz@MacBook-Pro bea % twine upload dist/* Uploading distributions to https://upload.pypi.org/legacy/ Enter your username: __token__ Enter your password: Uploading beasy-0.0.1a1-py3-none-any.whl 100%|████████████████████████████████████████████████████████████████████████████████████████| 7.49k/7.49k [00:00<00:00, 20.7kB/s] 100%|████████████████████████████████████████████████████████████████████████████████████████| 7.49k/7.49k [00:01<00:00, 4.51kB/s] Uploading beasy-0.0.1a1.tar.gz 100%|████████████████████████████████████████████████████████████████████████████████████████| 9.55k/9.55k [00:00<00:00, 10.7kB/s] View at: https://pypi.org/project/beasy/0.0.1a1/
Now, the package is live at https://pypi.org/project/beasy/0.0.1a1/.
Because the package is using an alpha version, it can be installed with
pip install beasy==0.0.1a1. This statement is explicit about the version.
Python removed the period that I had before the
a in the version name, so I needed to update the README.md.
Upload to Github
Finally, since the package is live, I need to upload the project to Github.
I found a basic
.gitignore file online that will prevent unnecessary files from being pushed.
To push the repository to Github, in the repository root, I first ran the command
git init to push the repository to Github in the repository root.
After that, I added the remote origin:
git remote add origin https://github.com/jdretz/simple-bea-client.git
Finally, I committed the files (with the message "init commit") and pushed up to Github.
git push -u origin master
The project is now ready for use on PyPI and available on Github at https://github.com/jdretz/simple-bea-client.
This has been a reasonable and enjoyable experience. If you have made it through reading the full series, I hope it was beneficial somehow.
I still need to publish the first version and create examples for the README. However, the concludes this series on building a Python package. Thanks for reading!