pyossmtool 0.0.2__tar.gz → 0.0.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (143) hide show
  1. pyossmtool-0.0.4/PKG-INFO +260 -0
  2. pyossmtool-0.0.4/README.md +230 -0
  3. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/pyproject.toml +7 -3
  4. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/__init__.py +1 -1
  5. pyossmtool-0.0.4/src/pyossmtool/bundle/defaults/configs/ruff.toml +11 -0
  6. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/cli.py +24 -6
  7. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/installer.py +6 -10
  8. pyossmtool-0.0.4/src/pyossmtool.egg-info/PKG-INFO +260 -0
  9. pyossmtool-0.0.4/tests/test_cli.py +49 -0
  10. pyossmtool-0.0.2/PKG-INFO +0 -351
  11. pyossmtool-0.0.2/README.md +0 -322
  12. pyossmtool-0.0.2/src/pyossmtool/bundle/defaults/configs/ruff.toml +0 -8
  13. pyossmtool-0.0.2/src/pyossmtool.egg-info/PKG-INFO +0 -351
  14. pyossmtool-0.0.2/tests/test_cli.py +0 -17
  15. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/LICENSE +0 -0
  16. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/setup.cfg +0 -0
  17. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/catalog/checks/bandit.scan.yaml +0 -0
  18. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/catalog/checks/codespell.spelling.yaml +0 -0
  19. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/catalog/checks/deadcode.scan.yaml +0 -0
  20. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/catalog/checks/gate.acronym-allowlist.yaml +0 -0
  21. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/catalog/checks/gate.folder-breadth.yaml +0 -0
  22. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/catalog/checks/gate.module-private-vars.yaml +0 -0
  23. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/catalog/checks/gate.module-size.yaml +0 -0
  24. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/catalog/checks/gitleaks.secrets.yaml +0 -0
  25. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/catalog/checks/hadolint.dockerfile.yaml +0 -0
  26. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/catalog/checks/jscpd.duplication.yaml +0 -0
  27. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/catalog/checks/markdownlint.check.yaml +0 -0
  28. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/catalog/checks/mdformat.apply.yaml +0 -0
  29. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/catalog/checks/mdformat.format.yaml +0 -0
  30. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/catalog/checks/mutmut.run.yaml +0 -0
  31. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/catalog/checks/pydeps.cycles.yaml +0 -0
  32. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/catalog/checks/pytest.coverage.yaml +0 -0
  33. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/catalog/checks/pytest.test.yaml +0 -0
  34. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/catalog/checks/radon.cc.yaml +0 -0
  35. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/catalog/checks/radon.mi.yaml +0 -0
  36. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/catalog/checks/ruff.format.apply.yaml +0 -0
  37. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/catalog/checks/ruff.format.yaml +0 -0
  38. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/catalog/checks/ruff.lint.yaml +0 -0
  39. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/catalog/checks/ruff.unused.yaml +0 -0
  40. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/catalog/checks/semgrep.scan.yaml +0 -0
  41. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/catalog/checks/shellcheck.yaml +0 -0
  42. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/catalog/checks/shfmt.apply.yaml +0 -0
  43. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/catalog/checks/shfmt.format.yaml +0 -0
  44. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/catalog/checks/sourcery.review.yaml +0 -0
  45. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/catalog/checks/ty.check.yaml +0 -0
  46. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/catalog/checks/vulture.scan.yaml +0 -0
  47. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/catalog/checks/yamlfmt.apply.yaml +0 -0
  48. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/catalog/checks/yamlfmt.format.yaml +0 -0
  49. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/catalog/checks/yamllint.check.yaml +0 -0
  50. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/catalog/tools/bandit.yaml +0 -0
  51. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/catalog/tools/codespell.yaml +0 -0
  52. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/catalog/tools/deadcode.yaml +0 -0
  53. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/catalog/tools/gitleaks.yaml +0 -0
  54. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/catalog/tools/hadolint.yaml +0 -0
  55. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/catalog/tools/jscpd.yaml +0 -0
  56. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/catalog/tools/markdownlint.yaml +0 -0
  57. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/catalog/tools/mdformat.yaml +0 -0
  58. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/catalog/tools/mutmut.yaml +0 -0
  59. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/catalog/tools/pydeps.yaml +0 -0
  60. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/catalog/tools/pytest.yaml +0 -0
  61. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/catalog/tools/radon.yaml +0 -0
  62. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/catalog/tools/ruff.yaml +0 -0
  63. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/catalog/tools/script.yaml +0 -0
  64. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/catalog/tools/semgrep.yaml +0 -0
  65. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/catalog/tools/shellcheck.yaml +0 -0
  66. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/catalog/tools/shfmt.yaml +0 -0
  67. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/catalog/tools/sourcery.yaml +0 -0
  68. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/catalog/tools/ty.yaml +0 -0
  69. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/catalog/tools/vulture.yaml +0 -0
  70. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/catalog/tools/yamlfmt.yaml +0 -0
  71. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/catalog/tools/yamllint.yaml +0 -0
  72. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/defaults/allowlists/acronyms.yaml +0 -0
  73. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/defaults/allowlists/folder-breadth.txt +0 -0
  74. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/defaults/allowlists/module-private-vars.txt +0 -0
  75. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/defaults/allowlists/module-size.txt +0 -0
  76. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/defaults/configs/bandit.yaml +0 -0
  77. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/defaults/configs/gates/acronym-allowlist.yaml +0 -0
  78. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/defaults/configs/gates/folder-breadth.yaml +0 -0
  79. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/defaults/configs/gates/module-private-vars.yaml +0 -0
  80. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/defaults/configs/gates/module-size.yaml +0 -0
  81. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/defaults/configs/markdownlint.json +0 -0
  82. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/defaults/configs/ty.toml +0 -0
  83. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/defaults/configs/yamlfmt.yaml +0 -0
  84. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/defaults/configs/yamllint.yaml +0 -0
  85. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/defaults/gates/README.md +0 -0
  86. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/defaults/gates/acronym-allowlist.sh +0 -0
  87. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/defaults/gates/folder-breadth.sh +0 -0
  88. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/defaults/gates/lib.sh +0 -0
  89. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/defaults/gates/module-private-vars.sh +0 -0
  90. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/defaults/gates/module-size.sh +0 -0
  91. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/defaults/semgrep/python-quality.yml +0 -0
  92. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/suites/all.yaml +0 -0
  93. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/suites/demo.yaml +0 -0
  94. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/suites/extended.yaml +0 -0
  95. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/suites/format.yaml +0 -0
  96. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/suites/formatting.yaml +0 -0
  97. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/suites/policy.yaml +0 -0
  98. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/suites/python-quality.yaml +0 -0
  99. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/suites/reslab-parity.yaml +0 -0
  100. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/bundle/suites/standard.yaml +0 -0
  101. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/config_resolver.py +0 -0
  102. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/discovery.py +0 -0
  103. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/error_formatters.py +0 -0
  104. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/gate_config.py +0 -0
  105. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/gates.py +0 -0
  106. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/ignore.py +0 -0
  107. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/ignore_materialize.py +0 -0
  108. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/models.py +0 -0
  109. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/parsers/__init__.py +0 -0
  110. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/parsers/analysis.py +0 -0
  111. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/parsers/base.py +0 -0
  112. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/parsers/common.py +0 -0
  113. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/parsers/format_text.py +0 -0
  114. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/parsers/gates.py +0 -0
  115. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/parsers/patterns.py +0 -0
  116. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/parsers/prose.py +0 -0
  117. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/parsers/ruff.py +0 -0
  118. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/parsers/shell.py +0 -0
  119. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/policy/__init__.py +0 -0
  120. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/policy/acronym_allowlist.py +0 -0
  121. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/policy/folder_breadth.py +0 -0
  122. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/registry.py +0 -0
  123. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/reporter.py +0 -0
  124. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/resolver.py +0 -0
  125. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/runner.py +0 -0
  126. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/runner_script.py +0 -0
  127. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool/target_expand.py +0 -0
  128. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool.egg-info/SOURCES.txt +0 -0
  129. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool.egg-info/dependency_links.txt +0 -0
  130. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool.egg-info/entry_points.txt +0 -0
  131. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool.egg-info/requires.txt +0 -0
  132. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/src/pyossmtool.egg-info/top_level.txt +0 -0
  133. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/tests/test_check_modes.py +0 -0
  134. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/tests/test_config_and_targets.py +0 -0
  135. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/tests/test_discovery.py +0 -0
  136. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/tests/test_error_formatters.py +0 -0
  137. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/tests/test_gate_config.py +0 -0
  138. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/tests/test_ignore.py +0 -0
  139. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/tests/test_npm_install.py +0 -0
  140. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/tests/test_packaging.py +0 -0
  141. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/tests/test_parser_registry.py +0 -0
  142. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/tests/test_script_gates.py +0 -0
  143. {pyossmtool-0.0.2 → pyossmtool-0.0.4}/tests/test_wheel_install.py +0 -0
@@ -0,0 +1,260 @@
1
+ Metadata-Version: 2.4
2
+ Name: pyossmtool
3
+ Version: 0.0.4
4
+ Summary: Quality-gate orchestrator for AI-assisted development
5
+ Author-email: Vishal Kumar Mishra <vishal.k.mishra2@gmail.com>
6
+ License-Expression: MIT
7
+ Project-URL: Changelog, https://github.com/inquilabee/pyossmtool/blob/main/CHANGELOG.md
8
+ Project-URL: Homepage, https://github.com/inquilabee/pyossmtool
9
+ Project-URL: Issues, https://github.com/inquilabee/pyossmtool/issues
10
+ Project-URL: Repository, https://github.com/inquilabee/pyossmtool
11
+ Keywords: quality,lint,format,pre-commit,python,static-analysis
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Environment :: Console
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Programming Language :: Python :: 3.14
21
+ Classifier: Topic :: Software Development :: Quality Assurance
22
+ Requires-Python: <3.15,>=3.11
23
+ Description-Content-Type: text/markdown
24
+ License-File: LICENSE
25
+ Requires-Dist: pydantic>=2.0
26
+ Requires-Dist: pathspec>=0.12
27
+ Requires-Dist: pyyaml>=6.0
28
+ Requires-Dist: typer>=0.12
29
+ Dynamic: license-file
30
+
31
+ # pyossmtool
32
+
33
+ Quality gates for Python repos that developers can run locally, in CI, or hand to an AI agent without inventing a new workflow each time.
34
+
35
+ `pyossmtool` gives you one project config, a bundled catalog of checks, quiet success, and structured failure reports. It is inspired by Trunk and pre-commit, but keeps the surface area small:
36
+
37
+ ```bash
38
+ pyossmtool install
39
+ pyossmtool format
40
+ pyossmtool check
41
+ ```
42
+
43
+ ## Install
44
+
45
+ ```bash
46
+ pip install pyossmtool
47
+ # or
48
+ uv add --dev pyossmtool
49
+ ```
50
+
51
+ Requires Python 3.11–3.14.
52
+
53
+ ## 60-Second Setup
54
+
55
+ Create `pyossmtool.yaml`:
56
+
57
+ ```yaml
58
+ suite: all
59
+ env: auto
60
+ target: .
61
+ error-format: compact
62
+ configs:
63
+ mode: auto
64
+ ```
65
+
66
+ Then run:
67
+
68
+ ```bash
69
+ pyossmtool install # install tools needed by suite:
70
+ pyossmtool format # apply formatter/autofix checks
71
+ pyossmtool check # report-only quality checks
72
+ ```
73
+
74
+ The `suite:` value is the project default. You do not need to repeat `--suite all`; the CLI reads it from `pyossmtool.yaml`.
75
+
76
+ Success is silent and exits `0`. Failures exit `1`, write a JSON report under `reports/failures/`, and print the same report through your configured `error-format`.
77
+
78
+ ## Mental Model
79
+
80
+ - **Suite**: a named checklist, such as `python-quality`, `standard`, or `all`.
81
+ - **Check**: one rule runner inside a suite, such as `ruff.lint` or `ty.check`.
82
+ - **`check`**: report-only. It should not rewrite your files.
83
+ - **`format`**: applies write/fix checks, such as formatters.
84
+ - **`install`**: installs the tools needed by the selected suite.
85
+
86
+ Most teams pick a suite once in `pyossmtool.yaml` and run the same three commands everywhere.
87
+
88
+ ## Config That Matters
89
+
90
+ ```yaml
91
+ suite: python-quality # default checklist for install/check/format
92
+ env: auto # auto | managed | project
93
+ target: . # scan root; defaults to .
94
+ error-format: compact # json | log | text | compact | github
95
+
96
+ configs:
97
+ mode: auto # repo configs first, bundled fallback
98
+ ```
99
+
100
+ Use `--suite` only when you want a one-off override:
101
+
102
+ ```bash
103
+ pyossmtool check --suite extended
104
+ pyossmtool install --suite standard
105
+ ```
106
+
107
+ Copy [`pyossmtool.yaml.example`](pyossmtool.yaml.example) for an annotated config with ignores, custom checks, gates, and custom error formatters.
108
+
109
+ ## Suites
110
+
111
+ Suites are bundled starting points. They choose which checks run; tools still discover their own files and `.gitignore` is always respected.
112
+
113
+ | Suite | Use it for |
114
+ | --- | --- |
115
+ | `all` | Run every bundled check |
116
+ | `python-quality` | Core Python lint, format-check, and type checks |
117
+ | `formatting` | Report-only formatting drift |
118
+ | `format` | Formatter/autofix checks that write files |
119
+ | `standard` | Broader portable quality baseline |
120
+ | `extended` | Slower optional checks on top of standard |
121
+ | `policy` | Bundled script gates |
122
+ | `demo` | Internal/sample fixture suite |
123
+
124
+ Examples:
125
+
126
+ ```yaml
127
+ # Local Python repo
128
+ suite: python-quality
129
+ error-format: text
130
+ ```
131
+
132
+ ```yaml
133
+ # CI baseline with GitHub annotations
134
+ suite: standard
135
+ error-format: github
136
+ ```
137
+
138
+ ```yaml
139
+ # Max coverage while developing pyossmtool itself
140
+ suite: all
141
+ error-format: compact
142
+ ```
143
+
144
+ ## Error Output
145
+
146
+ On failure, pyossmtool always writes the canonical JSON report to disk:
147
+
148
+ ```text
149
+ reports/failures/ruff.lint-20260716T163000Z/report.json
150
+ ```
151
+
152
+ `error-format` only controls what is printed to stderr.
153
+
154
+ | Format | Example output |
155
+ | --- | --- |
156
+ | `json` | Pretty JSON report, including `report_path` |
157
+ | `log` | `2026-07-16T12:00:00+00:00 [error] ruff.lint/E501 src/app.py:42: Line too long` |
158
+ | `text` | `- [error] E501: Line too long (src/app.py:42)` |
159
+ | `compact` | `src/app.py:42: error: E501 Line too long` |
160
+ | `github` | `::error file=src/app.py,title=ruff.lint/E501,line=42::Line too long` |
161
+
162
+ Default is `json` when `error-format` is omitted.
163
+
164
+ Custom formatters live in `pyossmtool.yaml`:
165
+
166
+ ```yaml
167
+ suite: all
168
+ error-format: short
169
+ error-formatters:
170
+ short:
171
+ kind: finding_line
172
+ template: "{severity}\t{rule_id}\t{file}:{line}\t{message}"
173
+ jq-summary:
174
+ kind: jq
175
+ program: >
176
+ .findings[] | "[\(.severity)] \(.rule_id) \(.message)"
177
+ ```
178
+
179
+ `finding_line` placeholders: `severity`, `rule_id`, `message`, `file`, `line`, `check_id`, `report_path`.
180
+
181
+ `jq` formatters require `jq` on `PATH`.
182
+
183
+ ## Daily Commands
184
+
185
+ ```bash
186
+ pyossmtool install
187
+ pyossmtool format
188
+ pyossmtool check
189
+ ```
190
+
191
+ Inspect what is available:
192
+
193
+ ```bash
194
+ pyossmtool list suites
195
+ pyossmtool list tools
196
+ pyossmtool list checks
197
+ ```
198
+
199
+ Run a single check:
200
+
201
+ ```bash
202
+ pyossmtool check --check ruff.lint --target .
203
+ ```
204
+
205
+ Export the failure report schema:
206
+
207
+ ```bash
208
+ pyossmtool schema > failure-report.schema.json
209
+ ```
210
+
211
+ ## Project-Local Gates
212
+
213
+ Use gates when a repo needs a policy that is not covered by the bundled catalog.
214
+
215
+ ```bash
216
+ pyossmtool gate init module-size --description "Cap module line counts"
217
+ ```
218
+
219
+ That creates a shell gate under `.pyossmtool/gates/` and a catalog entry under `.pyossmtool/catalog/checks/`. Enable it from `pyossmtool.yaml`:
220
+
221
+ ```yaml
222
+ checks:
223
+ - id: gate.module-size
224
+ ```
225
+
226
+ ## CI
227
+
228
+ Minimal GitHub Actions job:
229
+
230
+ ```yaml
231
+ name: quality
232
+
233
+ on:
234
+ pull_request:
235
+ push:
236
+ branches: [main]
237
+
238
+ jobs:
239
+ pyossmtool:
240
+ runs-on: ubuntu-latest
241
+ steps:
242
+ - uses: actions/checkout@v4
243
+ - uses: astral-sh/setup-uv@v6
244
+ - run: uvx pyossmtool install
245
+ - run: uvx pyossmtool check
246
+ ```
247
+
248
+ For GitHub PR annotations, set:
249
+
250
+ ```yaml
251
+ error-format: github
252
+ ```
253
+
254
+ ## Contributing
255
+
256
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for local development, adding tools/checks, and release notes.
257
+
258
+ ## License
259
+
260
+ MIT
@@ -0,0 +1,230 @@
1
+ # pyossmtool
2
+
3
+ Quality gates for Python repos that developers can run locally, in CI, or hand to an AI agent without inventing a new workflow each time.
4
+
5
+ `pyossmtool` gives you one project config, a bundled catalog of checks, quiet success, and structured failure reports. It is inspired by Trunk and pre-commit, but keeps the surface area small:
6
+
7
+ ```bash
8
+ pyossmtool install
9
+ pyossmtool format
10
+ pyossmtool check
11
+ ```
12
+
13
+ ## Install
14
+
15
+ ```bash
16
+ pip install pyossmtool
17
+ # or
18
+ uv add --dev pyossmtool
19
+ ```
20
+
21
+ Requires Python 3.11–3.14.
22
+
23
+ ## 60-Second Setup
24
+
25
+ Create `pyossmtool.yaml`:
26
+
27
+ ```yaml
28
+ suite: all
29
+ env: auto
30
+ target: .
31
+ error-format: compact
32
+ configs:
33
+ mode: auto
34
+ ```
35
+
36
+ Then run:
37
+
38
+ ```bash
39
+ pyossmtool install # install tools needed by suite:
40
+ pyossmtool format # apply formatter/autofix checks
41
+ pyossmtool check # report-only quality checks
42
+ ```
43
+
44
+ The `suite:` value is the project default. You do not need to repeat `--suite all`; the CLI reads it from `pyossmtool.yaml`.
45
+
46
+ Success is silent and exits `0`. Failures exit `1`, write a JSON report under `reports/failures/`, and print the same report through your configured `error-format`.
47
+
48
+ ## Mental Model
49
+
50
+ - **Suite**: a named checklist, such as `python-quality`, `standard`, or `all`.
51
+ - **Check**: one rule runner inside a suite, such as `ruff.lint` or `ty.check`.
52
+ - **`check`**: report-only. It should not rewrite your files.
53
+ - **`format`**: applies write/fix checks, such as formatters.
54
+ - **`install`**: installs the tools needed by the selected suite.
55
+
56
+ Most teams pick a suite once in `pyossmtool.yaml` and run the same three commands everywhere.
57
+
58
+ ## Config That Matters
59
+
60
+ ```yaml
61
+ suite: python-quality # default checklist for install/check/format
62
+ env: auto # auto | managed | project
63
+ target: . # scan root; defaults to .
64
+ error-format: compact # json | log | text | compact | github
65
+
66
+ configs:
67
+ mode: auto # repo configs first, bundled fallback
68
+ ```
69
+
70
+ Use `--suite` only when you want a one-off override:
71
+
72
+ ```bash
73
+ pyossmtool check --suite extended
74
+ pyossmtool install --suite standard
75
+ ```
76
+
77
+ Copy [`pyossmtool.yaml.example`](pyossmtool.yaml.example) for an annotated config with ignores, custom checks, gates, and custom error formatters.
78
+
79
+ ## Suites
80
+
81
+ Suites are bundled starting points. They choose which checks run; tools still discover their own files and `.gitignore` is always respected.
82
+
83
+ | Suite | Use it for |
84
+ | --- | --- |
85
+ | `all` | Run every bundled check |
86
+ | `python-quality` | Core Python lint, format-check, and type checks |
87
+ | `formatting` | Report-only formatting drift |
88
+ | `format` | Formatter/autofix checks that write files |
89
+ | `standard` | Broader portable quality baseline |
90
+ | `extended` | Slower optional checks on top of standard |
91
+ | `policy` | Bundled script gates |
92
+ | `demo` | Internal/sample fixture suite |
93
+
94
+ Examples:
95
+
96
+ ```yaml
97
+ # Local Python repo
98
+ suite: python-quality
99
+ error-format: text
100
+ ```
101
+
102
+ ```yaml
103
+ # CI baseline with GitHub annotations
104
+ suite: standard
105
+ error-format: github
106
+ ```
107
+
108
+ ```yaml
109
+ # Max coverage while developing pyossmtool itself
110
+ suite: all
111
+ error-format: compact
112
+ ```
113
+
114
+ ## Error Output
115
+
116
+ On failure, pyossmtool always writes the canonical JSON report to disk:
117
+
118
+ ```text
119
+ reports/failures/ruff.lint-20260716T163000Z/report.json
120
+ ```
121
+
122
+ `error-format` only controls what is printed to stderr.
123
+
124
+ | Format | Example output |
125
+ | --- | --- |
126
+ | `json` | Pretty JSON report, including `report_path` |
127
+ | `log` | `2026-07-16T12:00:00+00:00 [error] ruff.lint/E501 src/app.py:42: Line too long` |
128
+ | `text` | `- [error] E501: Line too long (src/app.py:42)` |
129
+ | `compact` | `src/app.py:42: error: E501 Line too long` |
130
+ | `github` | `::error file=src/app.py,title=ruff.lint/E501,line=42::Line too long` |
131
+
132
+ Default is `json` when `error-format` is omitted.
133
+
134
+ Custom formatters live in `pyossmtool.yaml`:
135
+
136
+ ```yaml
137
+ suite: all
138
+ error-format: short
139
+ error-formatters:
140
+ short:
141
+ kind: finding_line
142
+ template: "{severity}\t{rule_id}\t{file}:{line}\t{message}"
143
+ jq-summary:
144
+ kind: jq
145
+ program: >
146
+ .findings[] | "[\(.severity)] \(.rule_id) \(.message)"
147
+ ```
148
+
149
+ `finding_line` placeholders: `severity`, `rule_id`, `message`, `file`, `line`, `check_id`, `report_path`.
150
+
151
+ `jq` formatters require `jq` on `PATH`.
152
+
153
+ ## Daily Commands
154
+
155
+ ```bash
156
+ pyossmtool install
157
+ pyossmtool format
158
+ pyossmtool check
159
+ ```
160
+
161
+ Inspect what is available:
162
+
163
+ ```bash
164
+ pyossmtool list suites
165
+ pyossmtool list tools
166
+ pyossmtool list checks
167
+ ```
168
+
169
+ Run a single check:
170
+
171
+ ```bash
172
+ pyossmtool check --check ruff.lint --target .
173
+ ```
174
+
175
+ Export the failure report schema:
176
+
177
+ ```bash
178
+ pyossmtool schema > failure-report.schema.json
179
+ ```
180
+
181
+ ## Project-Local Gates
182
+
183
+ Use gates when a repo needs a policy that is not covered by the bundled catalog.
184
+
185
+ ```bash
186
+ pyossmtool gate init module-size --description "Cap module line counts"
187
+ ```
188
+
189
+ That creates a shell gate under `.pyossmtool/gates/` and a catalog entry under `.pyossmtool/catalog/checks/`. Enable it from `pyossmtool.yaml`:
190
+
191
+ ```yaml
192
+ checks:
193
+ - id: gate.module-size
194
+ ```
195
+
196
+ ## CI
197
+
198
+ Minimal GitHub Actions job:
199
+
200
+ ```yaml
201
+ name: quality
202
+
203
+ on:
204
+ pull_request:
205
+ push:
206
+ branches: [main]
207
+
208
+ jobs:
209
+ pyossmtool:
210
+ runs-on: ubuntu-latest
211
+ steps:
212
+ - uses: actions/checkout@v4
213
+ - uses: astral-sh/setup-uv@v6
214
+ - run: uvx pyossmtool install
215
+ - run: uvx pyossmtool check
216
+ ```
217
+
218
+ For GitHub PR annotations, set:
219
+
220
+ ```yaml
221
+ error-format: github
222
+ ```
223
+
224
+ ## Contributing
225
+
226
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for local development, adding tools/checks, and release notes.
227
+
228
+ ## License
229
+
230
+ MIT
@@ -1,9 +1,9 @@
1
1
  [project]
2
2
  name = "pyossmtool"
3
- version = "0.0.2"
3
+ version = "0.0.4"
4
4
  description = "Quality-gate orchestrator for AI-assisted development"
5
5
  readme = "README.md"
6
- requires-python = ">=3.11,<3.14"
6
+ requires-python = ">=3.11,<3.15"
7
7
  license = "MIT"
8
8
  license-files = ["LICENSE"]
9
9
  authors = [
@@ -26,6 +26,7 @@ classifiers = [
26
26
  "Programming Language :: Python :: 3.11",
27
27
  "Programming Language :: Python :: 3.12",
28
28
  "Programming Language :: Python :: 3.13",
29
+ "Programming Language :: Python :: 3.14",
29
30
  "Topic :: Software Development :: Quality Assurance",
30
31
  ]
31
32
  dependencies = [
@@ -83,7 +84,10 @@ line-length = 120
83
84
  target-version = "py311"
84
85
 
85
86
  [tool.ruff.lint]
86
- select = ["B", "E", "F", "I", "UP"]
87
+ select = ["B", "C90", "E", "F", "I", "UP"]
88
+
89
+ [tool.ruff.lint.mccabe]
90
+ max-complexity = 10
87
91
 
88
92
  [tool.ty]
89
93
  # Repo-owned config; wins over bundled defaults when configs.mode=auto
@@ -1,3 +1,3 @@
1
1
  """pyossmtool — quality-gate orchestrator for AI-assisted development."""
2
2
 
3
- __version__ = "0.0.2"
3
+ __version__ = "0.0.4"
@@ -0,0 +1,11 @@
1
+ line-length = 120
2
+ target-version = "py311"
3
+
4
+ [lint]
5
+ select = ["E", "F", "I", "UP", "B", "C90"]
6
+
7
+ [lint.mccabe]
8
+ max-complexity = 10
9
+
10
+ [format]
11
+ quote-style = "double"
@@ -89,12 +89,22 @@ def export_schema() -> None:
89
89
 
90
90
  @app.command("install")
91
91
  def install(
92
- suite: str = typer.Option("demo", "--suite", help="Suite whose tool dependencies to install"),
92
+ suite: str | None = typer.Option(
93
+ None,
94
+ "--suite",
95
+ help="Suite whose tools to install (default: suite from pyossmtool.yaml)",
96
+ ),
93
97
  ) -> None:
94
98
  registry = _registry()
95
- installer = Installer(registry, _project_root())
99
+ project_root = _project_root()
100
+ project_config = registry.load_project_config(project_root)
101
+ suite_id = suite or (project_config.suite if project_config else None)
102
+ if not suite_id:
103
+ typer.echo("SETUP provide --suite or set suite: in pyossmtool.yaml", err=True)
104
+ raise typer.Exit(code=2)
105
+ installer = Installer(registry, project_root)
96
106
  try:
97
- installer.install_suite(suite)
107
+ installer.install_suite(suite_id)
98
108
  except Exception as exc:
99
109
  typer.echo(f"SETUP {exc}", err=True)
100
110
  raise typer.Exit(code=2) from exc
@@ -102,7 +112,11 @@ def install(
102
112
 
103
113
  @app.command("check")
104
114
  def check_cmd(
105
- suite: str | None = typer.Option(None, "--suite", help="Suite id to run"),
115
+ suite: str | None = typer.Option(
116
+ None,
117
+ "--suite",
118
+ help="Suite id to run (default: suite from pyossmtool.yaml)",
119
+ ),
106
120
  check: str | None = typer.Option(None, "--check", help="Single check id to run"),
107
121
  target: str | None = typer.Option(None, "--target", help="Target path for single check"),
108
122
  fail_fast: bool = typer.Option(False, "--fail-fast", help="Stop at first failure"),
@@ -114,7 +128,11 @@ def check_cmd(
114
128
 
115
129
  @app.command("format")
116
130
  def format_cmd(
117
- suite: str | None = typer.Option("format", "--suite", help="Suite id to run"),
131
+ suite: str | None = typer.Option(
132
+ None,
133
+ "--suite",
134
+ help="Suite id to run (default: suite from pyossmtool.yaml)",
135
+ ),
118
136
  check: str | None = typer.Option(None, "--check", help="Single check id to run"),
119
137
  target: str | None = typer.Option(None, "--target", help="Target path for single check"),
120
138
  fail_fast: bool = typer.Option(False, "--fail-fast", help="Stop at first failure"),
@@ -147,7 +165,7 @@ def _execute(
147
165
 
148
166
  suite_id = suite or (project_config.suite if project_config else None)
149
167
  if not suite_id:
150
- typer.echo("SETUP provide --suite or create pyossmtool.yaml", err=True)
168
+ typer.echo("SETUP provide --suite or set suite: in pyossmtool.yaml", err=True)
151
169
  return 2
152
170
 
153
171
  try:
@@ -76,6 +76,12 @@ class Installer:
76
76
  return False
77
77
 
78
78
  def _managed_python(self) -> str:
79
+ """Prefer a stable CPython for managed tool installs.
80
+
81
+ pyossmtool itself supports 3.11–3.14. Some third-party CLI tools still lag
82
+ on brand-new interpreters, so when the host is 3.14+, prefer 3.13/3.12/3.11
83
+ if available for the managed venv.
84
+ """
79
85
  if sys.version_info < (3, 14):
80
86
  return sys.executable
81
87
  for candidate in ("python3.13", "python3.12", "python3.11"):
@@ -85,16 +91,6 @@ class Installer:
85
91
  return sys.executable
86
92
 
87
93
  def _ensure_managed_venv(self) -> None:
88
- python_bin = self.managed_venv / "bin" / "python"
89
- if python_bin.exists():
90
- version = subprocess.run(
91
- [str(python_bin), "--version"],
92
- capture_output=True,
93
- text=True,
94
- check=True,
95
- ).stdout
96
- if "3.14" in version:
97
- shutil.rmtree(self.managed_venv)
98
94
  if (self.managed_venv / "bin" / "python").exists():
99
95
  return
100
96
  self.managed_venv.parent.mkdir(parents=True, exist_ok=True)