Skip to main content

A Python tool to maintain a modular package architecture.

Project description

image image image image Checked with pyright Ruff

Tach

a Python tool to enforce modular design, written in Rust.

Docs

Tach lets you define and enforce dependencies between Python modules in your project.

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

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 where you want to place module boundaries in your project.

You can do this interactively! From the root of your python project, 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 and unmark each module boundary you want to create with 'Enter' (or 'Ctrl + a' to mark all sibling modules). Common choices would be to mark all of your top-level Python source packages, or just a few packages which you want to isolate.

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

tach sync

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

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

cat tach.yml

NOTE: Your 'project root' directory (the directory containing your tach.yml) will implicitly be treated as a module boundary, and may show up in your dependency constraints as ''.

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 module 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 modules 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!

If you have any questions or run into any issues, let us know by either reaching out on Discord or submitting a Github Issue!

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

tach-0.5.1.tar.gz (388.8 kB view hashes)

Uploaded Source

Built Distributions

tach-0.5.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (2.4 MB view hashes)

Uploaded PyPy manylinux: glibc 2.17+ x86-64

tach-0.5.1-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl (2.7 MB view hashes)

Uploaded PyPy manylinux: glibc 2.17+ s390x

tach-0.5.1-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl (2.5 MB view hashes)

Uploaded PyPy manylinux: glibc 2.17+ ppc64le

tach-0.5.1-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl (2.3 MB view hashes)

Uploaded PyPy manylinux: glibc 2.17+ ARMv7l

tach-0.5.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (2.4 MB view hashes)

Uploaded PyPy manylinux: glibc 2.17+ ARM64

tach-0.5.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl (2.4 MB view hashes)

Uploaded PyPy manylinux: glibc 2.5+ i686

tach-0.5.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (2.4 MB view hashes)

Uploaded PyPy manylinux: glibc 2.17+ x86-64

tach-0.5.1-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl (2.7 MB view hashes)

Uploaded PyPy manylinux: glibc 2.17+ s390x

tach-0.5.1-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl (2.5 MB view hashes)

Uploaded PyPy manylinux: glibc 2.17+ ppc64le

tach-0.5.1-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl (2.3 MB view hashes)

Uploaded PyPy manylinux: glibc 2.17+ ARMv7l

tach-0.5.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (2.4 MB view hashes)

Uploaded PyPy manylinux: glibc 2.17+ ARM64

tach-0.5.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl (2.4 MB view hashes)

Uploaded PyPy manylinux: glibc 2.5+ i686

tach-0.5.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (2.4 MB view hashes)

Uploaded PyPy manylinux: glibc 2.17+ x86-64

tach-0.5.1-pp38-pypy38_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl (2.7 MB view hashes)

Uploaded PyPy manylinux: glibc 2.17+ s390x

tach-0.5.1-pp38-pypy38_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl (2.5 MB view hashes)

Uploaded PyPy manylinux: glibc 2.17+ ppc64le

tach-0.5.1-pp38-pypy38_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl (2.3 MB view hashes)

Uploaded PyPy manylinux: glibc 2.17+ ARMv7l

tach-0.5.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (2.4 MB view hashes)

Uploaded PyPy manylinux: glibc 2.17+ ARM64

tach-0.5.1-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl (2.4 MB view hashes)

Uploaded PyPy manylinux: glibc 2.5+ i686

tach-0.5.1-cp312-none-win_amd64.whl (1.4 MB view hashes)

Uploaded CPython 3.12 Windows x86-64

tach-0.5.1-cp312-none-win32.whl (1.3 MB view hashes)

Uploaded CPython 3.12 Windows x86

tach-0.5.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (2.4 MB view hashes)

Uploaded CPython 3.12 manylinux: glibc 2.17+ x86-64

tach-0.5.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl (2.7 MB view hashes)

Uploaded CPython 3.12 manylinux: glibc 2.17+ s390x

tach-0.5.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl (2.5 MB view hashes)

Uploaded CPython 3.12 manylinux: glibc 2.17+ ppc64le

tach-0.5.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl (2.3 MB view hashes)

Uploaded CPython 3.12 manylinux: glibc 2.17+ ARMv7l

tach-0.5.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (2.4 MB view hashes)

Uploaded CPython 3.12 manylinux: glibc 2.17+ ARM64

tach-0.5.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl (2.4 MB view hashes)

Uploaded CPython 3.12 manylinux: glibc 2.5+ i686

tach-0.5.1-cp312-cp312-macosx_11_0_arm64.whl (1.5 MB view hashes)

Uploaded CPython 3.12 macOS 11.0+ ARM64

tach-0.5.1-cp312-cp312-macosx_10_12_x86_64.whl (1.5 MB view hashes)

Uploaded CPython 3.12 macOS 10.12+ x86-64

tach-0.5.1-cp311-none-win_amd64.whl (1.4 MB view hashes)

Uploaded CPython 3.11 Windows x86-64

tach-0.5.1-cp311-none-win32.whl (1.3 MB view hashes)

Uploaded CPython 3.11 Windows x86

tach-0.5.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (2.4 MB view hashes)

Uploaded CPython 3.11 manylinux: glibc 2.17+ x86-64

tach-0.5.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl (2.7 MB view hashes)

Uploaded CPython 3.11 manylinux: glibc 2.17+ s390x

tach-0.5.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl (2.5 MB view hashes)

Uploaded CPython 3.11 manylinux: glibc 2.17+ ppc64le

tach-0.5.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl (2.3 MB view hashes)

Uploaded CPython 3.11 manylinux: glibc 2.17+ ARMv7l

tach-0.5.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (2.4 MB view hashes)

Uploaded CPython 3.11 manylinux: glibc 2.17+ ARM64

tach-0.5.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl (2.4 MB view hashes)

Uploaded CPython 3.11 manylinux: glibc 2.5+ i686

tach-0.5.1-cp311-cp311-macosx_11_0_arm64.whl (1.5 MB view hashes)

Uploaded CPython 3.11 macOS 11.0+ ARM64

tach-0.5.1-cp311-cp311-macosx_10_12_x86_64.whl (1.5 MB view hashes)

Uploaded CPython 3.11 macOS 10.12+ x86-64

tach-0.5.1-cp310-none-win_amd64.whl (1.4 MB view hashes)

Uploaded CPython 3.10 Windows x86-64

tach-0.5.1-cp310-none-win32.whl (1.3 MB view hashes)

Uploaded CPython 3.10 Windows x86

tach-0.5.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (2.4 MB view hashes)

Uploaded CPython 3.10 manylinux: glibc 2.17+ x86-64

tach-0.5.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl (2.7 MB view hashes)

Uploaded CPython 3.10 manylinux: glibc 2.17+ s390x

tach-0.5.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl (2.5 MB view hashes)

Uploaded CPython 3.10 manylinux: glibc 2.17+ ppc64le

tach-0.5.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl (2.3 MB view hashes)

Uploaded CPython 3.10 manylinux: glibc 2.17+ ARMv7l

tach-0.5.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (2.4 MB view hashes)

Uploaded CPython 3.10 manylinux: glibc 2.17+ ARM64

tach-0.5.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl (2.4 MB view hashes)

Uploaded CPython 3.10 manylinux: glibc 2.5+ i686

tach-0.5.1-cp310-cp310-macosx_11_0_arm64.whl (1.5 MB view hashes)

Uploaded CPython 3.10 macOS 11.0+ ARM64

tach-0.5.1-cp310-cp310-macosx_10_12_x86_64.whl (1.5 MB view hashes)

Uploaded CPython 3.10 macOS 10.12+ x86-64

tach-0.5.1-cp39-none-win_amd64.whl (1.4 MB view hashes)

Uploaded CPython 3.9 Windows x86-64

tach-0.5.1-cp39-none-win32.whl (1.3 MB view hashes)

Uploaded CPython 3.9 Windows x86

tach-0.5.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (2.4 MB view hashes)

Uploaded CPython 3.9 manylinux: glibc 2.17+ x86-64

tach-0.5.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl (2.7 MB view hashes)

Uploaded CPython 3.9 manylinux: glibc 2.17+ s390x

tach-0.5.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl (2.5 MB view hashes)

Uploaded CPython 3.9 manylinux: glibc 2.17+ ppc64le

tach-0.5.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl (2.3 MB view hashes)

Uploaded CPython 3.9 manylinux: glibc 2.17+ ARMv7l

tach-0.5.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (2.4 MB view hashes)

Uploaded CPython 3.9 manylinux: glibc 2.17+ ARM64

tach-0.5.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl (2.4 MB view hashes)

Uploaded CPython 3.9 manylinux: glibc 2.5+ i686

tach-0.5.1-cp39-cp39-macosx_11_0_arm64.whl (1.5 MB view hashes)

Uploaded CPython 3.9 macOS 11.0+ ARM64

tach-0.5.1-cp39-cp39-macosx_10_12_x86_64.whl (1.5 MB view hashes)

Uploaded CPython 3.9 macOS 10.12+ x86-64

tach-0.5.1-cp38-none-win_amd64.whl (1.4 MB view hashes)

Uploaded CPython 3.8 Windows x86-64

tach-0.5.1-cp38-none-win32.whl (1.3 MB view hashes)

Uploaded CPython 3.8 Windows x86

tach-0.5.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (2.4 MB view hashes)

Uploaded CPython 3.8 manylinux: glibc 2.17+ x86-64

tach-0.5.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl (2.7 MB view hashes)

Uploaded CPython 3.8 manylinux: glibc 2.17+ s390x

tach-0.5.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl (2.5 MB view hashes)

Uploaded CPython 3.8 manylinux: glibc 2.17+ ppc64le

tach-0.5.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl (2.3 MB view hashes)

Uploaded CPython 3.8 manylinux: glibc 2.17+ ARMv7l

tach-0.5.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (2.4 MB view hashes)

Uploaded CPython 3.8 manylinux: glibc 2.17+ ARM64

tach-0.5.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl (2.4 MB view hashes)

Uploaded CPython 3.8 manylinux: glibc 2.5+ i686

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page