Skip to Content
Course content

343: Structuring a Distributable Package

Click on the "Edit" button in the top corner of the screen to edit your slide content.

You've written a great piece of logic—let's say you've built a library called carbon_calc that helps developers calculate the CO2 impact of their cloud infrastructure. It works perfectly on your machine. Now comes the part where most developers stumble: trying to give that code to someone else so they can pip install it without you having to spend three hours on a Zoom call explaining how to configure their PYTHONPATH.

The "Just Put It In a Folder" Approach

The most intuitive way to start is what I call the flat layout. You create a folder named carbon_calc, throw your __init__.py and your logic files in there, and put your README and LICENSE in the root. It looks clean. When you're working in that root directory, you can run python` and import carbon_calc works because Python automatically adds the current working directory to the search path.

But here is where it breaks. When you actually distribute this—say, by uploading it to PyPI or sharing a wheel file—the user installs it into their site-packages. If you have your tests in the root directory (which most people do in a flat layout), you might find yourself accidentally testing the local folder instead of the installed package. I've seen countless bugs where a developer thinks their package is working, but it's only because Python is importing the local source code, while the actual installed version is missing a critical file or has a broken dependency. You're essentially lying to yourself about whether the package is actually "distributable."

Moving to the src Layout

If you want to do this like a pro, you need to introduce a layer of separation. I always recommend the src layout. In this version, your project root contains your configuration files, but the actual package code lives inside a directory called src/. So, your path becomes src/carbon_calc/__init__.py.

This feels like an annoying extra folder at first. Why add the nesting? Because it forces you to install the package (usually in editable mode via pip install -e .) before you can run your tests or import your code. If you forget to include a file in your build configuration, your tests will fail immediately because the code isn't just "there" in the root—it's tucked away in src/. It guarantees that what you're testing is exactly what the end-user will experience.

# A professional structure for carbon_calc
project_root/
├── pyproject.toml       # The modern source of truth
├── README.md
├── LICENSE
├── src/
│   └── carbon_calc/     # The actual importable package
│       ├── __init__.py
│       ├── calculator.py
│       └── constants.py
└── tests/
    └── test_calc.py

Ditching setup.py for pyproject.toml

You'll see a lot of old tutorials telling you to write a setup.py file. Please, ignore them. setup.py is an executable script, which is a security risk and a maintenance headache. The industry has moved to pyproject.toml. It's a declarative configuration file—it tells the build system (like setuptools, flit, or hatch) exactly what your package is and what it needs to run, without executing arbitrary Python code during installation.

In your pyproject.toml, you define your build-system and your project metadata. I prefer this because it keeps the "how to build" separate from the "what is being built." When you specify [tool.setuptools.packages.find] where = ["src"], you're telling Python exactly where to look for your code, removing any ambiguity about which folders should be included in the final distribution. It's a small shift in organization, but it's the difference between a script that "works for me" and a professional library that works for everyone.




📋 Practical Task

Refactoring the Cloud-Audit Package Structure

You have been handed a messy project called cloud_audit. Currently, it is using a naive flat layout where the package code and the tests are mixed in the root, and it relies on an outdated setup.py file. Your goal is to transition this project to a professional src layout.

Your task:

  • Create a src/ directory and move the cloud_audit/ package folder inside it.
  • Delete the existing setup.py.
  • Create a pyproject.toml file in the project root. In this file, you must:
    • Define the [build-system] using setuptools.
    • Define the [project] section with a name, version, and a dependency on the requests library.
    • Use [tool.setuptools.packages.find] to explicitly point the build system to the src directory.
  • Verify the structure by attempting to install the package in editable mode (pip install -e .) and confirming that you can no longer import cloud_audit if you are in the root directory without having installed it first.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.