Publishing PyPi packages Being in the process of publishing my second PyPi-package, I take notes on the process for quicker turn-around in the future.
I usually start my projects very barebones, with a single directory and a main.py file:
$ tree project-name ├── main.py ├── README.md ├── requirements.txt
After something useful has been hacked together, I start moving things around.
$ tree project-name ├── LICENSE ├── README.md ├── data │ └── example_data.txt ├── package_name │ ├── __init__.py │ └── package_name.py ├── requirements.txt ├── setup.py └── tests
As an MVP, the important thing here is to move the
main.py into a package directory and to create a
setup.py file looks something like this:
import setuptools with open('README.md', 'r') as fh: long_description = fh.read() setuptools.setup( name='project_name', version='0.0.1', author='Casper Lehmann', author_email='@.com', description='Project description', long_description=long_description, long_description_content_type='text/markdown', url='https://github.com/casperlehmann/project-name', packages=setuptools.find_packages(), classifiers=[ 'Programming Language :: Python :: 3', 'License :: OSI Approved :: MIT License', 'Operating System :: OS Independent', ], python_requires='>=3.6', install_requires=[ 'wheel', ], )
To test the installation process, run:
$ python setup.py sdist bdist_wheel
A classic error to get on this one is:
$ python setup.py sdist bdist_wheel usage: setup.py [global_opts] cmd1 [cmd1_opts] [cmd2 [cmd2_opts] ...] or: setup.py --help [cmd1 cmd2 ...] or: setup.py --help-commands or: setup.py cmd --help error: invalid command 'bdist_wheel'
The problem here is that the wheel package is not installed. Pip install it in your venv, or globally, if you like to YOLO.
$ pip install wheel Collecting wheel Using cached wheel-0.36.2-py2.py3-none-any.whl (35 kB) Installing collected packages: wheel Successfully installed wheel-0.36.2
setup.py again, and you’ll get a
dist-directory in your project. This contains all that needs to be uploaded.
Register with PyPi
$ pip install twine
Upload to TestPyPi
$ twine upload --repository testpypi dist/*
Pip install with no-deps, since we cannot guarantee that TestPyPi has the same packages available as PyPi.
Note: This example uses —index-url flag to specify TestPyPI instead of live PyPI. Additionally, it specifies —no-deps. Since TestPyPI doesn’t have the same packages as the live PyPI, it’s possible that attempting to install dependencies may fail or install something unexpected. While our example package doesn’t have any dependencies, it’s a good practice to avoid installing dependencies when using TestPyPI.
Try it in a new venv.
$ python -m venv .venv $ pip install --no-deps -i https://test.pypi.org/simple/ project-name==0.0.1 $ python -m project_name
The last command will fail if there are missing packages, but that’s OK as long as our package installed.
$ twine upload dist/*
$ pip install project_name
Adding command line script
Two steps need to be completed to install a package as a command line on your system.
Write a script that handles arguments, etc. Then specify the inclusion of this script in
setup.py add the following:
setuptools.setup( ... scripts = ['bin/script-name'], )
Then create the file
bin/script-name (no extension required), and write something like the following:
#!/usr/bin/env python import argparse from project_name import function_name parser = argparse.ArgumentParser(description='Describe the functionality') parser.add_argument('Path', metavar='path', type=str, help='the path to some file') args = parser.parse_args() function_name.convert(args.Path)