Skip to content
/ tach Public

A Python tool to enforce a modular, decoupled package architecture. 🌎 Open source 🐍 Installable via pip πŸ”§ Able to be adopted incrementally - ⚑ Implemented with no runtime impact ♾️ Interoperable with your existing systems

License

Notifications You must be signed in to change notification settings

gauge-sh/tach

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

image image image image Checked with pyright Ruff

Tach

a Python tool to enforce modular design

Docs

Tach lets you define and enforce dependencies across Python packages in your project. A Python package is any directory that contains an __init__.py.

This enforces a decoupled, modular architecture, which makes maintenance and development easier. If a package tries to import from another package that is not listed as a dependency, tach will throw an exception.

Here's an example:

tach_demo_ds

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

pip install tach

Setup

Tach allows you to configure what is and is not considered a package. By default, Tach will identify and create configuration for all top level packages it finds.

You can do this interactively! From the root of your python project, run:

 tach pkg
# Up/Down: Navigate  Ctrl + Up: Jump to parent  Right: Expand  Left: Collapse
# Ctrl + c: Exit without saving  Ctrl + s: Save packages  Enter: Mark/unmark package  Ctrl + a: Mark/unmark all siblings

Mark and unmark each package as needed, depending on what you want to define boundaries for.

Once you have marked all the packages you want to enforce constraints between, run:

tach sync

This will create the root configuration for your project, tach.yml, with the dependencies that currently exist between each package you've marked.

You can then see what Tach has found by viewing the tach.yml's contents:

cat tach.yml

Note: Dependencies on code that are not marked as packages are out of the scope of Tach and will not be enforced.

Enforcement

Tach comes with a simple cli command to enforce the boundaries that you just set up! From the root of your Python project, run:

tach check

You will see:

βœ… All package dependencies validated!

You can validate that Tach is working by either commenting out an item in a depends_on key in tach.yml, or by adding an import between packages that didn't previously import from each other.

Give both a try and run tach check again. This will generate an error:

❌ path/file.py[LNO]: Cannot import 'path.other'. Tags ['scope:other'] cannot depend on ['scope:file']. 

Extras

If an error is generated that is an intended dependency, you can sync your actual dependencies with tach.yml:

tach sync

After running this command, tach check will always pass.

If your configuration is in a bad state, from the root of your python project you can run:

tach clean

This will wipe all the configuration generated and enforced by Tach.

Tach also supports:

More info in the docs. Tach logs anonymized usage statistics which are easily opted out of. If you have any feedback, we'd love to talk!

Discord

About

A Python tool to enforce a modular, decoupled package architecture. 🌎 Open source 🐍 Installable via pip πŸ”§ Able to be adopted incrementally - ⚑ Implemented with no runtime impact ♾️ Interoperable with your existing systems

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published