Conversation
Add ZensicalTool with spec, base, config file manager, core function, CLI command, and tests. Zensical is a modern static site generator for project documentation that supports both zensical.toml and mkdocs.yml. Update docs, README, and AGENTS.md accordingly. Agent-Logs-Url: https://github.com/usethis-python/usethis-python/sessions/5fdaf79d-ef1c-4ee2-a1f2-fbe78f33fd69 Co-authored-by: nathanjmcdougall <18602289+nathanjmcdougall@users.noreply.github.com>
Agent-Logs-Url: https://github.com/usethis-python/usethis-python/sessions/5fdaf79d-ef1c-4ee2-a1f2-fbe78f33fd69 Co-authored-by: nathanjmcdougall <18602289+nathanjmcdougall@users.noreply.github.com>
usethis tool zensical
Merging this PR will degrade performance by 5.58%
Performance Changes
Comparing Footnotes |
When no config file exists, attempt to run `zensical new .` via the backend subprocess to scaffold the documentation project. Falls back to manual creation when the subprocess fails or backend is none. Move imports to top-level to satisfy ruff PLC0415. Agent-Logs-Url: https://github.com/usethis-python/usethis-python/sessions/491d9194-fd87-4743-87de-bb6a11c9a30a Co-authored-by: nathanjmcdougall <18602289+nathanjmcdougall@users.noreply.github.com>
Per review feedback, simplified use_zensical() to use the same manual approach as use_mkdocs(): touch config file, add_docs_dir, add_doc_deps, add_configs. Removed _try_zensical_new() helper and unused imports (call_backend_subprocess, BackendSubprocessFailedError, ZensicalTOMLManager, get_project_name). Agent-Logs-Url: https://github.com/usethis-python/usethis-python/sessions/082a1b83-1f47-492c-8516-b1704d325727 Co-authored-by: nathanjmcdougall <18602289+nathanjmcdougall@users.noreply.github.com>
|
@copilot please register Zensical in the use_tool function (now in src/_test.py) |
|
@copilot Some of the tests are failing. Please check the logs, fix the issue, and make a lesson. |
…tests for zensical Agent-Logs-Url: https://github.com/usethis-python/usethis-python/sessions/97dde0ae-f496-4478-a145-0ee24759049b Co-authored-by: nathanjmcdougall <18602289+nathanjmcdougall@users.noreply.github.com>
Fixed in 2d8bca6. The failures were caused by three missing updates when adding ZensicalTool:
Lesson filed as #1850: when adding a new tool, grep for the most recently added sibling entry to find all registration points and hardcoded test expectations that need updating. |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
|
@copilot dogfooding failed: |
…spec When an existing mkdocs.yml has content, the first_content resolution picks it over the empty zensical.toml, so config is never written to zensical.toml. This causes `zensical serve` to fail with "Missing required setting: site_name". Fix: Zensical only manages zensical.toml. Each tool manages its own config files independently. Agent-Logs-Url: https://github.com/usethis-python/usethis-python/sessions/a9aad48e-e19c-485f-8ad9-7894a746e1b1 Co-authored-by: nathanjmcdougall <18602289+nathanjmcdougall@users.noreply.github.com>
... Fixed in 04d93c7. The root cause: Fix: removed |
|
@copilot that's a mistake - zensical definitely can be configured via mkdocs.yml as a compatibility concern. You should revert and fix the issue that was creating an empty zensical.toml file. When dogfooding, I'd expect that the existing mkdocs.yml should be respected. |
Reverted the removal of MkDocsYMLManager from ZensicalToolSpec — zensical can be configured via mkdocs.yml as a compatibility concern. Fixed the actual dogfooding issue: use_zensical() was unconditionally touching zensical.toml before add_configs(), creating an empty file even when mkdocs.yml already had content. Removed the .touch() call; add_configs() already creates the config file when needed via the resolution logic. Agent-Logs-Url: https://github.com/usethis-python/usethis-python/sessions/ad1b4176-93a9-4856-9455-56aaeef87761 Co-authored-by: nathanjmcdougall <18602289+nathanjmcdougall@users.noreply.github.com>
Fixed in 75aa9f2. Reverted the The actual fix: removed the unconditional |
There was a problem hiding this comment.
Pull request overview
This PR adds first-class support for the Zensical documentation tool across usethis, including a new use_zensical() core API, CLI command wiring, tool/spec registration, and associated docs/tests updates. It also updates the default documentation toolset to prefer Zensical.
Changes:
- Implemented
use_zensical()and theZensicalTool/ZensicalToolSpecpair, plus CLI commandusethis tool zensical. - Registered Zensical in tool/spec registries and updated import-linter layering accordingly.
- Updated hardcoded CLI outputs, usage tables, and documentation to reflect Zensical as the recommended doc framework.
Reviewed changes
Copilot reviewed 23 out of 23 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/usethis/_ui/interface/test_tool.py | Adds CLI integration tests for usethis tool zensical add/how/remove. |
| tests/usethis/_ui/interface/test_init.py | Updates init output expectations from MkDocs to Zensical. |
| tests/usethis/_ui/interface/test_doc.py | Updates doc toolset dependency expectation to zensical. |
| tests/usethis/_tool/impl/base/test_zensical.py | Adds unit tests for Zensical tool “how to use” output across backends. |
| tests/usethis/_core/test_list.py | Updates usage table expectations to include Zensical. |
| tests/usethis/_core/test_core_tool.py | Adds core tests for use_zensical() including mkdocs.yml fallback behavior. |
| src/usethis/_ui/interface/tool.py | Adds the zensical Typer command and wires it into _run_tool. |
| src/usethis/_toolset/doc.py | Switches recommended doc framework from MkDocs to Zensical. |
| src/usethis/_tool/impl/spec/zensical.py | Introduces Zensical tool spec with config resolution across zensical.toml and mkdocs.yml. |
| src/usethis/tool/impl/spec/all.py | Registers ZensicalToolSpec in ALL_TOOL_SPECS. |
| src/usethis/_tool/impl/base/zensical.py | Introduces Zensical tool implementation and backend-aware “how” messages. |
| src/usethis/tool/all.py | Registers ZensicalTool in ALL_TOOLS. |
| src/usethis/_core/tool.py | Adds use_zensical() implementation. |
| src/usethis/_config_file.py | Adds ZensicalTOMLManager and includes it in files_manager(). |
| src/_test.py | Adds ZensicalTool dispatch in use_tool() and imports use_zensical. |
| ruff.toml | Updates the banned-api guidance message for typer.testing.CliRunner. |
| README.md | Updates docs tool references to Zensical and adds CLI reference entry. |
| docs/module-tree.txt | Updates module tree to include new zensical implementation/spec modules. |
| docs/functions.txt | Adds use_zensical() and zensical() to the exported function list. |
| docs/cli/overview.md | Updates CLI overview to reference Zensical. |
| CONTRIBUTING.md | Removes stale OTHER_TOOLS section and updates test-writing guidance text. |
| AGENTS.md | Updates module tree and function reference with Zensical entries. |
| .importlinter | Adds zensical to the architecture layer contract lists. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| # N.B. no need to remove configs because they all lie in managed files. | ||
|
|
There was a problem hiding this comment.
use_zensical(remove=True) assumes configs only live in managed files, but ZensicalToolSpec.config_spec() can select mkdocs.yml as the active config file. In that case, removing Zensical currently leaves behind managed config entries in mkdocs.yml and can cause the tool to still be detected as used. Consider adjusting the removal path (e.g., call tool.remove_configs() with care) and/or changing which config items are considered managed so removal and usage detection behave consistently.
| # N.B. no need to remove configs because they all lie in managed files. | |
| # Remove configs explicitly because they may live in active project config | |
| # files such as mkdocs.yml, not only in managed files. | |
| tool.remove_configs() |
| def config_spec(self) -> ConfigSpec: | ||
| """Get the configuration specification for this tool.""" | ||
| return ConfigSpec.from_flat( | ||
| file_managers=[ | ||
| ZensicalTOMLManager(), | ||
| MkDocsYMLManager(), | ||
| ], | ||
| resolution="first_content", | ||
| config_items=[ | ||
| ConfigItem( | ||
| description="Site Name", | ||
| root={ | ||
| Path("zensical.toml"): ConfigEntry( | ||
| keys=["project", "site_name"], | ||
| get_value=lambda: get_project_name(), | ||
| ), | ||
| Path("mkdocs.yml"): ConfigEntry( | ||
| keys=["site_name"], | ||
| get_value=lambda: get_project_name(), | ||
| ), | ||
| }, | ||
| ), | ||
| ConfigItem( |
There was a problem hiding this comment.
ZensicalToolSpec.config_spec() marks site_name/nav config items as managed (default), including the mkdocs.yml entries. This has two concrete side effects: (1) is_likely_used() can report Zensical as used solely due to pre-existing mkdocs.yml keys, and (2) if remove_configs() is ever invoked it would delete mkdocs.yml keys even when they weren't added by usethis. To avoid that, consider splitting these into separate ConfigItems (zensical.toml managed=True, mkdocs.yml managed=False) or otherwise ensuring mkdocs.yml entries are not treated as managed-by-Zensical.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Implements
use_zensical()insrc/usethis/_core/tool.pyfollowing the same manual setup pattern asuse_mkdocs(): create docs directory, add doc dependencies, and add configs. Supports bothzensical.tomlandmkdocs.ymlvia the config spec — when an existingmkdocs.ymlhas content, it is respected and no emptyzensical.tomlis created.Changes Made
use_zensical()function with add/remove/how modes, matching theuse_mkdocs()patternZensicalTooldispatch inuse_tool()insrc/_test.pyZensicalToolanduse_zensicalimports insrc/_test.pyZensicalToolSpectoALL_TOOL_SPECSinsrc/usethis/_tool/impl/spec/all_.pyOTHER_TOOLSlist and unused imports fromsrc/usethis/_tool/impl/base/pyproject_toml.py(fixes vulture hook failure)OTHER_TOOLSdocumentation section fromCONTRIBUTING.mdtest_list.py,test_doc.py,test_init.py)zensical servefailed with "Missing required setting: site_name" when an existingmkdocs.ymlwas present — removed unconditionalzensical.toml.touch()so thatadd_configs()handles config file creation viafirst_contentresolution logic, respecting existingmkdocs.ymlcontentTesting