FAQ
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.
Can I declare a module without restricting its dependencies?
Yes, you can mark a module as unchecked
in your tach.toml
configuration. This lets you make Tach aware of a module boundary so that it can be referenced in other modules’ dependencies,
even if you don’t want to restrict the dependencies of every module.
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.
How can I define a public interface for a module?
Public interfaces are defined in tach.toml, and restrict the imports which are allowed from a given module. This is useful when you want to expose a stable API from a module and prevent other modules from becoming deeply coupled to its implementation details.
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
.