Skip to content

feat(pyscn): integrate pyscn code quality gate into CI - #23

Merged
dlstadther merged 3 commits into
mainfrom
dlstadther/pyscn
Sep 11, 2026
Merged

feat(pyscn): integrate pyscn code quality gate into CI#23
dlstadther merged 3 commits into
mainfrom
dlstadther/pyscn

Conversation

@dlstadther

@dlstadther dlstadther commented Sep 11, 2026

Copy link
Copy Markdown
Owner

Summary

  • Adds pyscn (CFG-based dead code detection, cyclomatic complexity, clone detection, coupling/dependency analysis) as a dev dependency
  • Wires pyscn check . into the make lint chain (new lint-quality target), the pre-commit hooks (local hook, same language: system pattern as pyrefly), and a new "Quality check with pyscn" step in the CI lint job
  • Configures pyscn via [tool.pyscn.*] sections in pyproject.toml (matching this repo's convention of keeping tool config there, rather than a dedicated .pyscn.toml): full output/complexity sections, dead_code/cbo trimmed to their enabled toggle, architecture disabled (flat single-package library, not a layered app). clones/analysis are left on pyscn's built-in defaults since neither has an enabled toggle in its schema. Links to the full config reference (https://docs.codescan.dev/configuration/reference/) for anyone tuning it further.
  • Adds .pyscn/ (report output dir) to .gitignore
  • Ran pyscn analyze . manually once (full report, not committed): health score 88/100 (B) — no complexity, dead code, duplication, or coupling issues; only a minor cohesion (LCOM) note on 2 classes

Test plan

  • make lint-quality passes locally
  • make format / make lint-python / make lint-sql / make type / make test all pass
  • uv lock / uv sync --all-extras succeed with the new dependency
  • CI tests.yml lint job runs the new step
  • Confirmed pyscn picks up [tool.pyscn.*] from pyproject.toml and reproduces the same 88/100 health score as before the config existed

🤖 Generated with Claude Code

https://claude.ai/code/session_01EEpPSmBaxSif7DbNLcFXZM

Adds pyscn (complexity, dead code, clone, and circular-dependency
checks) as a dev dependency, wired into the pre-commit hooks, the
make lint / nox lint targets, and the CI lint job. Uses pyscn's
built-in "check" defaults (max complexity 10, dead-code and
circular-dependency failures, clone warnings) rather than a custom
.pyscn.toml.

Claude-Session: https://claude.ai/code/session_01EEpPSmBaxSif7DbNLcFXZM

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

@dlstadther dlstadther left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's go ahead and add the toml config file. Start it with reasonable defaults. I want this to be a starting place for configurability.

Adds a full pyscn config file (generated via `pyscn init`) as a
starting point for tuning quality-gate behavior later. Disables the
generated example layered-architecture rules by default since this
project is a flat single-package library, not a layered app, so
they'd otherwise misclassify modules and score false violations.
Everything else keeps pyscn's own defaults, which reproduce the
same health score as running with no config file at all.

Addresses PR review feedback.

Claude-Session: https://claude.ai/code/session_01EEpPSmBaxSif7DbNLcFXZM

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@dlstadther

Copy link
Copy Markdown
Owner Author

Added .pyscn.toml in 0f017c5 (generated via pyscn init), so it's now the starting point for tuning thresholds going forward.

One call I made: the generated file ships example layered-architecture rules (presentation/application/domain/infrastructure package-name matching). This repo is a flat single package (src/sample/*), so I disabled that section ([architecture] enabled = false) rather than leave it live — with it on, it misclassified modules and dropped the architecture score to 71% for no real reason. Left the layer/rule definitions in as commented-out examples for when the project grows into distinct layers.

Everything else keeps pyscn's own defaults, and confirmed the health score (88/100, B) is identical with the config file present vs. absent.

Comment thread .pyscn.toml Outdated
Comment thread .pyscn.toml Outdated
Comment thread .pyscn.toml Outdated
# This file configures all analysis features of pyscn
# Place this file in your project root to customize analysis behavior

# =============================================================================

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll group a few update requests into a single comment here:

  • Keep the "output" section
  • Keep the "complexity" section
  • Reduce the "dead_code", "clones", "cbo", and "analysis" sections to just their "enabled" attribute.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 45fa4c7, with one caveat: kept output and complexity in full, and reduced dead_code/cbo to just enabled = true as asked.

For clones and analysis, though — pyscn's config schema doesn't actually define an enabled field on either (confirmed against https://docs.codescan.dev/configuration/reference/; clones starts straight into fragment-selection params like min_lines, and analysis is just file-discovery patterns). So there's no toggle to reduce those sections to. I omitted both sections entirely instead, letting pyscn's own defaults apply — functionally the closest equivalent to "just the enabled attribute," but flagging it in case you wanted something else here (e.g. keeping one of them in full, or dropping min_severity/exclude patterns from dead_code/analysis instead). Leaving this thread open in case that's not what you meant.

Comment thread .pyscn.toml Outdated
Comment thread .pyscn.toml Outdated
Replaces the standalone .pyscn.toml with [tool.pyscn.*] sections in
pyproject.toml, matching this repo's convention of keeping tool
config there (ruff, pytest, pyrefly, interrogate, sqlfluff, etc.)
instead of one-off dotfiles.

Trims the generated boilerplate down to what's actually meaningful
here: full "output" and "complexity" sections (kept per review
request), "dead_code" and "cbo" reduced to their enabled toggle
(pyscn's only other options there are fine-tuning, not on/off), and
"architecture" reduced to enabled=false with a one-line rationale.
Drops the commented-out example-configurations block and the
generated layered-architecture layers/rules entirely rather than
leaving them commented out.

"clones" and "analysis" are omitted rather than reduced to an
"enabled" toggle, since pyscn's config schema doesn't define such a
field for either section (confirmed against
https://docs.codescan.dev/configuration/reference/) - they use
pyscn's built-in defaults for now.

Verified `pyscn analyze .` and `pyscn check .` behave identically
before/after (same 88/100 health score) by reading config from
pyproject.toml instead of a dedicated .pyscn.toml.

Addresses PR review feedback.

Claude-Session: https://claude.ai/code/session_01EEpPSmBaxSif7DbNLcFXZM

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@dlstadther
dlstadther merged commit 31b0e3d into main Sep 11, 2026
10 checks passed
@dlstadther
dlstadther deleted the dlstadther/pyscn branch September 11, 2026 23:56
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.

1 participant