Skip to content

Implement usethis tool tach for architecture enforcement#1639

Open
Copilot wants to merge 8 commits intomainfrom
copilot/implement-usethis-tool-tach
Open

Implement usethis tool tach for architecture enforcement#1639
Copilot wants to merge 8 commits intomainfrom
copilot/implement-usethis-tool-tach

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 29, 2026

  • Create src/usethis/_tool/impl/spec/tach.py - Tach tool specification (config, deps, pre-commit)
  • Create src/usethis/_tool/impl/base/tach.py - Tach tool implementation
  • Add TachTOMLManager to src/usethis/_config_file.py for tach.toml file management
  • Register TachTool in src/usethis/_tool/all_.py
  • Add use_tach() function to src/usethis/_core/tool.py
  • Add tach CLI command to src/usethis/_ui/interface/tool.py
  • Create tests: tests/usethis/_tool/impl/base/test_tach.py (100% coverage on spec+base)
  • Add tests for use_tach() in tests/usethis/_core/test_core_tool.py (add, config, pre-commit, remove, how)
  • Update .importlinter contracts to include tach modules
  • Update AGENTS.md and docs/module-tree.txt sync
  • Fix missing docstrings for use_tach and tach CLI functions
  • Update docs/functions.txt and AGENTS.md sync blocks
  • Revert _toolset/arch.py — tach is an alternative to import-linter, not a complement
  • Register "tach" in _HOOK_ORDER in _integrations/pre_commit/hooks.py
  • Add TachTool to OTHER_TOOLS in pyproject_toml.py and update usage table test expectations
  • Update tach CLI help text to "enforce self-imposed dependency and interface rules"

Resolves #1254


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Copilot AI linked an issue Mar 29, 2026 that may be closed by this pull request
Copilot AI and others added 2 commits March 29, 2026 23:22
Add Tach tool integration that:
- Creates tach.toml configuration with layers inferred from import graph
- Adds tach as a dev dependency
- Configures pre-commit hook for tach check
- Registers tach in the arch toolset alongside Import Linter
- Adds CLI command: usethis tool tach

Agent-Logs-Url: https://github.com/usethis-python/usethis-python/sessions/e208815b-6629-4e78-aaad-bc82cbedace0

Co-authored-by: nathanjmcdougall <18602289+nathanjmcdougall@users.noreply.github.com>
…or tach

Agent-Logs-Url: https://github.com/usethis-python/usethis-python/sessions/e208815b-6629-4e78-aaad-bc82cbedace0

Co-authored-by: nathanjmcdougall <18602289+nathanjmcdougall@users.noreply.github.com>
Copilot AI changed the title [WIP] Implement usethis tool tach for layered architecture Implement usethis tool tach for architecture enforcement Mar 29, 2026
Copilot AI requested a review from nathanjmcdougall March 29, 2026 23:30
@nathanjmcdougall nathanjmcdougall marked this pull request as ready for review March 30, 2026 00:00
@nathanjmcdougall
Copy link
Copy Markdown
Collaborator

@copilot failing static checks, please fix

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Mar 30, 2026

@copilot failing static checks, please fix

Fixed in 19c91fb — the use_tach and tach CLI functions were missing docstrings required by the export-functions hook (which runs with --strict). Also updated docs/functions.txt and the AGENTS.md sync block.

@codspeed-hq
Copy link
Copy Markdown

codspeed-hq bot commented Mar 30, 2026

Merging this PR will degrade performance by 6.1%

❌ 1 regressed benchmark
✅ 1 untouched benchmark

⚠️ Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Mode Benchmark BASE HEAD Efficiency
Simulation test_help_flag 40.4 ms 43.1 ms -6.1%

Comparing copilot/implement-usethis-tool-tach (bd6e237) with main (3204a24)1

Open in CodSpeed

Footnotes

  1. No successful run was found on main (118d2c6) during the generation of this report, so 3204a24 was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

…d use_tach tests

Agent-Logs-Url: https://github.com/usethis-python/usethis-python/sessions/aa9351bc-3fdf-4933-8e5d-48f36e6c7245

Co-authored-by: nathanjmcdougall <18602289+nathanjmcdougall@users.noreply.github.com>
@nathanjmcdougall
Copy link
Copy Markdown
Collaborator

@copilot tests are failing, please fix.

Details

=================================== FAILURES ===================================
_____________________ TestGetUsageTable.test_empty_project _____________________

self = <tests.usethis._core.test_list.TestGetUsageTable object at 0x7fc5307e2980>
tmp_path = PosixPath('/tmp/pytest-of-runner/pytest-0/test_empty_project1')

def test_empty_project(self, tmp_path: Path):
    # Act
    with change_cwd(tmp_path), files_manager():
        table = get_usage_table()

    # Assert
    expected = UsageTable(
        rows=[
            UsageRow(category="tool", name="Codespell", status="unused"),
            UsageRow(category="tool", name="Coverage.py", status="unused"),
            UsageRow(category="tool", name="deptry", status="unused"),
            UsageRow(category="tool", name="Import Linter", status="unused"),
            UsageRow(category="tool", name="MkDocs", status="unused"),
            UsageRow(category="tool", name="pre-commit", status="unused"),
            UsageRow(category="tool", name="pyproject-fmt", status="unused"),
            UsageRow(category="tool", name="pyproject.toml", status="unused"),
            UsageRow(category="tool", name="pytest", status="unused"),
            UsageRow(category="tool", name="requirements.txt", status="unused"),
            UsageRow(category="tool", name="Ruff", status="unused"),
            UsageRow(category="tool", name="ty", status="unused"),
            UsageRow(category="config", name="docstyle", status="unused"),
            UsageRow(category="", name="README", status="unused"),
        ],
    )
  assert table == expected

E AssertionError: assert UsageTable(ro...us='unused')]) == UsageTable(ro...us='unused')])
E
E Full diff:
E - UsageTable(rows=[UsageRow(category='tool', name='Codespell', status='unused'), UsageRow(category='tool', name='Coverage.py', status='unused'), UsageRow(category='tool', name='deptry', status='unused'), UsageRow(category='tool', name='Import Linter', status='unused'), UsageRow(category='tool', name='MkDocs', status='unused'), UsageRow(category='tool', name='pre-commit', status='unused'), UsageRow(category='tool', name='pyproject-fmt', status='unused'), UsageRow(category='tool', name='pyproject.toml', status='unused'), UsageRow(category='tool', name='pytest', status='unused'), UsageRow(category='tool', name='requirements.txt', status='unused'), UsageRow(category='tool', name='Ruff', status='unused'), UsageRow(category='tool', name='ty', status='unused'), UsageRow(category='config', name='docstyle', status='unused'), UsageRow(category='', name='README', status='unused')])
E ? ^^^^^^^^^^^^^^^^^^^^^^
E + UsageTable(rows=[UsageRow(category='tool', name='Codespell', status='unused'), UsageRow(category='tool', name='Coverage.py', status='unused'), UsageRow(category='tool', name='deptry', status='unused'), UsageRow(category='tool', name='Import Linter', status='unused'), UsageRow(category='tool', name='MkDocs', status='unused'), UsageRow(category='tool', name='pre-commit', status='unused'), UsageRow(category='tool', name='pyproject-fmt', status='unused'), UsageRow(category='tool', name='pyproject.toml', status='unused'), UsageRow(category='tool', name='pytest', status='unused'), UsageRow(category='tool', name='requirements.txt', status='unused'), UsageRow(category='tool', name='Ruff', status='unused'), UsageRow(category='tool', name='Tach', status='unused'), UsageRow(category='tool', name='ty', status='unused'), UsageRow(category='config', name='docstyle', status='unused'), UsageRow(category='', name='README', status='unused')])
E ? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

expected = UsageTable(rows=[UsageRow(category='tool', name='Codespell', status='unused'), UsageRow(category='tool', name='Coverag... UsageRow(category='config', name='docstyle', status='unused'), UsageRow(category='', name='README', status='unused')])
self = <tests.usethis._core.test_list.TestGetUsageTable object at 0x7fc5307e2980>
table = UsageTable(rows=[UsageRow(category='tool', name='Codespell', status='unused'), UsageRow(category='tool', name='Coverag... UsageRow(category='config', name='docstyle', status='unused'), UsageRow(category='', name='README', status='unused')])
tmp_path = PosixPath('/tmp/pytest-of-runner/pytest-0/test_empty_project1')

tests/usethis/_core/test_list.py:51: AssertionError
_______________________ TestGetUsageTable.test_ruff_used _______________________

self = <tests.usethis._core.test_list.TestGetUsageTable object at 0x7fc5307e0d00>
tmp_path = PosixPath('/tmp/pytest-of-runner/pytest-0/test_ruff_used0')

def test_ruff_used(self, tmp_path: Path):
    # Arrange
    (tmp_path / "ruff.toml").touch()

    # Act
    with change_cwd(tmp_path), files_manager():
        table = get_usage_table()

    # Assert
    expected = UsageTable(
        rows=[
            UsageRow(category="tool", name="Codespell", status="unused"),
            UsageRow(category="tool", name="Coverage.py", status="unused"),
            UsageRow(category="tool", name="deptry", status="unused"),
            UsageRow(category="tool", name="Import Linter", status="unused"),
            UsageRow(category="tool", name="MkDocs", status="unused"),
            UsageRow(category="tool", name="pre-commit", status="unused"),
            UsageRow(category="tool", name="pyproject-fmt", status="unused"),
            UsageRow(category="tool", name="pyproject.toml", status="unused"),
            UsageRow(category="tool", name="pytest", status="unused"),
            UsageRow(category="tool", name="requirements.txt", status="unused"),
            UsageRow(category="tool", name="Ruff", status="used"),
            UsageRow(category="tool", name="ty", status="unused"),
            UsageRow(category="config", name="docstyle", status="unused"),
            UsageRow(category="", name="README", status="unused"),
        ],
    )
  assert table == expected

E AssertionError: assert UsageTable(ro...us='unused')]) == UsageTable(ro...us='unused')])
E
E Full diff:
E - UsageTable(rows=[UsageRow(category='tool', name='Codespell', status='unused'), UsageRow(category='tool', name='Coverage.py', status='unused'), UsageRow(category='tool', name='deptry', status='unused'), UsageRow(category='tool', name='Import Linter', status='unused'), UsageRow(category='tool', name='MkDocs', status='unused'), UsageRow(category='tool', name='pre-commit', status='unused'), UsageRow(category='tool', name='pyproject-fmt', status='unused'), UsageRow(category='tool', name='pyproject.toml', status='unused'), UsageRow(category='tool', name='pytest', status='unused'), UsageRow(category='tool', name='requirements.txt', status='unused'), UsageRow(category='tool', name='Ruff', status='used'), UsageRow(category='tool', name='ty', status='unused'), UsageRow(category='config', name='docstyle', status='unused'), UsageRow(category='', name='README', status='unused')])
E ? ^^^^^^^^^^^^^^^^^^^^^^
E + UsageTable(rows=[UsageRow(category='tool', name='Codespell', status='unused'), UsageRow(category='tool', name='Coverage.py', status='unused'), UsageRow(category='tool', name='deptry', status='unused'), UsageRow(category='tool', name='Import Linter', status='unused'), UsageRow(category='tool', name='MkDocs', status='unused'), UsageRow(category='tool', name='pre-commit', status='unused'), UsageRow(category='tool', name='pyproject-fmt', status='unused'), UsageRow(category='tool', name='pyproject.toml', status='unused'), UsageRow(category='tool', name='pytest', status='unused'), UsageRow(category='tool', name='requirements.txt', status='unused'), UsageRow(category='tool', name='Ruff', status='used'), UsageRow(category='tool', name='Tach', status='unused'), UsageRow(category='tool', name='ty', status='unused'), UsageRow(category='config', name='docstyle', status='unused'), UsageRow(category='', name='README', status='unused')])
E ? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

expected = UsageTable(rows=[UsageRow(category='tool', name='Codespell', status='unused'), UsageRow(category='tool', name='Coverag... UsageRow(category='config', name='docstyle', status='unused'), UsageRow(category='', name='README', status='unused')])
self = <tests.usethis._core.test_list.TestGetUsageTable object at 0x7fc5307e0d00>
table = UsageTable(rows=[UsageRow(category='tool', name='Codespell', status='unused'), UsageRow(category='tool', name='Coverag... UsageRow(category='config', name='docstyle', status='unused'), UsageRow(category='', name='README', status='unused')])
tmp_path = PosixPath('/tmp/pytest-of-runner/pytest-0/test_ruff_used0')

tests/usethis/_core/test_list.py:80: AssertionError
_____________________ TestGetUsageTable.test_uv_init_case ______________________

self = <tests.usethis._core.test_list.TestGetUsageTable object at 0x7fc5307e33a0>
uv_init_dir = PosixPath('/tmp/pytest-of-runner/pytest-0/test_uv_init_case0')

def test_uv_init_case(self, uv_init_dir: Path):
    # Act
    with change_cwd(uv_init_dir), files_manager():
        table = get_usage_table()

    # Assert
    expected = UsageTable(
        rows=[
            UsageRow(category="tool", name="Codespell", status="unused"),
            UsageRow(category="tool", name="Coverage.py", status="unused"),
            UsageRow(category="tool", name="deptry", status="unused"),
            UsageRow(category="tool", name="Import Linter", status="unused"),
            UsageRow(category="tool", name="MkDocs", status="unused"),
            UsageRow(category="tool", name="pre-commit", status="unused"),
            UsageRow(category="tool", name="pyproject-fmt", status="unused"),
            UsageRow(category="tool", name="pyproject.toml", status="used"),
            UsageRow(category="tool", name="pytest", status="unused"),
            UsageRow(category="tool", name="requirements.txt", status="unused"),
            UsageRow(category="tool", name="Ruff", status="unused"),
            UsageRow(category="tool", name="ty", status="unused"),
            UsageRow(category="config", name="docstyle", status="unused"),
            UsageRow(category="", name="README", status="used"),
        ],
    )
  assert table == expected

E AssertionError: assert UsageTable(ro...atus='used')]) == UsageTable(ro...atus='used')])
E
E Full diff:
E - UsageTable(rows=[UsageRow(category='tool', name='Codespell', status='unused'), UsageRow(category='tool', name='Coverage.py', status='unused'), UsageRow(category='tool', name='deptry', status='unused'), UsageRow(category='tool', name='Import Linter', status='unused'), UsageRow(category='tool', name='MkDocs', status='unused'), UsageRow(category='tool', name='pre-commit', status='unused'), UsageRow(category='tool', name='pyproject-fmt', status='unused'), UsageRow(category='tool', name='pyproject.toml', status='used'), UsageRow(category='tool', name='pytest', status='unused'), UsageRow(category='tool', name='requirements.txt', status='unused'), UsageRow(category='tool', name='Ruff', status='unused'), UsageRow(category='tool', name='ty', status='unused'), UsageRow(category='config', name='docstyle', status='unused'), UsageRow(category='', name='README', status='used')])
E ? ^^^^^^^^^^^^^^^^^^^^^^
E + UsageTable(rows=[UsageRow(category='tool', name='Codespell', status='unused'), UsageRow(category='tool', name='Coverage.py', status='unused'), UsageRow(category='tool', name='deptry', status='unused'), UsageRow(category='tool', name='Import Linter', status='unused'), UsageRow(category='tool', name='MkDocs', status='unused'), UsageRow(category='tool', name='pre-commit', status='unused'), UsageRow(category='tool', name='pyproject-fmt', status='unused'), UsageRow(category='tool', name='pyproject.toml', status='used'), UsageRow(category='tool', name='pytest', status='unused'), UsageRow(category='tool', name='requirements.txt', status='unused'), UsageRow(category='tool', name='Ruff', status='unused'), UsageRow(category='tool', name='Tach', status='unused'), UsageRow(category='tool', name='ty', status='unused'), UsageRow(category='config', name='docstyle', status='unused'), UsageRow(category='', name='README', status='used')])
E ? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

expected = UsageTable(rows=[UsageRow(category='tool', name='Codespell', status='unused'), UsageRow(category='tool', name='Coverag...), UsageRow(category='config', name='docstyle', status='unused'), UsageRow(category='', name='README', status='used')])
self = <tests.usethis._core.test_list.TestGetUsageTable object at 0x7fc5307e33a0>
table = UsageTable(rows=[UsageRow(category='tool', name='Codespell', status='unused'), UsageRow(category='tool', name='Coverag...), UsageRow(category='config', name='docstyle', status='unused'), UsageRow(category='', name='README', status='used')])
uv_init_dir = PosixPath('/tmp/pytest-of-runner/pytest-0/test_uv_init_case0')

/home/runner/work/usethis-python/usethis-python/tests/usethis/_core/test_list.py:106: AssertionError
__________________ TestOtherTools.test_in_sync_with_all_tools __________________

self = <tests.usethis._tool.impl.base.test_pyproject_toml.TestOtherTools object at 0x7fc52fabdfc0>

def test_in_sync_with_all_tools(self):
  assert {tool.name.lower() for tool in OTHER_TOOLS} | {
        PyprojectTOMLTool().name
    } == {tool.name.lower() for tool in ALL_TOOLS}

E AssertionError: assert {'codespell',...-commit', ...} == {'codespell',...-commit', ...}
E
E Extra items in the right set:
E 'tach'
E
E Full diff:
E {
E 'codespell',
E 'coverage.py',
E 'deptry',
E 'import linter',
E 'mkdocs',
E 'pre-commit',
E 'pyproject-fmt',
E 'pyproject.toml',
E 'pytest',
E 'requirements.txt',
E 'ruff',
E - 'tach',
E 'ty',
E }

self = <tests.usethis._tool.impl.base.test_pyproject_toml.TestOtherTools object at 0x7fc52fabdfc0>

tests/usethis/_tool/impl/base/test_pyproject_toml.py:15: AssertionError
---------------- generated Markdown report: /tmp/tmp.jqbeCrH6qE ----------------
=========================== short test summary info ============================
SKIPPED [14] tests/usethis/test_fallback.py:56: Avoid flaky pipelines by testing version bumps manually
SKIPPED [1] tests/usethis/_tool/test_base.py:631: Multiple hooks in one repo not supported yet.
SKIPPED [1] tests/usethis/_tool/test_base.py:771: Multiple hooks in one repo not supported yet
SKIPPED [1] tests/usethis/_tool/test_base.py:808: Multiple hooks in one repo not supported yet
FAILED tests/usethis/_core/test_list.py::TestGetUsageTable::test_empty_project - AssertionError: assert UsageTable(ro...us='unused')]) == UsageTable(ro...us='unused')])

Full diff:

  • UsageTable(rows=[UsageRow(category='tool', name='Codespell', status='unused'), UsageRow(category='tool', name='Coverage.py', status='unused'), UsageRow(category='tool', name='deptry', status='unused'), UsageRow(category='tool', name='Import Linter', status='unused'), UsageRow(category='tool', name='MkDocs', status='unused'), UsageRow(category='tool', name='pre-commit', status='unused'), UsageRow(category='tool', name='pyproject-fmt', status='unused'), UsageRow(category='tool', name='pyproject.toml', status='unused'), UsageRow(category='tool', name='pytest', status='unused'), UsageRow(category='tool', name='requirements.txt', status='unused'), UsageRow(category='tool', name='Ruff', status='unused'), UsageRow(category='tool', name='ty', status='unused'), UsageRow(category='config', name='docstyle', status='unused'), UsageRow(category='', name='README', status='unused')])
    ? ^^^^^^^^^^^^^^^^^^^^^^
  • UsageTable(rows=[UsageRow(category='tool', name='Codespell', status='unused'), UsageRow(category='tool', name='Coverage.py', status='unused'), UsageRow(category='tool', name='deptry', status='unused'), UsageRow(category='tool', name='Import Linter', status='unused'), UsageRow(category='tool', name='MkDocs', status='unused'), UsageRow(category='tool', name='pre-commit', status='unused'), UsageRow(category='tool', name='pyproject-fmt', status='unused'), UsageRow(category='tool', name='pyproject.toml', status='unused'), UsageRow(category='tool', name='pytest', status='unused'), UsageRow(category='tool', name='requirements.txt', status='unused'), UsageRow(category='tool', name='Ruff', status='unused'), UsageRow(category='tool', name='Tach', status='unused'), UsageRow(category='tool', name='ty', status='unused'), UsageRow(category='config', name='docstyle', status='unused'), UsageRow(category='', name='README', status='unused')])
    ? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    FAILED tests/usethis/_core/test_list.py::TestGetUsageTable::test_ruff_used - AssertionError: assert UsageTable(ro...us='unused')]) == UsageTable(ro...us='unused')])

Full diff:

  • UsageTable(rows=[UsageRow(category='tool', name='Codespell', status='unused'), UsageRow(category='tool', name='Coverage.py', status='unused'), UsageRow(category='tool', name='deptry', status='unused'), UsageRow(category='tool', name='Import Linter', status='unused'), UsageRow(category='tool', name='MkDocs', status='unused'), UsageRow(category='tool', name='pre-commit', status='unused'), UsageRow(category='tool', name='pyproject-fmt', status='unused'), UsageRow(category='tool', name='pyproject.toml', status='unused'), UsageRow(category='tool', name='pytest', status='unused'), UsageRow(category='tool', name='requirements.txt', status='unused'), UsageRow(category='tool', name='Ruff', status='used'), UsageRow(category='tool', name='ty', status='unused'), UsageRow(category='config', name='docstyle', status='unused'), UsageRow(category='', name='README', status='unused')])
    ? ^^^^^^^^^^^^^^^^^^^^^^
  • UsageTable(rows=[UsageRow(category='tool', name='Codespell', status='unused'), UsageRow(category='tool', name='Coverage.py', status='unused'), UsageRow(category='tool', name='deptry', status='unused'), UsageRow(category='tool', name='Import Linter', status='unused'), UsageRow(category='tool', name='MkDocs', status='unused'), UsageRow(category='tool', name='pre-commit', status='unused'), UsageRow(category='tool', name='pyproject-fmt', status='unused'), UsageRow(category='tool', name='pyproject.toml', status='unused'), UsageRow(category='tool', name='pytest', status='unused'), UsageRow(category='tool', name='requirements.txt', status='unused'), UsageRow(category='tool', name='Ruff', status='used'), UsageRow(category='tool', name='Tach', status='unused'), UsageRow(category='tool', name='ty', status='unused'), UsageRow(category='config', name='docstyle', status='unused'), UsageRow(category='', name='README', status='unused')])
    ? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    FAILED tests/usethis/_core/test_list.py::TestGetUsageTable::test_uv_init_case - AssertionError: assert UsageTable(ro...atus='used')]) == UsageTable(ro...atus='used')])

Full diff:

  • UsageTable(rows=[UsageRow(category='tool', name='Codespell', status='unused'), UsageRow(category='tool', name='Coverage.py', status='unused'), UsageRow(category='tool', name='deptry', status='unused'), UsageRow(category='tool', name='Import Linter', status='unused'), UsageRow(category='tool', name='MkDocs', status='unused'), UsageRow(category='tool', name='pre-commit', status='unused'), UsageRow(category='tool', name='pyproject-fmt', status='unused'), UsageRow(category='tool', name='pyproject.toml', status='used'), UsageRow(category='tool', name='pytest', status='unused'), UsageRow(category='tool', name='requirements.txt', status='unused'), UsageRow(category='tool', name='Ruff', status='unused'), UsageRow(category='tool', name='ty', status='unused'), UsageRow(category='config', name='docstyle', status='unused'), UsageRow(category='', name='README', status='used')])
    ? ^^^^^^^^^^^^^^^^^^^^^^
  • UsageTable(rows=[UsageRow(category='tool', name='Codespell', status='unused'), UsageRow(category='tool', name='Coverage.py', status='unused'), UsageRow(category='tool', name='deptry', status='unused'), UsageRow(category='tool', name='Import Linter', status='unused'), UsageRow(category='tool', name='MkDocs', status='unused'), UsageRow(category='tool', name='pre-commit', status='unused'), UsageRow(category='tool', name='pyproject-fmt', status='unused'), UsageRow(category='tool', name='pyproject.toml', status='used'), UsageRow(category='tool', name='pytest', status='unused'), UsageRow(category='tool', name='requirements.txt', status='unused'), UsageRow(category='tool', name='Ruff', status='unused'), UsageRow(category='tool', name='Tach', status='unused'), UsageRow(category='tool', name='ty', status='unused'), UsageRow(category='config', name='docstyle', status='unused'), UsageRow(category='', name='README', status='used')])
    ? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    FAILED tests/usethis/_tool/impl/base/test_pyproject_toml.py::TestOtherTools::test_in_sync_with_all_tools - AssertionError: assert {'codespell',...-commit', ...} == {'codespell',...-commit', ...}

Extra items in the right set:
'tach'

Full diff:
{
'codespell',
'coverage.py',
'deptry',
'import linter',
'mkdocs',
'pre-commit',
'pyproject-fmt',
'pyproject.toml',
'pytest',
'requirements.txt',
'ruff',

  • 'tach',
    'ty',
    
    }
    ============ 4 failed, 1520 passed, 17 skipped in 131.12s (0:02:11) ============
    Error: Process completed with exit code 1.
    Run echo "::group::..."
    ...

=====================================================================================
Markdown summaries: https://github.com/usethis-python/usethis-python/actions/runs/23722634434

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Mar 30, 2026

@copilot tests are failing, please fix.

Details

...

Fixed in 6df8bdd — two issues:

  1. TachTool was missing from OTHER_TOOLS in pyproject_toml.py, causing test_in_sync_with_all_tools to fail.
  2. The usage table tests in test_list.py needed a UsageRow(category="tool", name="Tach", status="unused") entry in all three test cases.

Agent-Logs-Url: https://github.com/usethis-python/usethis-python/sessions/a84a6dac-86cc-4e67-a370-bf8466435f37

Co-authored-by: nathanjmcdougall <18602289+nathanjmcdougall@users.noreply.github.com>
@codecov
Copy link
Copy Markdown

codecov bot commented Mar 30, 2026

Codecov Report

❌ Patch coverage is 97.14286% with 4 lines in your changes missing coverage. Please review.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
src/usethis/_ui/interface/tool.py 33.33% 4 Missing ⚠️

📢 Thoughts on this report? Let us know!

@nathanjmcdougall
Copy link
Copy Markdown
Collaborator

nathanjmcdougall commented Mar 30, 2026

@copilot The usethis tool tach CLI itself is not being tested, please add tests.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement usethis tool tach

2 participants