tach

repository·main·Indexed 25 days ago

https://github.com/tach-org/tach

A Python tool written in Rust designed to enforce architectural boundaries. Tach ensures imports follow declared dependencies, cross-module calls use public interfaces, and no dependency cycles exist in the graph. It provides a CLI for initializing projects, interactively defining module boundaries, syncing constraints, and visualizing dependency graphs, as well as a VS Code extension for real-time validation.

Tokens
17.9K
Snippets
43
Records
142
Agent score
84%

What's inside tach

  1. Overview of Tach

    main
    Tach is a tool designed to control dependencies between Python modules. It enables developers to define explicit public interfaces for modules, which helps prevent deep coupling and promotes a more modular architecture. Tach works by verifying that no module imports from another module unless that dependency is explicitly listed. If a module defines a public interface, any import that bypasses that interface will trigger an error from Tach. Additionally, dependencies can be marked as 'deprecated' to surface their usage without causing errors.
  2. Understand Tach dependency management

    main

    Tach is a CLI tool used to control and enforce dependencies between Python modules. It helps prevent deep coupling by allowing you to:

    • Define module boundaries and dependencies.
    • Define explicit public interfaces to restrict how modules interact.
    • Mark dependencies as deprecated to surface usage without triggering errors.
    • Enforce these rules via CI checks or pre-commit hooks.

    Tach is designed to be adopted incrementally and has no runtime impact on your Python code.

  3. Understand how Tach caching works

    main

    Tach uses a 'computation cache' to speed up tasks like tach test. Caching is applied at the command level: a single invocation of a command results in either a complete cache hit or a complete cache miss. Individual sub-tasks (like individual tests within a test suite) are not cached separately.

    When a cache hit occurs, the terminal output is wrapped in the following markers:

    ============ Cached results found!  ============
    ...
    ============ END Cached results  ============
  4. Understand the purpose of Tach for Python modularity

    main

    Tach is a tool designed to manage and enforce modularity in Python codebases. It addresses the complexity of large-scale projects by providing mechanisms to:

    • Define module boundaries: Establish clear separations between different areas of your code.
    • Control dependencies: Manage and restrict how modules depend on one another to prevent messy or opaque dependency webs.
    • Define explicit public interfaces: Prevent deep coupling by requiring modules to interact through defined APIs.
    • Gradual adoption: Allows for incremental implementation in existing, complex projects.
    • Workflow integration: Can be integrated into CI/CD pipelines and pre-commit hooks to enforce architectural rules automatically.
  5. Document ignore reasons with `tach-ignore`

    main

    You can include a reason for ignoring an import by adding a message in parentheses immediately following the tach-ignore directive. This helps document why a specific rule is being bypassed.

    # tach-ignore(Alternative API not yet available 11/26/24) private_api
    from core.api import private_api
  6. Ignore imports using the `tach-ignore` directive

    main

    To allow a specific import unconditionally, use the # tach-ignore comment directive. You can apply this to an entire import line or specify a particular name to ignore when importing multiple items from the same module.

    Important: When specifying names, use the alias as it appears in the import line, not the full module path from the project root.

    # Ignore the entire line
    # tach-ignore
    from core.main import private_function
    
    # Ignore a specific name in a multi-import line
    from core.api import private_calculation, public_service  # tach-ignore private_calculation
    
    # Ignore a specific name within a parenthesized import block
    from core.package import (  # tach-ignore service_two
        service_one,
        service_two
    )
  7. Report security vulnerabilities privately

    main

    Do not report security vulnerabilities through public GitHub issues. To report a security issue privately, use one of the following methods:

    • Discord: Send a Direct Message (DM) to caelean or nashsando via the Tach Discord server.
    • Email: Contact caelean@gauge.sh or evan@gauge.sh.

    Significant security issues may be eligible for a bounty.

  8. Define public interfaces in tach.toml

    main

    You can prevent modules from coupling to implementation details by defining a public interface in tach.toml. When a module has a public interface, Tach will only allow imports that match the specified expose patterns. Any import not explicitly listed in the expose array for that module will cause tach check to fail.

    [[modules]]
    path = "domain"
    depends_on = [
        "core"
    ]
    
    [[modules]]
    path = "core"
    depends_on = []
    
    [[interfaces]]
    expose = ["get_data"]
    from = ["core"]
  9. Configure module boundaries with tach mod

    main

    Run tach mod to open an interactive terminal editor for defining module boundaries.

    Interactive Controls:

    • Arrow keys: Navigate the directory tree.
    • Enter: Mark an individual module.
    • Ctrl + a: Mark all siblings as modules.
    • s: Mark Python source roots (helps Tach identify first-party imports).
    • u: Mark a module as a utility (e.g., utils/) that can be freely used by other code.
    • Ctrl + s: Save changes.
    • Ctrl + c: Exit without saving.

    Note: After making changes with tach mod, you must run tach sync to update dependency rules.

  10. Setup the Tach VS Code Extension

    main

    To use Tach in VS Code, follow these steps:

    1. Install the extension: Once installed, Tach will automatically highlight invalid imports as errors when you save a file.
    2. Configure arguments: If you need to pass specific arguments to Tach, navigate to Extensions > Tach in your VS Code settings.
    3. Restart the server: If the extension is not behaving as expected, open the Command Palette (CMD+SHFT+P on macOS or Ctrl+Shift+P on Windows/Linux) and run the command Tach: Restart Server.