How does it work?

Tach works by analyzing the imports in your Python modules. When you define dependencies in your project-level tach.toml, running tach check will verify that the imports in your modules match your expected dependencies.

What is a module?

A ‘module’ is a Python module with dependencies configured in tach.toml. A module can be a python file or a directory. The module is identified by its import path from the nearest source root (e.g. a.b for <root>/a/b.py), and its dependencies are listed in the depends_on key containing module paths in the same format.

See more information on configuration here.

How can I isolate a module from the rest of the code?

To prevent any external usage of a given module, you can set visibility: [] for the module in tach.toml. This means that no other module can declare a dependency on this module.

See more information on configuration here.

How can I declare modules which are freely usable by the rest of the code?

This is typically done for modules like utils/, errors/ or lib/, which contain relatively isolated code which can be used throughout a project.

Tach allows marking these modules as Utilities, which means they can be used without being listed as an explicit dependency.

Marking a module with utility: true is different from visibility: ['*']. Even when a module has public visibility, other modules must declare an explicit dependency to use it (in fact, modules are publicly visible by default). In contrast, a utility module does not require its dependents to list an explicit dependency.

See more information on configuration here.

Are conditional imports checked?

Tach will check all imports in your source files, including those which are called conditionally. The only exceptions are imports made within TYPE_CHECKING conditional blocks. If you want to disable checks for these imports, you can add ignore_type_checking_imports: true to your tach.toml.

See more information on configuration here.

Can you catch dynamic references?

Since Tach uses the AST to find imports and public members, dynamic imports (e.g. using a string path) and dynamic names (e.g. using setattr, locals, globals) are not supported. If these usages cause Tach to report incorrect errors, the ignore directive should be sufficient to reach a passing state.

How can I make a feature request or file a bug?

This project uses GitHub Issues to track bugs and feature requests. Search the existing issues before filing new issues to avoid duplicates. File your bug or feature request as a new Issue.

How can I get help?

For help and questions, join the Discord!

How can I report a security issue?

Do not report security vulnerabilities through public GitHub issues. Instead, please send a DM to caelean or nashsando on Discord. You can also email us at caelean@gauge.sh or evan@gauge.sh. If the issue is significant, we will consider paying a bounty.

What information does Tach track?

Tach tracks anonymized usage and error report statistics; we ascribe to Posthog’s approach as detailed here. If you would like to opt out of sending anonymized info, you can set disable_logging to true in your tach.toml.