⚡️️Python Package Publishing Speedrun️⚡
Welcome to yet another garbanzo tutorial on the internet that no one asked for. This one teaches you how to pollute PyPI with a shitty and useless package as fast as possible. We’re moving fast. Agility. We’re dialing in the motions of getting from point A to point B. Parkour. Warning: This package will do nothing.
To compete in this speedrun category, you need to complete six achievements:
- version dependencies
- all commits are thoughtful and atomic
- write a test and pass it
- automate testing
- write a README.md
- packaging and publishing to PyPI
Some achievements contain an intro/fetishization as to why I picked them. The hardcore speedrunner can ignore them and follow along with the instructions, but for the trivia nerds out there, feel free to check them.
Version your dependencies
backstory
I use Poetry and it’s been treating me right. It handles all the annoying dependency management for me. Best part? It uses pyproject.toml
instead of the headache-inducing requirements.txt
. I can’t exactly pinpoint why, but that file never sat right with me. Anyway, since I hopped on the Poetry bandwagon, my dependencie-headaches have practically vanished and PEP 518 actually defined pyproject.toml
as the container of build system requirements. You can even use it to describe, let’s say, which modules to ignore with mypy. Poetry also makes it trivial to build and publish your package to Pypi 🤌.
Enough about Poetry, let’s start a brand new project for your shitty useless package
Step 1:
poetry new shitty_project_1797
Note: Make sure you check Pypy and see if your project’s name isn’t already in use and abstain from actually using meaningful names, add some random digits.
Step 2: Enter the new project and open your editor of choice. If you run tree
you should be looking at something like this.
.
├── pyproject.toml
├── README.md
├── shitty_package
│ └── __init__.py
└── tests
└── __init__.py
3 directories, 4 files
All commits are thoughtful
backstory on Conventional Commits
Welcome to Conventional Commits, your new best bud. This cool cat helps you craft thoughtful commits, and it even adds emojis with predefined meanings. Check out https://gitmoji.dev/ and the commit history of this mini-useless project for a taste. You might roll your eyes at another dev tool for a “non-existing problem”, specially for something trivial like commit messages. But hey, it’s about letting the tool guide your thoughts, man.
When you call up the extension for a new commit, it throws options at you. Are we refactoring, adding a feature, tweaking docs, fixing bugs, writing tests, or messing with CI? Then, you pick an emoji for a single action (https://gitmoji.dev/). Only after that, you write your commit title and maybe a longer description, and a section addresssing breaking changes or issues that can be closed.
As you iterate on that workflow, you’ll notice that it pushes you to break down your changes into commitable chunks, atomizing the changes in the project. Forcing you to think in isolated bits. The options laid out in front of you not only prompt introspection about the changes you’ve made but also remind you of potential tasks you haven’t tackled yet, like writing tests or setting up CI. Maybe I’m hyping it up for my own narrative, but it’s still an awesome tool that helps reducing what can otherwise be a over-complex changes into trackable checkpoints, with the side effect of feeling like you’re using modern hieroglyphs.
Initialize your repo, after that, assuming you’re using VSCode, install Coventional Commits, do Ctrl+Shift+P, and select Conventional Commits. Select chores
. Select No scope
. Phew, phew. Search and select for ,tada
🎉, which means start of a new project, and write start of speedrun
. Every single commit will have to follow this general guideline. Not following this convention will disqualify your run. Keep adding commits in their rights categories as you make changes. Don’t rush, with time you’ll be get to know the available options.
Write a test and pass it
backstory on writing tests
Writing tests is an essential part of software development, and it’s no different when creating a Python package. A well-crafted test suite ensures that your code works as expected and helps you catch bugs or issues early in the development process. Additionally, having tests in place makes it easier for you to make changes to the codebase with confidence, knowing that any breaking changes will be caught by the tests, and soon enough you’ll get the heebie-jeebies when working on a codebase with no testing.
In this speedrun, we’ll be writing a simple test for our shitty package. Although the package itself is useless, the process of writing and running tests is invaluable and will serve you well in your future development endeavors.
Step 1: Write a simple test for your package. In the tests directory, create a new file named test_shitty_package.py. Inside this file, write a basic test function. Since our package is useless, the test can be as simple as checking if truthy:
def test_shitty_package():
assert True, "Run, now"
Step 2: Install pytest. In your project’s root directory, run:
poetry add --dev pytest
This will add pytest as a development dependency and update your pyproject.toml file accordingly. To update your env with your new dependency run:
poetry installs --with dev
Step 3: Run the test using pytest. In your terminal, navigate to your project’s root directory and run, don’t forget to activate the environment:
pytest .
If everything is set up correctly, you should see output similar to the following:
============================= test session starts ==============================
platform linux -- Python 3.9.7, pytest-6.2.5, py-1.10.0, pluggy-1.0.0
rootdir: /path/to/shitty_project_1797
collected 1 item
tests/test_shitty_package.py . [100%]
============================== 1 passed in 0.01s ===============================
Automate the testing
backstory on test automation
Automating your tests is a crucial part of the development process. It ensures that your tests are executed regularly and consistently, helping you catch any issues or regressions early on. By incorporating test automation into your workflow, you save time and reduce the chances of human error. Additionally, it makes it easy for you to integrate your tests with continuous integration (CI) systems like GitHub Actions.To automate the testing of your Python package, we’ll use a simple GitHub Actions workflow:
Step 1: In your project’s root directory, create a new directory named .github, and inside it, create another directory named workflows. Your project structure should now look like this:
.
├── .github
│ └── workflows
├── pyproject.toml
├── README.md
├── shitty_package
│ └── __init__.py
└── tests
└── __init__.py
Now, pour this YAML nonsense into test.yml:
name: Test
on: [push]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.9", "3.10","3.11"]
steps:
- name: Checkout Code
uses: actions/checkout@v3
- name: Setup Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Install Poetry
uses: snok/install-poetry@v1
with:
version: 1.3.2
virtualenvs-create: false
virtualenvs-in-project: false
installer-parallel: true
- name: Install dependencies
run: poetry install --with dev
- name: Run tests and coverage
run: pytest
Write a README
A well-written README.md file is vital for any project, especially when you’re publishing a Python package. It’s the first thing users see when they come across your package on GitHub or PyPI, and it’s often their first point of reference for understanding what your package does and how to use it. A good README should include information about the package’s purpose, installation instructions, usage examples, and any necessary documentation. While your package is useless, writing a proper README is excellent practice for future projects. Also for bonus points design some kind of banner or logo.
Packaging and publishing to PyPi
In this final step, we’ll package your useless project and publish it to PyPI, making it available for others to ignore, and for some bots to download it.
Step 1: Create a PyPi account
Step 2: Configure poetry
to use your PyPi credentials.
Step 4: Package your project
poetry build
Step 5: Publish your project
poetry publish
And there you have it – a complete guide on how to publish a Python package that adds absolutely no value to the world. Perhaps you picked up a thing or two along the way, but let’s be real, this was pretty useless. Congratulations, you’ve achieved peak annoyance, you’re a python speedrunner.