syntopica-codeality-py 0.2.0__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.
- syntopica_codeality_py-0.2.0/.gitignore +44 -0
- syntopica_codeality_py-0.2.0/CHANGELOG.md +222 -0
- syntopica_codeality_py-0.2.0/LICENSE +21 -0
- syntopica_codeality_py-0.2.0/PKG-INFO +96 -0
- syntopica_codeality_py-0.2.0/README.md +53 -0
- syntopica_codeality_py-0.2.0/codeality-py.toml +27 -0
- syntopica_codeality_py-0.2.0/mypy.ini +10 -0
- syntopica_codeality_py-0.2.0/pyproject.toml +60 -0
- syntopica_codeality_py-0.2.0/ruff.toml +51 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/__init__.py +1 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/assets/codeality-py-ci.yml +51 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/assets/codeality-py.toml +19 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/assets/importlinter.ini +12 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/assets/mypy.ini +7 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/assets/pyproject-sections.toml +34 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/assets/ruff.toml +51 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/baseline/__init__.py +1 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/baseline/baseline_file.py +15 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/baseline/classified_findings.py +14 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/baseline/classify_findings.py +18 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/baseline/finding_context.py +19 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/baseline/fingerprint.py +21 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/baseline/fingerprint_context.py +27 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/baseline/read_baseline.py +32 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/baseline/write_baseline.py +18 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/cli.py +22 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/commands/__init__.py +1 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/commands/baseline_check_command.py +36 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/commands/baseline_command.py +15 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/commands/baseline_update_command.py +24 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/commands/check_command.py +45 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/commands/checked_project.py +26 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/commands/gate_command.py +33 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/commands/init_command.py +53 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/commands/project_option.py +12 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/config/__init__.py +1 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/config/baseline_config.py +27 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/config/check_schema_version.py +16 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/config/config_error.py +5 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/config/default_generated_globs.py +10 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/config/discover_source_roots.py +30 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/config/discover_test_roots.py +12 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/config/limits.py +11 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/config/load_config.py +64 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/config/module_role.py +18 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/config/override.py +14 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/config/parse_overrides.py +32 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/config/parse_roles.py +33 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/config/parse_rule_codes.py +17 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/config/pyproject_layout_hints.py +36 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/config/read_config_document.py +17 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/config/reject_duplicate_role_claims.py +20 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/config/reject_unknown_keys.py +15 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/engine/__init__.py +1 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/engine/check_project.py +32 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/engine/check_result.py +15 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/engine/check_source_file.py +25 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/engine/fingerprint_findings.py +33 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/engine/rule_registry.py +24 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/gate/__init__.py +1 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/gate/build_stage_result.py +20 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/gate/gate_result.py +23 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/gate/gate_stages.py +50 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/gate/run_gate.py +27 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/gate/run_stage.py +52 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/gate/stage.py +14 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/gate/stage_kind.py +11 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/gate/stage_result.py +19 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/gate/stage_status.py +12 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/init/__init__.py +1 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/init/add_missing_rules.py +33 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/init/apply_init.py +19 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/init/current_branch.py +24 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/init/first_party_packages.py +23 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/init/has_ruff_table.py +21 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/init/managed_asset_files.py +9 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/init/managed_file.py +16 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/init/merge_pyproject_sections.py +35 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/init/merge_quality_group.py +14 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/init/merge_ruff_config.py +28 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/init/plan_asset_file.py +25 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/init/plan_disposition.py +12 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/init/plan_init.py +28 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/init/plan_pyproject.py +32 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/init/plan_ruff.py +21 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/init/plan_shadowed_ruff.py +28 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/init/python_floor_minor.py +15 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/init/read_asset.py +8 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/init/read_requires_python.py +16 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/init/render_asset.py +55 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/init/render_nested_workflow.py +25 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/init/repository_root.py +15 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/init/workflow_target.py +21 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/model/__init__.py +1 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/model/finding.py +34 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/model/location.py +14 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/model/rule_code.py +30 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/model/severity.py +10 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/parsing/__init__.py +1 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/parsing/infrastructure_error.py +5 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/parsing/parse_source_file.py +32 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/parsing/read_source_text.py +16 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/parsing/source_file.py +18 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/parsing/syntax_error_finding.py +16 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/report/__init__.py +1 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/report/exit_code.py +12 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/report/finding_document.py +24 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/report/findings_summary.py +11 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/report/render_gate_report.py +21 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/report/render_json_report.py +24 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/report/render_text_report.py +16 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/report/stage_document.py +16 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/roles/__init__.py +1 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/roles/assign_module_role.py +36 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/roles/compile_glob.py +17 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/roles/matches_any_pattern.py +8 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/roles/matches_glob.py +14 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/roles/test_file_patterns.py +18 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/rules/__init__.py +1 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/rules/barrel_only_init.py +38 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/rules/count_code_lines.py +29 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/rules/data_unit_findings.py +16 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/rules/docstring_line_spans.py +26 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/rules/file_matches_unit.py +33 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/rules/grab_bag_names.py +3 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/rules/is_allowed_barrel_statement.py +16 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/rules/is_column_list.py +15 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/rules/is_docstring_statement.py +12 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/rules/is_sql_literal.py +15 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/rules/is_static_dunder_assignment.py +24 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/rules/is_type_checking_block.py +15 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/rules/joined_string_text.py +12 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/rules/looks_like_sql.py +31 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/rules/max_file_lines.py +35 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/rules/no_grab_bag_names.py +36 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/rules/no_inline_sql.py +52 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/rules/one_primary_unit.py +22 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/rules/ordinary_unit_findings.py +26 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/rules/sql_subject.py +10 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/rules/unit_finding.py +23 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/suppression/__init__.py +1 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/suppression/apply_suppressions.py +31 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/suppression/build_suppression.py +15 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/suppression/covering_suppression.py +25 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/suppression/is_overridden.py +14 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/suppression/parse_suppression_line.py +25 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/suppression/parse_suppressions.py +17 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/suppression/suppression.py +14 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/traversal/__init__.py +1 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/traversal/collect_source_files.py +17 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/traversal/default_excludes.py +25 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/traversal/gitignore_matcher.py +44 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/traversal/walk_root.py +27 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/units/__init__.py +1 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/units/coalesce_overloads.py +17 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/units/coalesce_singledispatch.py +25 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/units/collect_declarations.py +15 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/units/count_primary_declarations.py +18 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/units/declaration.py +18 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/units/declaration_for.py +33 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/units/declaration_kind.py +11 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/units/decorator_name.py +14 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/units/decorator_names.py +12 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/units/is_main_guard.py +11 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/units/is_private_local_handler.py +13 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/units/legacy_type_alias.py +33 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/units/literal_string_names.py +15 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/units/merge_stray_letters.py +20 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/units/named_declaration.py +23 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/units/overload_family_length.py +22 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/units/resolve_exported_names.py +22 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/units/to_snake_case.py +20 -0
- syntopica_codeality_py-0.2.0/src/codeality_py/units/top_level_statements.py +20 -0
- syntopica_codeality_py-0.2.0/tests/baseline/test_classify_findings.py +111 -0
- syntopica_codeality_py-0.2.0/tests/commands/test_baseline_command.py +67 -0
- syntopica_codeality_py-0.2.0/tests/commands/test_check_command.py +77 -0
- syntopica_codeality_py-0.2.0/tests/config/test_load_config.py +88 -0
- syntopica_codeality_py-0.2.0/tests/config/test_pyproject_layout_hints.py +52 -0
- syntopica_codeality_py-0.2.0/tests/conftest.py +35 -0
- syntopica_codeality_py-0.2.0/tests/gate/test_gate_stages.py +69 -0
- syntopica_codeality_py-0.2.0/tests/gate/test_run_gate.py +85 -0
- syntopica_codeality_py-0.2.0/tests/init/test_merge_ruff_config.py +49 -0
- syntopica_codeality_py-0.2.0/tests/init/test_plan_init.py +172 -0
- syntopica_codeality_py-0.2.0/tests/init/test_render_asset.py +132 -0
- syntopica_codeality_py-0.2.0/tests/model/test_finding.py +27 -0
- syntopica_codeality_py-0.2.0/tests/model/test_rule_code.py +12 -0
- syntopica_codeality_py-0.2.0/tests/parsing/test_parse_source_file.py +42 -0
- syntopica_codeality_py-0.2.0/tests/roles/test_assign_module_role.py +72 -0
- syntopica_codeality_py-0.2.0/tests/roles/test_matches_glob.py +38 -0
- syntopica_codeality_py-0.2.0/tests/rules/test_barrel_only_init.py +69 -0
- syntopica_codeality_py-0.2.0/tests/rules/test_file_matches_unit.py +41 -0
- syntopica_codeality_py-0.2.0/tests/rules/test_max_file_lines.py +53 -0
- syntopica_codeality_py-0.2.0/tests/rules/test_no_grab_bag_names.py +37 -0
- syntopica_codeality_py-0.2.0/tests/rules/test_no_inline_sql.py +71 -0
- syntopica_codeality_py-0.2.0/tests/rules/test_one_primary_unit.py +209 -0
- syntopica_codeality_py-0.2.0/tests/test_cli_version.py +11 -0
- syntopica_codeality_py-0.2.0/tests/traversal/test_collect_source_files.py +78 -0
- syntopica_codeality_py-0.2.0/tests/units/test_to_snake_case.py +23 -0
- syntopica_codeality_py-0.2.0/uv.lock +1061 -0
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
node_modules/
|
|
2
|
+
.pnpm-store/
|
|
3
|
+
**/.astro/
|
|
4
|
+
**/.next/
|
|
5
|
+
**/.nuxt/
|
|
6
|
+
**/.output/
|
|
7
|
+
**/dist/
|
|
8
|
+
**/build/
|
|
9
|
+
**/coverage/
|
|
10
|
+
**/*.tsbuildinfo
|
|
11
|
+
**/.lighthouseci/
|
|
12
|
+
# Written per workspace by scripts/deps-graph-aliased.mjs and removed again on
|
|
13
|
+
# the way out; ignored so a crashed run cannot leave a tracked file behind.
|
|
14
|
+
**/.baseline-depcruise.tsconfig.json
|
|
15
|
+
**/.turbo/
|
|
16
|
+
.turbo/
|
|
17
|
+
.DS_Store
|
|
18
|
+
# CocoIndex Code (ccc)
|
|
19
|
+
/.cocoindex_code/
|
|
20
|
+
# Codegraph local index
|
|
21
|
+
/.codegraph/
|
|
22
|
+
|
|
23
|
+
# Serena (local tool state)
|
|
24
|
+
.serena/
|
|
25
|
+
|
|
26
|
+
target/
|
|
27
|
+
|
|
28
|
+
# eslint-suppressions.json is deliberately committed: it is the shared
|
|
29
|
+
# frozen baseline of pre-existing violations.
|
|
30
|
+
|
|
31
|
+
# Stryker's mutant sandbox and HTML report
|
|
32
|
+
.stryker-tmp/
|
|
33
|
+
reports/mutation/
|
|
34
|
+
|
|
35
|
+
# Python (packages/codeality-py, templates/python-package)
|
|
36
|
+
**/.venv/
|
|
37
|
+
**/__pycache__/
|
|
38
|
+
**/.pytest_cache/
|
|
39
|
+
**/.mypy_cache/
|
|
40
|
+
**/.ruff_cache/
|
|
41
|
+
**/*.egg-info/
|
|
42
|
+
|
|
43
|
+
# coverage.py writes its SQLite database beside the tests it measured.
|
|
44
|
+
.coverage
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `syntopica-codeality-py` are documented here. The format
|
|
4
|
+
follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the project
|
|
5
|
+
adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
|
+
|
|
7
|
+
## 0.2.0
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
|
|
11
|
+
- Renamed everywhere: the distribution is `syntopica-codeality-py`, the import
|
|
12
|
+
package is `codeality_py`, the console script is `codeality-py`, and the
|
|
13
|
+
configuration file is `codeality-py.toml`. The old `busirocket-baseline-py`
|
|
14
|
+
releases stay on PyPI and receive no further updates.
|
|
15
|
+
- The inline suppression prefix is now `# codeality-py: ignore[...]` and
|
|
16
|
+
`# codeality-py: ignore-file[...]`. Rule codes keep the `BPY` prefix: codes
|
|
17
|
+
are permanent identifiers and never change meaning.
|
|
18
|
+
|
|
19
|
+
### Migration
|
|
20
|
+
|
|
21
|
+
- Replace the dependency, rename `baseline-py.toml` to `codeality-py.toml`,
|
|
22
|
+
rewrite any `# baseline-py:` suppression comment, and change
|
|
23
|
+
`uv run baseline-py gate` to `uv run codeality-py gate` in CI.
|
|
24
|
+
|
|
25
|
+
## 0.1.12
|
|
26
|
+
|
|
27
|
+
### Fixed
|
|
28
|
+
|
|
29
|
+
- A failing stage's detail now carries its stderr as well as its stdout. deptry
|
|
30
|
+
reports on stderr, so a red deptry stage in CI showed an exit code and an
|
|
31
|
+
empty detail, and the reader had nothing to act on.
|
|
32
|
+
|
|
33
|
+
## 0.1.11
|
|
34
|
+
|
|
35
|
+
### Fixed
|
|
36
|
+
|
|
37
|
+
- An f-string holding SQL is one `BPY006` finding, reported at the string. Its
|
|
38
|
+
constant parts were reported too, and their positions differ between Python
|
|
39
|
+
3.11 and 3.12, so the same query fingerprinted differently depending on the
|
|
40
|
+
interpreter: a baseline recorded on 3.13 reported one new and one resolved
|
|
41
|
+
finding on a 3.11 runner.
|
|
42
|
+
- `init --ci` in a project nested inside a repository writes the workflow at the
|
|
43
|
+
repository root, named `quality-<project>.yml`, with every step running from
|
|
44
|
+
the project directory. GitHub reads workflows only from the root, so the file
|
|
45
|
+
scaffolded inside `tools/qlctool` was never picked up.
|
|
46
|
+
|
|
47
|
+
## 0.1.10
|
|
48
|
+
|
|
49
|
+
### Fixed
|
|
50
|
+
|
|
51
|
+
- The scaffolded workflow listens on the branch the project is checked out on
|
|
52
|
+
instead of always `main`. Two of the first eight adopters lived on `master`
|
|
53
|
+
and on a feature branch, and a workflow watching `main` never ran for either;
|
|
54
|
+
a nested project reads the enclosing repository's branch.
|
|
55
|
+
|
|
56
|
+
## 0.1.9
|
|
57
|
+
|
|
58
|
+
### Fixed
|
|
59
|
+
|
|
60
|
+
- `init` no longer rewrites a consumer's `[tool.ruff.lint]` `select` and
|
|
61
|
+
`ignore` arrays when merging. The old merge rebuilt each array as a sorted
|
|
62
|
+
set, which kept every code and dropped every comment - and a consumer's ignore
|
|
63
|
+
list is usually a dated ledger of adoption debt, one family per line with the
|
|
64
|
+
count found. The arrays are now extended in place: missing codes land on one
|
|
65
|
+
new line, marked, and nothing else moves. A project with nothing missing is
|
|
66
|
+
reported `unchanged`.
|
|
67
|
+
- The scaffolded CI matrix and ruff `target-version` follow the project's
|
|
68
|
+
`requires-python` floor instead of a hard-coded 3.11. A matrix cell below the
|
|
69
|
+
floor failed on `uv sync` before the gate ran; a ruff target below it let
|
|
70
|
+
pyupgrade stop short of the syntax the project may already use.
|
|
71
|
+
|
|
72
|
+
### Changed
|
|
73
|
+
|
|
74
|
+
- The scaffolded workflow installs with
|
|
75
|
+
`uv sync --locked --all-extras --all-groups`, so CI audits and tests the same
|
|
76
|
+
environment a local `uv run codeality-py gate` does; a group-only install left
|
|
77
|
+
out the extras the tests import. Its actions are pinned by commit SHA.
|
|
78
|
+
- The shipped `mypy.ini` no longer carries a `[mypy-tests.*]` section. The
|
|
79
|
+
gate's mypy stage checks source roots only, so the section relaxed nothing;
|
|
80
|
+
configuration should not promise what the gate does not do.
|
|
81
|
+
|
|
82
|
+
## 0.1.8
|
|
83
|
+
|
|
84
|
+
### Added
|
|
85
|
+
|
|
86
|
+
- `init` now reports a `ruff.toml` sitting beside a pyproject that also declares
|
|
87
|
+
`[tool.ruff]`. Ruff reads one configuration per directory, so the file wins
|
|
88
|
+
outright and the table is never read - silently. The pair builds itself over
|
|
89
|
+
time: init writes the file when no table exists, and a table arrives later.
|
|
90
|
+
Found in DJCenterDeluxe, which spent a release linting against a config nobody
|
|
91
|
+
read; once the shadow was removed, 1707 findings resolved to 6 real ones.
|
|
92
|
+
|
|
93
|
+
### Changed
|
|
94
|
+
|
|
95
|
+
- The shipped deptry ignores gained `DEP004` defaults for the pytest family:
|
|
96
|
+
test tooling legitimately lives in a dev group and is imported only by tests.
|
|
97
|
+
|
|
98
|
+
## 0.1.7
|
|
99
|
+
|
|
100
|
+
### Changed
|
|
101
|
+
|
|
102
|
+
- A missing shadow-stage tool is now `skipped-not-applicable` instead of
|
|
103
|
+
`failed-to-run`. A required tool that cannot run is still a failure; an
|
|
104
|
+
advisory tool that was never installed is not an alarm.
|
|
105
|
+
- `init` no longer adds the quality dependency group to a project whose
|
|
106
|
+
`requires-python` floor is below 3.11: the group carries
|
|
107
|
+
`syntopica-codeality-py`, and declaring it there makes every uv resolution
|
|
108
|
+
unsatisfiable. Found adopting the baseline in `djplayerdeluxe`, which declares
|
|
109
|
+
`>=3.8` for its Raspberry Pi target.
|
|
110
|
+
|
|
111
|
+
## 0.1.6
|
|
112
|
+
|
|
113
|
+
### Added
|
|
114
|
+
|
|
115
|
+
- `[audit] ignore-vulns` in `codeality-py.toml`: accepted advisories, each
|
|
116
|
+
expected to carry a written reason, reach pip-audit as `--ignore-vuln` flags.
|
|
117
|
+
Found adopting the baseline in `clawd-pet`, where platformio 6.x pins
|
|
118
|
+
starlette below the patched release and the gate had no way to accept the
|
|
119
|
+
documented risk.
|
|
120
|
+
- `init` records the discovered `import-package`, so coverage measures the
|
|
121
|
+
package instead of a source directory path.
|
|
122
|
+
|
|
123
|
+
### Changed
|
|
124
|
+
|
|
125
|
+
- Tests' per-file-ignores grew `S105`, `S106`, `S108` (fixtures hold dummy
|
|
126
|
+
tokens and /tmp sockets) and now ignore the whole `PLR` family (a test factory
|
|
127
|
+
with seven keywords is a fixture, not a design smell).
|
|
128
|
+
|
|
129
|
+
## 0.1.5
|
|
130
|
+
|
|
131
|
+
### Changed
|
|
132
|
+
|
|
133
|
+
- Root discovery now reads the layout a `pyproject.toml` already declares -
|
|
134
|
+
pytest's `pythonpath` and `testpaths`, hatch's wheel `packages` - before
|
|
135
|
+
guessing from directories. Found adopting the baseline in `clawd-pet`, a
|
|
136
|
+
firmware host whose Python lives under `host/src` where directory scanning
|
|
137
|
+
sees nothing.
|
|
138
|
+
- The test per-file-ignores pattern is `**/tests/**`, so it also reaches nested
|
|
139
|
+
test roots such as `host/tests`.
|
|
140
|
+
- `D107` joined the ignore list: an `__init__` that stores its arguments has
|
|
141
|
+
nothing to add to the class docstring.
|
|
142
|
+
|
|
143
|
+
### Fixed
|
|
144
|
+
|
|
145
|
+
- The package now passes its own `init`-scaffolded configuration - it had been
|
|
146
|
+
gating itself with ruff's and mypy's defaults instead of the strict config it
|
|
147
|
+
ships, because no `ruff.toml` or `mypy.ini` existed in the repository.
|
|
148
|
+
|
|
149
|
+
## 0.1.4
|
|
150
|
+
|
|
151
|
+
### Fixed
|
|
152
|
+
|
|
153
|
+
- The gate's structural stage now honors a recorded baseline: when
|
|
154
|
+
`.codeality-py-baseline.json` exists it runs `codeality-py baseline check`
|
|
155
|
+
instead of the bare `check`, so recording debt can actually turn the gate
|
|
156
|
+
green. Found adopting the baseline in `atrium`, where 61 recorded findings
|
|
157
|
+
still failed the gate.
|
|
158
|
+
- Merging into an existing `[tool.ruff]` no longer drops the per-file test
|
|
159
|
+
ignores and the pydocstyle convention the standalone `ruff.toml` always
|
|
160
|
+
carried. A project that already had a ruff table was held to docstring rules
|
|
161
|
+
in its tests that a fresh project was not.
|
|
162
|
+
- The shipped `codeality-py.toml` now carries `coverage-threshold = 80`, which
|
|
163
|
+
the dogfooded config always had and the asset silently lacked.
|
|
164
|
+
|
|
165
|
+
## 0.1.3
|
|
166
|
+
|
|
167
|
+
### Changed
|
|
168
|
+
|
|
169
|
+
- Python 3.11 is now supported. `ast.TypeAlias` handling degrades gracefully: on
|
|
170
|
+
3.11 the PEP 695 syntax cannot parse at all, so nothing is lost. Found
|
|
171
|
+
adopting the baseline in `atrium`, whose `requires-python = ">=3.11"` made the
|
|
172
|
+
quality group unresolvable.
|
|
173
|
+
- `init` now discovers what it used to ask for: `source-roots` in
|
|
174
|
+
`codeality-py.toml`, `known_first_party` for deptry, and the import-linter
|
|
175
|
+
root package are filled from the project's real layout instead of `src` and
|
|
176
|
+
`CHANGE_ME` placeholders. The placeholder survives only when nothing is
|
|
177
|
+
discoverable.
|
|
178
|
+
|
|
179
|
+
## 0.1.2
|
|
180
|
+
|
|
181
|
+
### Fixed
|
|
182
|
+
|
|
183
|
+
- Baseline fingerprints no longer collapse several violations of one rule in one
|
|
184
|
+
file into a single entry, which let a fixed finding pay for a new one.
|
|
185
|
+
Identity is now decided per rule: a file-level rule (`BPY001`, `BPY004`)
|
|
186
|
+
identifies itself, a naming rule (`BPY002`, `BPY003`) identifies its symbol,
|
|
187
|
+
and everything else uses the offending line's content plus an occurrence
|
|
188
|
+
counter, so it survives edits elsewhere in the file. Found adopting the
|
|
189
|
+
baseline in DJCenterDeluxe, where 155 findings recorded as only 91 entries.
|
|
190
|
+
|
|
191
|
+
## 0.1.1
|
|
192
|
+
|
|
193
|
+
### Fixed
|
|
194
|
+
|
|
195
|
+
- Glob patterns now mean what they do everywhere else: `*` stops at a directory
|
|
196
|
+
separator and `**` crosses it. They were matched with `fnmatch`, whose `*`
|
|
197
|
+
crosses separators, so a role or override written for the scripts in a
|
|
198
|
+
repository root silently claimed every file in the tree. Found while adopting
|
|
199
|
+
the baseline in DJCenterDeluxe, where `entrypoint = ["*.py"]` matched all 106
|
|
200
|
+
files instead of the 40 at the root and hid 25 real `BPY002` findings.
|
|
201
|
+
|
|
202
|
+
## 0.1.0
|
|
203
|
+
|
|
204
|
+
Initial release.
|
|
205
|
+
|
|
206
|
+
### Added
|
|
207
|
+
|
|
208
|
+
- `codeality-py check`: six structural rules no ruff rule covers, over module
|
|
209
|
+
roles assigned before any file is parsed.
|
|
210
|
+
- `BPY000` parse-error, `BPY001` one-primary-unit, `BPY002` file-matches-unit,
|
|
211
|
+
`BPY003` no-grab-bag-names, `BPY004` max-file-lines, `BPY005`
|
|
212
|
+
barrel-only-init, `BPY006` no-inline-sql.
|
|
213
|
+
- Text and versioned JSON output, four exit codes, inline and configured
|
|
214
|
+
suppressions. The command never writes.
|
|
215
|
+
- `codeality-py init`: scaffolds ruff, mypy, deptry, pytest, coverage and CI
|
|
216
|
+
configuration by merging into what a project already has. A project that
|
|
217
|
+
configures ruff gets its `[tool.ruff]` extended, never a `ruff.toml` that
|
|
218
|
+
would silently take precedence over it.
|
|
219
|
+
- `codeality-py gate`: runs the whole quality chain. A required tool that is not
|
|
220
|
+
installed fails the gate rather than being skipped.
|
|
221
|
+
- `codeality-py baseline update|check`: records migration debt by content
|
|
222
|
+
fingerprint, reports new, known and resolved findings.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) BusiRocket
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: syntopica-codeality-py
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Structural linter and config scaffolder for Python: atomic files, placement, size caps, no inline SQL
|
|
5
|
+
Project-URL: Homepage, https://github.com/syntopica/codeality
|
|
6
|
+
Project-URL: Issues, https://github.com/syntopica/codeality/issues
|
|
7
|
+
Author: Cristian Deluxe
|
|
8
|
+
License: MIT License
|
|
9
|
+
|
|
10
|
+
Copyright (c) BusiRocket
|
|
11
|
+
|
|
12
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
13
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
14
|
+
in the Software without restriction, including without limitation the rights
|
|
15
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
16
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
17
|
+
furnished to do so, subject to the following conditions:
|
|
18
|
+
|
|
19
|
+
The above copyright notice and this permission notice shall be included in all
|
|
20
|
+
copies or substantial portions of the Software.
|
|
21
|
+
|
|
22
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
23
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
24
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
25
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
26
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
27
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
28
|
+
SOFTWARE.
|
|
29
|
+
License-File: LICENSE
|
|
30
|
+
Keywords: architecture,ast,code-quality,linter
|
|
31
|
+
Classifier: Development Status :: 3 - Alpha
|
|
32
|
+
Classifier: Intended Audience :: Developers
|
|
33
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
34
|
+
Classifier: Programming Language :: Python :: 3
|
|
35
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
36
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
37
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
38
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
39
|
+
Requires-Python: >=3.11
|
|
40
|
+
Requires-Dist: click<9,>=8.1
|
|
41
|
+
Requires-Dist: tomlkit<1,>=0.13
|
|
42
|
+
Description-Content-Type: text/markdown
|
|
43
|
+
|
|
44
|
+
# codeality-py
|
|
45
|
+
|
|
46
|
+
Structural linter and config scaffolder for Python: atomic files, placement,
|
|
47
|
+
size caps, no inline SQL. Brings the same discipline as
|
|
48
|
+
`@syntopica/eslint-config` and `cargo-baseline` to Python projects.
|
|
49
|
+
|
|
50
|
+
- **Design spec:**
|
|
51
|
+
[docs/superpowers/specs/2026-08-31-python-baseline-design.md](https://github.com/syntopica/codeality/blob/main/docs/superpowers/specs/2026-08-31-python-baseline-design.md).
|
|
52
|
+
|
|
53
|
+
## Install
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
uv add --dev syntopica-codeality-py
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Usage
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
codeality-py init [--check|--apply|--force] # scaffold ruff, mypy, deptry,
|
|
63
|
+
# pytest, coverage and CI config
|
|
64
|
+
codeality-py check [PATH...] # run the structural rules
|
|
65
|
+
codeality-py gate # run the whole quality chain
|
|
66
|
+
codeality-py baseline create|update|check # track migration debt
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
`init` never overwrites: it merges into existing configuration, or reports a
|
|
70
|
+
conflict. `check` never writes. `gate` fails when a required tool is absent
|
|
71
|
+
rather than skipping it.
|
|
72
|
+
|
|
73
|
+
## Rules
|
|
74
|
+
|
|
75
|
+
| Code | Rule | Enforces |
|
|
76
|
+
| -------- | ------------------- | -------------------------------------------------------------- |
|
|
77
|
+
| `BPY000` | `parse-error` | A file that fails to parse is a finding, never a silent skip. |
|
|
78
|
+
| `BPY001` | `one-primary-unit` | Exactly one primary declaration per ordinary module. |
|
|
79
|
+
| `BPY002` | `file-matches-unit` | File name is the snake_case of its primary declaration. |
|
|
80
|
+
| `BPY003` | `no-grab-bag-names` | No `utils`, `helpers`, `misc` or `common` in any path segment. |
|
|
81
|
+
| `BPY004` | `max-file-lines` | Code-line cap per file; tests get their own, looser cap. |
|
|
82
|
+
| `BPY005` | `barrel-only-init` | `__init__.py` holds imports, `__all__` and nothing else. |
|
|
83
|
+
| `BPY006` | `no-inline-sql` | SQL lives in resource files, not in string literals. |
|
|
84
|
+
|
|
85
|
+
## Exit codes
|
|
86
|
+
|
|
87
|
+
| Code | Meaning |
|
|
88
|
+
| ---- | --------------------------------------------------------------- |
|
|
89
|
+
| 0 | All blocking checks passed. |
|
|
90
|
+
| 1 | Policy findings. |
|
|
91
|
+
| 2 | Invalid usage or invalid configuration. |
|
|
92
|
+
| 3 | Infrastructure failure: a required tool is missing or unusable. |
|
|
93
|
+
|
|
94
|
+
## License
|
|
95
|
+
|
|
96
|
+
MIT
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# codeality-py
|
|
2
|
+
|
|
3
|
+
Structural linter and config scaffolder for Python: atomic files, placement,
|
|
4
|
+
size caps, no inline SQL. Brings the same discipline as
|
|
5
|
+
`@syntopica/eslint-config` and `cargo-baseline` to Python projects.
|
|
6
|
+
|
|
7
|
+
- **Design spec:**
|
|
8
|
+
[docs/superpowers/specs/2026-08-31-python-baseline-design.md](https://github.com/syntopica/codeality/blob/main/docs/superpowers/specs/2026-08-31-python-baseline-design.md).
|
|
9
|
+
|
|
10
|
+
## Install
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
uv add --dev syntopica-codeality-py
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Usage
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
codeality-py init [--check|--apply|--force] # scaffold ruff, mypy, deptry,
|
|
20
|
+
# pytest, coverage and CI config
|
|
21
|
+
codeality-py check [PATH...] # run the structural rules
|
|
22
|
+
codeality-py gate # run the whole quality chain
|
|
23
|
+
codeality-py baseline create|update|check # track migration debt
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
`init` never overwrites: it merges into existing configuration, or reports a
|
|
27
|
+
conflict. `check` never writes. `gate` fails when a required tool is absent
|
|
28
|
+
rather than skipping it.
|
|
29
|
+
|
|
30
|
+
## Rules
|
|
31
|
+
|
|
32
|
+
| Code | Rule | Enforces |
|
|
33
|
+
| -------- | ------------------- | -------------------------------------------------------------- |
|
|
34
|
+
| `BPY000` | `parse-error` | A file that fails to parse is a finding, never a silent skip. |
|
|
35
|
+
| `BPY001` | `one-primary-unit` | Exactly one primary declaration per ordinary module. |
|
|
36
|
+
| `BPY002` | `file-matches-unit` | File name is the snake_case of its primary declaration. |
|
|
37
|
+
| `BPY003` | `no-grab-bag-names` | No `utils`, `helpers`, `misc` or `common` in any path segment. |
|
|
38
|
+
| `BPY004` | `max-file-lines` | Code-line cap per file; tests get their own, looser cap. |
|
|
39
|
+
| `BPY005` | `barrel-only-init` | `__init__.py` holds imports, `__all__` and nothing else. |
|
|
40
|
+
| `BPY006` | `no-inline-sql` | SQL lives in resource files, not in string literals. |
|
|
41
|
+
|
|
42
|
+
## Exit codes
|
|
43
|
+
|
|
44
|
+
| Code | Meaning |
|
|
45
|
+
| ---- | --------------------------------------------------------------- |
|
|
46
|
+
| 0 | All blocking checks passed. |
|
|
47
|
+
| 1 | Policy findings. |
|
|
48
|
+
| 2 | Invalid usage or invalid configuration. |
|
|
49
|
+
| 3 | Infrastructure failure: a required tool is missing or unusable. |
|
|
50
|
+
|
|
51
|
+
## License
|
|
52
|
+
|
|
53
|
+
MIT
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# codeality-py configuration - https://github.com/syntopica/codeality
|
|
2
|
+
schema-version = 1
|
|
3
|
+
source-roots = ["src"]
|
|
4
|
+
test-roots = ["tests"]
|
|
5
|
+
import-package = "codeality_py"
|
|
6
|
+
coverage-threshold = 80
|
|
7
|
+
|
|
8
|
+
[limits]
|
|
9
|
+
max-file-lines = 150
|
|
10
|
+
test-max-file-lines = 300
|
|
11
|
+
|
|
12
|
+
[roles]
|
|
13
|
+
data = [
|
|
14
|
+
"src/codeality_py/traversal/default_excludes.py",
|
|
15
|
+
"src/codeality_py/rules/grab_bag_names.py",
|
|
16
|
+
"src/codeality_py/roles/test_file_patterns.py",
|
|
17
|
+
"src/codeality_py/config/default_generated_globs.py",
|
|
18
|
+
"src/codeality_py/engine/rule_registry.py",
|
|
19
|
+
"src/codeality_py/init/managed_asset_files.py",
|
|
20
|
+
"src/codeality_py/commands/project_option.py",
|
|
21
|
+
]
|
|
22
|
+
entrypoint = ["src/codeality_py/cli.py"]
|
|
23
|
+
|
|
24
|
+
[[overrides]]
|
|
25
|
+
paths = ["tests/rules/test_no_inline_sql.py", "tests/baseline/test_classify_findings.py"]
|
|
26
|
+
disable = ["BPY006"]
|
|
27
|
+
reason = "Fixtures for the SQL detector and for fingerprinting are queries by definition"
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling>=1.27,<2"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "syntopica-codeality-py"
|
|
7
|
+
version = "0.2.0"
|
|
8
|
+
description = "Structural linter and config scaffolder for Python: atomic files, placement, size caps, no inline SQL"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.11"
|
|
11
|
+
license = { file = "LICENSE" }
|
|
12
|
+
authors = [{ name = "Cristian Deluxe" }]
|
|
13
|
+
keywords = ["linter", "code-quality", "architecture", "ast"]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Development Status :: 3 - Alpha",
|
|
16
|
+
"Intended Audience :: Developers",
|
|
17
|
+
"License :: OSI Approved :: MIT License",
|
|
18
|
+
"Programming Language :: Python :: 3",
|
|
19
|
+
"Programming Language :: Python :: 3.11",
|
|
20
|
+
"Programming Language :: Python :: 3.12",
|
|
21
|
+
"Programming Language :: Python :: 3.13",
|
|
22
|
+
"Topic :: Software Development :: Quality Assurance",
|
|
23
|
+
]
|
|
24
|
+
dependencies = ["click>=8.1,<9", "tomlkit>=0.13,<1"]
|
|
25
|
+
|
|
26
|
+
[project.scripts]
|
|
27
|
+
codeality-py = "codeality_py.cli:cli"
|
|
28
|
+
|
|
29
|
+
[project.urls]
|
|
30
|
+
Homepage = "https://github.com/syntopica/codeality"
|
|
31
|
+
Issues = "https://github.com/syntopica/codeality/issues"
|
|
32
|
+
|
|
33
|
+
[dependency-groups]
|
|
34
|
+
dev = [
|
|
35
|
+
"deptry>=0.20,<1",
|
|
36
|
+
"mypy>=1.11,<2",
|
|
37
|
+
"pip-audit>=2.7,<3",
|
|
38
|
+
"pytest>=8,<10",
|
|
39
|
+
"pytest-cov>=5,<8",
|
|
40
|
+
"ruff>=0.15,<1",
|
|
41
|
+
]
|
|
42
|
+
|
|
43
|
+
[tool.hatch.build.targets.wheel]
|
|
44
|
+
packages = ["src/codeality_py"]
|
|
45
|
+
|
|
46
|
+
[tool.deptry]
|
|
47
|
+
known_first_party = ["codeality_py"]
|
|
48
|
+
|
|
49
|
+
[tool.pytest.ini_options]
|
|
50
|
+
addopts = "-ra"
|
|
51
|
+
testpaths = ["tests"]
|
|
52
|
+
|
|
53
|
+
[tool.coverage.run]
|
|
54
|
+
branch = true
|
|
55
|
+
|
|
56
|
+
[tool.coverage.report]
|
|
57
|
+
show_missing = true
|
|
58
|
+
skip_covered = true
|
|
59
|
+
fail_under = 80
|
|
60
|
+
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Managed by codeality-py. Rules are listed explicitly: ALL expands silently on
|
|
2
|
+
# every ruff upgrade, turning a dependency bump into a lint failure.
|
|
3
|
+
line-length = 100
|
|
4
|
+
target-version = "py311"
|
|
5
|
+
|
|
6
|
+
[lint]
|
|
7
|
+
select = [
|
|
8
|
+
"E", # pycodestyle errors
|
|
9
|
+
"W", # pycodestyle warnings
|
|
10
|
+
"F", # pyflakes
|
|
11
|
+
"I", # import sorting
|
|
12
|
+
"N", # pep8-naming
|
|
13
|
+
"UP", # pyupgrade
|
|
14
|
+
"B", # bugbear
|
|
15
|
+
"A", # builtin shadowing
|
|
16
|
+
"C4", # comprehensions
|
|
17
|
+
"DTZ", # naive datetimes
|
|
18
|
+
"T20", # print in library code
|
|
19
|
+
"SIM", # simplifiable code
|
|
20
|
+
"RET", # return control flow
|
|
21
|
+
"ARG", # unused arguments
|
|
22
|
+
"PTH", # pathlib over os.path
|
|
23
|
+
"ERA", # commented-out code
|
|
24
|
+
"PL", # pylint: complexity, branches, statements
|
|
25
|
+
"RUF", # ruff-specific
|
|
26
|
+
"D", # docstrings; replaces interrogate
|
|
27
|
+
# bandit, curated: the full S set is intentionally noisy in tests and in
|
|
28
|
+
# subprocess-heavy code.
|
|
29
|
+
"S102", "S103", "S104", "S105", "S106", "S107", "S108",
|
|
30
|
+
"S301", "S302", "S303", "S304", "S305", "S306",
|
|
31
|
+
"S324", "S501", "S506", "S508", "S509",
|
|
32
|
+
"S608", "S609", "S612",
|
|
33
|
+
]
|
|
34
|
+
ignore = [
|
|
35
|
+
# Conflicts with the formatter; keeping these on fights ruff format forever.
|
|
36
|
+
"E501", "W191", "E111", "E114", "E117", "D206", "D300", "COM812", "ISC001",
|
|
37
|
+
"D203", # incompatible with D211
|
|
38
|
+
"D107", # an __init__ that stores its arguments has nothing to add to the class docstring
|
|
39
|
+
"D213", # incompatible with D212
|
|
40
|
+
]
|
|
41
|
+
|
|
42
|
+
[lint.per-file-ignores]
|
|
43
|
+
# **/ so the pattern also reaches nested test roots such as host/tests.
|
|
44
|
+
"**/tests/**" = ["D", "S101", "ARG", "PLR2004"]
|
|
45
|
+
"**/conftest.py" = ["D"]
|
|
46
|
+
|
|
47
|
+
[lint.pydocstyle]
|
|
48
|
+
convention = "google"
|
|
49
|
+
|
|
50
|
+
[format]
|
|
51
|
+
docstring-code-format = true
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Structural linter and config scaffolder for Python projects."""
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
name: Quality
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
gate:
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
strategy:
|
|
15
|
+
fail-fast: false
|
|
16
|
+
matrix:
|
|
17
|
+
python-version: ['3.11', '3.13']
|
|
18
|
+
steps:
|
|
19
|
+
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
|
|
20
|
+
|
|
21
|
+
- name: Install uv
|
|
22
|
+
uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0
|
|
23
|
+
with:
|
|
24
|
+
enable-cache: true
|
|
25
|
+
|
|
26
|
+
- name: Check the lockfile is current
|
|
27
|
+
run: uv lock --check
|
|
28
|
+
|
|
29
|
+
# Every extra and every group: the gate audits and tests the environment
|
|
30
|
+
# it runs in, and a group-only install leaves out the extras the tests
|
|
31
|
+
# import.
|
|
32
|
+
- name: Install from the lockfile
|
|
33
|
+
run: uv sync --locked --all-extras --all-groups
|
|
34
|
+
env:
|
|
35
|
+
UV_PYTHON: ${{ matrix.python-version }}
|
|
36
|
+
|
|
37
|
+
- name: Run the quality gate
|
|
38
|
+
run: uv run codeality-py gate --json
|
|
39
|
+
|
|
40
|
+
- name: Type-check with pyrefly, without blocking
|
|
41
|
+
continue-on-error: true
|
|
42
|
+
run: |
|
|
43
|
+
uv run --with pyrefly pyrefly check --output-format json > pyrefly.json || true
|
|
44
|
+
|
|
45
|
+
- name: Upload the pyrefly shadow report
|
|
46
|
+
if: always()
|
|
47
|
+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
|
48
|
+
with:
|
|
49
|
+
name: pyrefly-shadow-${{ matrix.python-version }}
|
|
50
|
+
path: pyrefly.json
|
|
51
|
+
retention-days: 90
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# codeality-py configuration - https://github.com/syntopica/codeality
|
|
2
|
+
schema-version = 1
|
|
3
|
+
source-roots = ["src"]
|
|
4
|
+
test-roots = ["tests"]
|
|
5
|
+
respect-gitignore = true
|
|
6
|
+
coverage-threshold = 80
|
|
7
|
+
|
|
8
|
+
[limits]
|
|
9
|
+
max-file-lines = 150
|
|
10
|
+
test-max-file-lines = 300
|
|
11
|
+
|
|
12
|
+
# A role states what a file is. Prefer a role over a suppression: it explains
|
|
13
|
+
# the file instead of silencing an alarm.
|
|
14
|
+
[roles]
|
|
15
|
+
data = []
|
|
16
|
+
registry = []
|
|
17
|
+
entrypoint = []
|
|
18
|
+
generated = []
|
|
19
|
+
namespace-init = []
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
; Managed by codeality-py, scaffolded only with --profile app. Declare the real
|
|
2
|
+
; layers of the project; an empty contract enforces nothing.
|
|
3
|
+
[importlinter]
|
|
4
|
+
root_package = CHANGE_ME
|
|
5
|
+
|
|
6
|
+
[importlinter:contract:layers]
|
|
7
|
+
name = Layered architecture
|
|
8
|
+
type = layers
|
|
9
|
+
layers =
|
|
10
|
+
cli
|
|
11
|
+
services
|
|
12
|
+
domain
|