diff options
Diffstat (limited to 'content/weblog/2019-01-31_python-package-to-pypi')
-rw-r--r-- | content/weblog/2019-01-31_python-package-to-pypi/index.md | 176 |
1 files changed, 176 insertions, 0 deletions
diff --git a/content/weblog/2019-01-31_python-package-to-pypi/index.md b/content/weblog/2019-01-31_python-package-to-pypi/index.md new file mode 100644 index 0000000..f0b14e0 --- /dev/null +++ b/content/weblog/2019-01-31_python-package-to-pypi/index.md @@ -0,0 +1,176 @@ ++++ +title = "Packaging and distributing python apps and modules" +date = 2019-01-31T08:10:00Z ++++ + +There may come a time after some hacking and playing around with python that +you feel like the piece of code you just created needs to be shared with the +world, and so you might be thinking "Man, wouldn't it be sweet if anyone could +install my app/module just by typing `pip install stuffimade'`. Well, it is +actually easier than you might think (it certainly was in my case). + +<!-- more --> + +It basically boils down to these five things: + +1. Make an account on pypi.org +1. Come up with an original name, that hasn't been taken on pypi (arguably the + hardest part of these instructions). +1. Prepare a setup py file to package your app/module, choose a license, maybe + (preferably) write a readme. +1. Package it. +1. Upload it. + +The first step is really simple, just go the website (pypi.org) and click on +the link that says "Register" on the top right corner. Be sure to not forget +your password, especially after uploading your package, since you will need +everything that you want to upload a new version of your package. + +The second step is all up to you, just use the search function in the website +to make sure that your package name hasn't been taken. + +After having created your account on pypi.org, and decided on a name for your +app/package, you'll proceed to create the necessary package files. Your package +should consist of a folder with your actual module or app, inside which should +also be a `__init__.py` file (it can be empty if you don't need to set any +variables or anything), a `LICENSE` file with your license of choice (e.g. MIT, +BSD, GPL, etc.), and a `README.rst` or `README.md` file containing a detailed +description of your app/module. + +Your directory structure should look something like this + +``` +/my-app-package + /my-app + __init__.py + (other files and directories) + setup.py + LICENSE + README.md +``` + +Now, if your app is going to have files other than python files, and the +aforementioned files, you might to add a `MANIFEST.in` in the root of you +package directory specifying the files to include. This is true, for example, +for Django apps, since they might contain template and static files (html, css, +js, etc.) that the packaging tool we are going to use might not pick up. As an +example I'll show you the `MANIFEST.in` file of my w3blog package + +``` +include LICENSE +include README.md +recursive-include weblog/static * +recursive-include weblog/templates * +recursive-include weblog/locale * +``` + +There I specified to, just in case, include the `LICENSE` and `README.md` +files, and also include static files, templates, and the message files for +localization, by recursively searching the directories of said files. + +Now on to the setup.py file. For this I am also going to use my project's file +as an example + +```py +#!/usr/bin/env python3 +import os +from setuptools import find_packages, setup + +with open(os.path.join(os.path.dirname(__file__), 'README.md')) as readme: + README = readme.read() + +# allow setup.py to be run from any path +os.chdir(os.path.normpath(os.path.join(os.path.abspath(__file__), os.pardir))) + +setup( + name='w3blog', + version='0.5.2', + packages=find_packages(), + include_package_data=True, + license='BSD License', + description='A simple blog engine for Django with multilingual capabilities.', + long_description=README, + url='https://www.yaroslavps.com/', + author='Yaroslav de la Peña Smirnov', + author_email='contact@yaroslavps.com', + classifiers=[ + 'Environment :: Web Environment', + 'Framework :: Django', + 'Framework :: Django :: 1.11', + 'Framework :: Django :: 2.0', + 'Framework :: Django :: 2.1', + 'Intended Audience :: Developers', + 'License :: OSI Approved :: BSD License', + 'Operating System :: OS Independent', + 'Programming Language :: Python', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.4', + 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', + 'Topic :: Internet :: WWW/HTTP', + 'Topic :: Internet :: WWW/HTTP :: Dynamic Content', + ], +) +``` + +Of course, you should customize this file according to your app's details, for +example, your classifiers list might look shorter, like this + +```py + classifiers=[ + 'License :: OSI Approved :: BSD License', + 'Operating System :: OS Independent', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.4', + 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', + ], +``` + +It will depend on which version of python you want to support, your license, +some other required packages, etc. The rest of the setup function parameters +should be self explanatory. + +Once you have you package files ready (don't forget about your readme and +license), you'll need to proceed to package them, i.e. generate the +distribution files. For that, we'll need to install a couple of packages, we +cant install them inside a virtual environment, or you could install them +system wide + +```sh +$ sudo pip3 install --upgrade setuptools wheel twine +``` + +Now just run the following command from the same directory where setup.py is +located + +```sh +$ python3 setup.py sdist bdist_wheel +``` + +After running that command, you should now have a dist subdirectory with a +.tar.gz archive and a .whl file. Those are the files that you'll need to +upload. The twine package that we just installed is going to take care of that +for us. Remember that you already should have an account on pypi.org to upload +your package. + +So for example, when I just uploaded the first version of w3blog, and each time +that I upload a new version I run a command (from the same directory as +setup.py) that looks like this + +```sh +$ python3 twine upload dist/w3blog-0.5.2* +``` + +Just replace "w3blog-0.5.2*" with your appropriate package name-version. After +running that command, twine is going to ask you for your username and password, +thence it is going to upload it to pypi. Once it is successfully uploaded, it +should be a matter of seconds or minutes before you, and everybody else in the +world with an internet connection (and capable of running python, of course), +can install your package! + +If you need more detailed information about this process, check out the +official documentation at +[https://packaging.python.org/tutorials/packaging-projects/](https://packaging.python.org/tutorials/packaging-projects/) |