30
loading...
This website collects cookies to deliver better user experience
pip
installed, I searched on-line and immediately got lost among the tens, hundreds maybe, of guides, tutorials and options and what looked like enough material for a doctoral dissertation to wade through. And all of it looked scary talking about starting from scratch (not from an existing package), wanting me to add and write a dozen files and understand this and that, and worse there are old ways, new ways, alternate ways ... Aaargh.__init__.py
file in it, and if it's a small package (as many of mine are) that's all they are. Nothing more, nothing less, than a folder with an __init__.py
in it that provided some classes and/or functions..py
files in the folder beside the __init__.py
. Minor detail, just what happens when it's a little too big to fit conveniently into the one file. build
- which creates from your package by default a .tar.gz
file and a .whl
file which is what pip wants/needs for it's install
ing career.
twine
- which publishes to pypi.org
pip install build twine
README.md
- a simple markdown file with a welcome message and whatever you want to add. What is this package, how do you use it? I use Typora but you can write it in any text editor and it can be as brief or in depth as you like. It is what's shown on the pypi.org page for your package so it's also your ad if you like for your package.
LICENSE.md
- Not sure you need it but worth doing and easy as Py. I am beastly careless in this space and just love the Hippocratic License. Download the markdown version and save it as LICENSE.md
the-folder-I-keep-it-in/
├── LICENSE
├── README.md
├── pyproject.toml
├── setup.cfg
└── src/
└── my_package/
└── __init__.py
You don't need to put it in a src
folder, but why not? If it ain't broke don't fix it. The src
strategy means you can just drag and drop you package from where it was into src ... done. The stuff above it is the publishing kit ...
pyproject.toml
and setup.cfg
just tell build
and twine
what to do. We'll come back to these shortly. The first is just a standard file to tell build
that we're going to use twine
in a roundabout way ;-) and the second one describes your package so twine
can publish it (purists may argue with this neat division, but let them).
The folder the-folder-I-keep-it-in
can have any name you like. won't change a thing with the build or publish. I actually call it my-package
(in this example). As to why, keep reading. It's just convenient that's all.
The folder my_package
should use underscores between words, yes, do it. There's a bizarre confusion in the Python world between my_package
and my-package
.
my_package
: just stick to this don't waver, never waver, use only this ;-). I kid ye not. Using my-package
in either the folder under src
or in setup.cfg
will cause you grief during the build, publish, install and test.
Once it's published it will appear on pypi.org as my-package
and people will install it with pip install my-package
, but use it with import my_package
. That's just the way it is, that's the convention, don't rock the boat, all you need to know is you don't have to lift a finger to make that happen, just stick with my_package
in the src
folder and in setup.cfg
.
But of course, the-folder-I-keep-it-in
is irrelevant here and I call it my-package
just because, because that's what the package is called. The only other exception is the github repo if you're using one (and I do), that too can be my-package
and is in my case in fact later you'll se I can exploit that for a nice two line install script.
pyproject.toml
is easy. Just copy the standard. Put this in it:[build-system]
requires = [
"setuptools>=42",
"wheel"
]
build-backend = "setuptools.build_meta"
build
internals and unless you're super keen in digging deeper, let it rest, this just means when you run python3 -m build
in your package folder, it knows what to do (if you don't have this file it will ask for one). What it does, is created a dist
folder and drops two files in it. These are what twine needs
setup.cfg
is not hard either and here's my minimalist take and the clarifications that I felt were missing elsewhere:[metadata]
name = my_package
version = 0.1
author = my name
author_email = my email address
description = My little package
long_description = file: README.md
long_description_content_type = text/markdown
url = https://github.com/me/my-package
project_urls =
Bug Tracker = https://github.com/me/my-package/issues
classifiers =
Programming Language :: Python :: 3
License :: Freely Distributable
Operating System :: OS Independent
Development Status :: 4 - Beta
Framework :: Django :: 3.2
Intended Audience :: System Administrators
Topic :: Software Development :: Libraries :: Python Modules
[options]
install_requires =
other_package1 >= 0.1.1
other_package2 >= 2.0.1
package_dir =
= src
packages = find:
python_requires = >=3.6
[options.packages.find]
where = src
name
should use my_package
not my-package
. Just believe me. Things go weird if it says my-package
. Experiment if you like, I wish I didn't need to and the tutorial was clear here.install_requires
wants one indented line per requirement with relatively familiar syntax (similar to pip freeze
- another one of those mysteriously named python commands that actually means pip show-me-whats-installed
). This is completely missed in the tutorial. package_dir
is weird, yes, but forget it. Like install_requires
it has a list of one liners beneath it, in this case just one. The one liners map package names to folders somehow in the internal complexities of setuptools - details most of don't care about or want to know about when publishing our simple one file package. The tutorial tells us that this line maps the "noname" package to the src
folder, and that the "noname" package (that nothingness before the = sign) is a code name for the overarching root package, so the src
folder becomes the mystical "root package". Do most of us actually care about this? What is a "root package"? anyhow. Nah, let's leave it for the boffins, and just accept this is the odd way of telling build
and/or twine
that our package is in the src
folder.find:
. No. That's just the syntax, live with it. Refer back to the intro, re: my sentiments on the unnecessary befuddling cryptic nature of Python package publication ... Ditto the where = src
, just accept it.python3 -m twine upload dist/*
version
you have in setup.cfg
as these get built into the filenames in dist
).testpypi
at https://test.pypi.org/ that you can publish to freely, as often as you need to get it right.You look at it on pypi and README.md
has issues. Either typos, or code lines that are too long and render badly etc. Either way, you get see how it's going to presented on pypi and can adjust your README to look nice.
Your test installing it with pip doesn't work. Which actually doens't happen now that I have a workflow, but happened a lot while Iw as trying to work all that setup.cfg
syntax out that the tutorial deigns to gloss over.
python3 -m twine upload --repository testpypi dist/*
twine
when used as above prompts for username and password. Alas these long random passwords of mine are not easy to type, so I usually do a copy/paste but alas pasting the password does not work - I tried and tried.python3 -m twine upload --repository testpypi -u $username -p $password dist/*
test-publish
that reads:#!/bin/bash
source ~/.auth/pypi.auth
python3 -m twine upload --repository testpypi --verbose -u $username -p $password dist/*
version
in setup.cfg
and rebuild before you can republish. Slows things down some. Not least because of the time and energy spent searching online for ways and means to republish. Some on-line sources suggest --skip-existing
does the trick, but it doesn't - not for me and it's not clear what it does or what it's for and maybe I just misread that. C'est la vie.install_requires
in setup.cfg
don't work, presumably because, when testing the required packages aren't on https://test.pypi.org/. But it took a bit of head scratching and try and try again to convince myself of that, as I was trying believe it or not to validate the syntax for just that setting as it's not described in the tutorial and sent me looking at that warren of other sources quickly again. I do wish that testpyi would look at pypi for requirements as a fallback so this test cycle could be complete.build
:#!/bin/bash
rm dist/*
python3 -m build
test-publish
:#!/bin/bash
source ~/.auth/pypi.auth
python3 -m twine upload --repository testpypi --verbose -u $username -p $password dist/*
test-install
:#!/bin/bash
package=$(basename $(dirname $(readlink -f "$0")))
python -m pip install --index-url https://test.pypi.org/simple/ $package
publish
:#!/bin/bash
source ~/.auth/pypi.auth
python3 -m twine upload --verbose -u $username -p $password dist/*
install
:#!/bin/bash
package=$(basename $(dirname $(readlink -f "$0")))
python -m pip install $package
README.md
to write, a LICENSE.md
to download, a pyproject.toml
to copy, and setup.cfg
to tune) and maybe 5 tiny little helper bash scripts and in no time a test and then publish cycle is underway.