Read time: 4.9 minutes (492 words)
Step 7: Publishing on PyPi¶
Python packages, including the mmdesigner application we are building, usually end up being published on the Python Package Index server. Once there, interested folks can install this tool on their systems using the standard pip command.
Our next job involves adding the structure needed to publish and maintain the project on PyPi.
Setup Files¶
To publish a project on PyPi, a setup.py file is required. This file contains information about the project that will end up being displayed on PyPi for interested folks to examine. Here is the file for this project:
1from setuptools import setup
2import io
3import re
4from os.path import dirname
5from os.path import join
6
7def read(*names, **kwargs):
8 with io.open(
9 join(dirname(__file__), *names),
10 encoding=kwargs.get('encoding', 'utf8')
11 ) as fh:
12 return fh.read()
13
14setup(
15 name='mmdesigner',
16 description='Indoor model airplane design using OpenSCAD',
17 long_description=re.compile(
18 '^.. start-badges.*^.. end-badges',
19 re.M | re.S
20 ).sub(
21 '',
22 read('README.rst')
23 ),
24 long_description_content_type='text/x-rst',
25 author='Roie R. Black',
26 author_email='roie.black@gmail.com',
27 url='https://github.com/rblack42/math-magik',
28 license='BSD',
29 version='0.1.10',
30 packages=['mmdesigner'],
31entry_points= {
32 "console_scripts": [
33 "mmd = mmdesigner.cli:cli"
34 ]
35 },
36 python_requires='>=3.7, <3.10',
37 classifiers=[
38 'Development Status :: 4 - Beta',
39 'Intended Audience :: Developers',
40 'Framework :: tox',
41 'License :: OSI Approved :: BSD License',
42 'Programming Language :: Python',
43 'Programming Language :: Python :: 3',
44 'Programming Language :: Python :: 3.7',
45 'Programming Language :: Python :: 3.8',
46 'Programming Language :: Python :: 3.9',
47 'Programming Language :: Python :: Implementation :: CPython',
48 'Programming Language :: Python :: Implementation :: PyPy',
49 'Topic :: Software Development :: Testing',
50 ],
51)
Details on all of this can be found in the pyPi documentation.
I also added one more file which aids in creating the package uploaded to PyPi
1[bdist_wheel]
2universal = 1
Updating Version Numbers¶
There is a version number in the setup.py file. Every time we create a version of the project that we want to let users access on PyPi we will need to update this number. PyPi does not let you update the version currently shown (the latest) after publishing it.
So far, the version number appears in three places in this project:
README.rst - seen on GitHub
mmdesigner/__version__.py - the master project version number
setup.py - PyPi control file
Managing all three of these can be a problem, so there is a nice tool that helps keep them on track: bump2version.
Using this tool, which we can add to the requirements.txt file, involves creating a configuration file that looks like this:
1[bumpversion]
2current_version = 0.1.10
3commit = True
4tag = True
5
6[bumpversion:file:mmdesigner/__init__.py]
7search = __version__ = "v{current_version}"
8replace = __version__ = "v{new_version}"
9
10[bumpversion:file:setup.py]
11search = {current_version}
12replace = {new_version}
13
14[bumpversion:file:README.rst]
15search = {current_version}
16replace = {new_version}
Warning
The project is named bump2version, but the configuration file is just bumpversion. The original project developer abandoned the project, and a new maintainer renamed it.
With this file n place, we can increment any part of a semantic versioning number using one of the new Makefile commands provided in the Modular Make collection:
1.PHONY: inc-major
2inc-major: ## increment major version number
3 @bump2version major
4
5.PHONY: inc-minor
6inc-minor: ## increment minor version number
7 @bump2version minor
8
9.PHONY: inc-patch
10inc-patch: ## increment patch version number
11 @bump2version patch
12
13.PHONY: version
14version: ## display current version number
15 @cat mmdesigner/__init__.py
Publishing the Project¶
Now, when the project reaches a milestone point and you want to release a new version on PyPi, we need to do a few things:
Bump the version number as needed
Build the package for PyPi
Test the new version to make sure it will upload properly
Publish the version officially
We have already covered the tools needed to bump the version number properly.
Building a Package for PyPi¶
To build the package for PyPi, all we need to do is run the setup.py script using Python:
$ python setup.py sdist bdist_wheel
This command will build two files n a new dist directory in the project root directory:
mmdesigner-x.x.x-py2.py3-none-any-whl
mmdesigner-x.x.x.tar.gz
The first file is the one that will be delivered to a user running the pip command. The second one contains the source code for the project. This is just the contents of the mmdesigner directory, not the full documentation and test code available on GitHub.
Test The Package for PyPi¶
PyPi has a test server that can be used to check the package before it goes public. We will use the twine tool to send this project to the test server:
$ twine upload --repository testpypi dist/* --skip-existing
This will upload the new version. If you try to upload an existing version, nothing will actually be uploaded.
Publish the Package¶
Finally, we use twine to publish the new version officially:
$ twine upload dist/* --skip-existing
All of these commands are included in a Modular Make module:
1.PHONY: build
2build: ## package project for PyPi
3 rm -rf build dist
4 python setup.py sdist bdist_wheel
5 twine check dist/*
6
7.PHONY: pypitest
8pypitest: build ## upload project to pypi test server
9 twine upload --repository testpypi dist/* --skip-existing
10
11.PHONY: upload
12upload: build ## upload new version to PyPi
13 twine upload dist/* --skip-existing