Setting Up More Configurations
I kind of glossed over dependencies in the previous lessons, so let’s take a second and go into them in a bit more detail. When you declare dependencies in your package,
pip will automatically install those dependencies when your package gets installed. There are four styles of dependency declaration.
pip will install that or anything higher. You can even get more detailed than that, specifying both upper and lower boundaries, mixing and matching greater than (
>), less than (
<), and their equal to (
==) variations. For
urllib3, it has to be greater than or equal to
1.21.1 and less than
01:04 This kind of declaration tends to be more common with major versions. If a library does a rewrite and removes some feature or function you’re using, you may want a boundary that stops before that change.
01:16 This kind of notation is also used in testing tools like tox where you specify a group of dependencies for a particular test suite run. The last dependency here is an interesting variation on the first case.
It says you can use any version of the TOML library, but only if Python’s version is less than
3.11. As TOML is included in the 3.11 standard library, this prevents another package being installed when the system one could be used instead.
01:44 The dependencies you’ve declared so far have just been the default ones. There are also ways of declaring other dependency targets. This is typically used to specify tools needed in dev or testing, but not by the main users.
project.optional-dependencies section of
pyproject lets you declare labels similar to the dependencies list, but named. When you install, you provide the optional tag in square brackets (
), and you get both the default dependencies and the tag ones.
02:36 Documentation is good both for people using your library and what I like to call future you. Write enough code or let enough time elapse, and you won’t remember how something worked, and good docs and comments can make it much easier to consume your library. At minimum, if you want to be lazy, you should provide a README file.
02:54 If you don’t tell people what your library does, they’re not likely to be able to find it or use it. Both Markdown and RST are common formats for README files, and GitHub knows how to turn these into HTML for the project landing page, so your README can be double duty, both on the PyPI and on your repo home.
03:14 If you’re going to go all the way, I’d recommend looking at Sphinx, which is a documentation tool that produces PDF, e-book, HTML, and more. Sphinx-based documents host nicely on the Read the Docs documentation-hosting site. Read the Docs can hook to your repo, monitor for commits, and then build your documents and push the new versions automatically. Real Python has a course on this.
03:37 Links will be included in the Further Investigation section of the Summary lesson. If you’ve added content in other places such, as a repo or Read the Docs, you can add the URLs to the project’s metadata.
05:05 There are different ways of specifying a version number, and there are pros and cons to each style. The two most popular are semantic versioning. That’s using major, minor, and patch numbers separated by dots, which is my preference, and calendar versioning that makes the version based on a date. There are a few variations on this one as well.
pyproject example you saw earlier, the version was hard-coded. There are a couple alternatives to doing that technique as well. The first that I’m going to show you is here in this snippet.
It uses the
dynamic attribute of the
project section. This attribute indicates that certain values are generated on the fly by the build system. How to calculate the values is in a different section, which is build system–dependent. For
tool.setuptools.dynamic section can indicate things to auto-generate.
This requires an extra step that wasn’t needed in
setup.config only worked with
setuptools. The two-step mechanism here is separating the metadata from the build-system configuration. The price you pay for flexibility is complexity.
Another way of handling version info—in fact, a far more comprehensive way—is using the
bumpver third-party library.
bumpver does template replacement, so you can have your version number show up in a bunch of places, and
bumver will do the replacement in each place.
This is what
init creates. In the
bumpver is defining all those places to look for a version number and what it looks like in each place. The sample here looks for one in the
pyproject.toml file, and another in the
tool.bumpver section is configuration information for
bumpver itself, telling it how to behave when you bump a version. The pattern of
tool.<tool_name> is common in
pyproject.toml, so if you’re doing something like tox, the config for that goes in
The command shows you the old and new versions and then updates those files that it was configured to manage.
bumpver even integrates with
git, so you can automatically commit, tag, and push when you bump, if you want.
This is the content of
reader. It includes all the TOML files from the
reader module. There’s only one. Doing this allows you to ship things besides your Python code inside of your package.
In the old days, if you wanted a command that didn’t explicitly require the users to type
python and then the script name, you’d have to have a little shell thing in your package, and that meant more stuff in your manifest and complications across platforms. Now instead, you can declare in your
pyproject.toml file that you want a script.
09:35 Purdy is a code and terminal display tool. You’ve actually seen me using it in this course. Purdy has several different ways it can be executed, and it can output to the terminal or to an RTF document, and as such, comes with a few different programs.
Several of the programs are really just shortcuts to the same function calls, but with different parameters. By using the
scripts feature, I can declare these in the package and then point them at different wrapper functions, and the package builder takes care of the rest. If you’ve done this, once your package is installed, the scripts are created for you and put inside of the virtual environment’s
bin directory. In the example above, I could now use
realpython from the command line as my reader.
license file is the standard way of doing this in your projects. The most common license in the Python world is the MIT License, which is generally permissive, meaning the code is out there in the wild for anyone to do anything with it.
If you happen to be on a Unix-based box, this is a script I have in my projects to tie a bunch of things together. First, it grabs the
__version__ value out of the
__init__ file and uses the
cut command to get just the version number.
build is done, I run
twine check, and although you could do the upload here, sometimes things go wrong, so I’ve opted for the easy way out and just remind myself exactly what I have to type to do the upload. When I’m ready for a new version to be published, I run this script—it’s usually called
clean_build—and then if all goes well, I type in that last
twine thing, and bingo: PyPI has my latest stuff.
Become a Member to join the conversation.