rlim

Avoiding Depedency Disasters in Your Python Projects

written by Ricky Lim on 2025-04-05

Why should we care about our python projects' dependency ?

Forgetting to declare dependencies in Python projects can result in runtime errors like ModuleNotFoundError or ImportError. In contrast, including unnecessary dependencies can unnecessarily bloat your project, particularly when deploying it as a Docker container where size matters.

Tools like FawltyDeps can help manage dependencies effectively, ensuring your project includes only what it needs.

Common Problems in Python Projects

FawltyDeps

FawltyDeps is a tool that helps you find both undeclared and unused dependencies in your python projects. Here's a simple guide how you can integrate it into your projects.

Let's consider a simple python project pycontainer-demo. In this project, we are going to setup FawltyDeps as a pre-commit hooks to ensure our dependencies are in check.

Setting up FawltyDeps

1. Install FawltyDeps

uv add --dev fawltydeps

Then we can run the tool.

2. Configure FawltyDeps

FawltyDeps v0.19.0 incorrectly flags dependencies provided by other declared dependencies as undeclared. For example, it may identify rich as undeclared, even though it is a dependency of the declared package typer.

To address this and exclude dependencies not intended for direct import in pycontainer-demo project, I added the following configuration to pyproject.toml

...

[tool.fawltydeps]
ignore_undeclared = [
    "rich"
]
ignore_unused = [
    "bump-my-version",
    "psycopg2-binary",
    "pre-commit",
    "flawtydeps",
]

3. Add to the pre-commit hooks

...

-   repo: https://github.com/tweag/FawltyDeps
    rev: v0.19.0
    hooks:
      - id: check-undeclared
      - id: check-unused

4. Install the pre-commit hooks

$ pre-commit install

Now when you commit changes, FawltyDeps will run and report any undeclared or unused dependencies.

Detect the unused dependencies

If we add a dependency to pyproject.toml but never used in the code. For example we add the following code to pyproject.toml.

# Example numpy that is not used
dependencies = [
    ...
    numpy
]

Then we commit the changes.

$ git add .
$ git commit -m "Add numpy"
FawltyDeps-unused........................................................Failed
- hook id: check-unused
- exit code: 4

These dependencies appear to be unused (i.e. not imported):
- 'numpy' declared in:
    pyproject.toml

This approach is helpful because it prevents unused dependencies from being committed. To resolve such issues, you can simply remove the unnecessary dependency from pyproject.toml.

Detect the undeclared dependencies

For example if we add the following code to src/robot/cli.py and install art with uv pip install art

from art import tprint

header = tprint("Robot Management System")
app = typer.Typer(help=header, no_args_is_help=True)
console = Console()

The update involves adding a header using the art package, enhancing the appearance of the CLI output. When you run the CLI, it will look like this:

$ robot
 ____          _             _     __  __                                                            _     ____               _
|  _ \   ___  | |__    ___  | |_  |  \/  |  __ _  _ __    __ _   __ _   ___  _ __ ___    ___  _ __  | |_  / ___|  _   _  ___ | |_   ___  _ __ ___
| |_) | / _ \ | '_ \  / _ \ | __| | |\/| | / _` || '_ \  / _` | / _` | / _ \| '_ ` _ \  / _ \| '_ \ | __| \___ \ | | | |/ __|| __| / _ \| '_ ` _ \
|  _ < | (_) || |_) || (_) || |_  | |  | || (_| || | | || (_| || (_| ||  __/| | | | | ||  __/| | | || |_   ___) || |_| |\__ \| |_ |  __/| | | | | |
|_| \_\ \___/ |_.__/  \___/  \__| |_|  |_| \__,_||_| |_| \__,_| \__, | \___||_| |_| |_| \___||_| |_| \__| |____/  \__, ||___/ \__| \___||_| |_| |_|

Then we commit the changes.

git add .

git commit -m "Add header with art"
FawltyDeps-undeclared....................................................Failed
- hook id: check-undeclared
- exit code: 3

These imports appear to be undeclared dependencies:
- 'art' imported at:
    src/robot/cli.py:2

Fortunately, the commit fails. Because we forget to declare art as a dependency.

This is really nice because with such failure we can prevent undeclared dependencies from being committed.

Next, we can add art to the dependencies and update the pyproject.toml file accordingly.

dependencies = [
    "sqlmodel>=0.0.22",
    "typer>=0.9.0",
    "psycopg2-binary>=2.9.9",
    "art>=6.4",
]

We can now commit the changes, and they should pass successfully.

git add .
git commit -m "Add header cli with art"
...
FawltyDeps-undeclared....................................................Passed
FawltyDeps-unused........................................................Passed

Key Takeaways

Setting up FawltyDeps as a pre-commit hook helps catch undeclared and unused dependencies, ensuring your project stays lean and avoids runtime errors.