Show HN: Strict interfaces and dep management for Python, written in Rust
Tach is a pip package that lets you define module boundaries, automatically detect all cross-module dependencies, and then validate and enforce those dependencies.<p>It also supports strict interfaces for modules by overloading `__all__`.<p>The core static analysis is done in Rust, so all Tach commands run quickly.<p>The goal of Tach is to help eng teams maintain velocity while scaling quickly, something we&#x27;ve seen break down a number of times. Give it a try!
GitHub - gauge-sh/tach: A Python tool to enforce dependencies, using modular architecture 🌎 Open source 🐍 Installable via pip 🔧 Able to be adopted incrementally - ⚡ Implemented with no runtime impact ♾️ Interoperable with your existing systems 🦀 Written in rust
Tach







a Python tool to enforce dependencies, written in Rust. Inspired by modular monolithic architecture.
Docs
Discord


Tach lets you define and enforce dependencies between Python modules within your project.
Here's an example:

If a module tries to import from another module that is not listed as a dependency, Tach can prevent it.
Tach is:

🌎 Open source
🐍 Installable via pip
🔧 Able to be adopted incrementally
⚡ Implemented with no runtime impact
♾️ Interoperable with your existing systems (cli, hooks, ci, etc.)

Getting Started
Installation

Setup
Tach allows you to configure where you want to place module boundaries in your project.
You can do this interactively - run:
 tach mod
# Up/Down: Navigate  Enter: Mark/unmark module  Right: Expand  Left: Collapse  Ctrl + Up: Jump to parent
# Ctrl + s: Exit and save  Ctrl + c: Exit without saving  Ctrl + a: Mark/unmark all
Mark each module boundary with 'Enter'. You can mark all of your top-level Python source packages, or just a few which you want to isolate.
If your Python code lives below your project root, or if you are working in a monorepo with multiple Python packages, mark your Python source roots using the 's' key.
This will create the config file for your project, tach.toml.
Once you've marked all the modules you want to enforce dependencies between, run:

Dependencies that exist between each module you've marked will be written to tach.toml.
Check out what Tach has found!

Note: Your source roots will implicitly be treated as module boundaries, and can show up as <root>.
Enforcement
Tach comes with a cli command to enforce the boundaries that you just set up! From the root of your Python project, run:

You will see:
✅ All module dependencies validated!
You can validate that Tach is working by either:

Commenting out an item in a depends_on key in tach.toml
By adding an import between modules that didn't previously import from each other.

Give both a try and run tach check again. This will generate an error:
❌ tach/check.py[L8]: Cannot import 'tach.filesystem'. Module 'tach' cannot depend on 'tach.filesystem'.
Each error indicates an import which violates your dependencies. If your terminal supports hyperlinks, click on the file path to go directly to the error.
When an error is detected, tach check will exit with a non-zero code. It can be easily integrated with CI/CD, Pre-commit hooks, and VS Code, and more!
Extras
Visualize your dependency graph.

Tach will generate a graph of your dependencies. Here's what this looks like for Tach:

Note that this graph is generated remotely with the contents of your tach.toml when running tach show --web.
If you would like to use the GraphViz DOT format locally, simply running tach show will generate tach_module_graph.dot in your working directory.
You can view the dependencies and usages for a given path:
tach report my_package/
# OR
tach report my_module.py
e.g.:
> tach report python/tach/filesystem
[Dependencies of 'python/tach/filesystem']
python/tach/filesystem/install.py[L6]: Import 'tach.hooks.build_pre_commit_hook_content'
python/tach/filesystem/project.py[L5]: Import 'tach.constants.CONFIG_FILE_NAME'
...
-------------------------------
[Usages of 'python/tach/filesystem']
python/tach/cache/access.py[L8]: Import 'tach.filesystem.find_project_config_root'
python/tach/cache/setup.py[L7]: Import 'tach.filesystem.find_project_config_root'
...
Tach also supports:

Strict public interfaces for modules
Deprecating individual dependencies
Incremental adoption
Manual file configuration
Monorepos and namespace packages
Inline exceptions
Pre-commit hooks

More info in the docs. Tach logs anonymized usage statistics which can be opted out of.
If you have any feedback, we'd love to talk!
If you have any questions or run into any issues, let us know by either reaching out on Discord or submitting a Github Issue!

Contributors

  

