Changelog¶
All notable changes to complexipy are documented here, newest first. Each release section links to its GitHub release notes for the full details.
Unreleased¶
[7.0.1] - 2026-08-12¶
Changed¶
- The release pipeline now retries artifact uploads with pinned workflow versions and only notifies downstream repositories on tag releases, keeping non-tag pushes silent.
- Pinned maturin version in the release workflow to avoid GitHub API rate limits when resolving the latest version inside Docker build containers.
Fixed¶
- Snapshot entries for analyzed files are updated in place instead of being moved to the end of the file: partial runs (e.g. pre-commit hooks analyzing only staged files) no longer reorder the snapshot, so the snapshot stays byte-identical across commits that do not change complexity. (#226)
See the release notes for the full details.
[7.0.0] - 2026-08-10¶
Migration
The deprecated --output-json, --output-csv, --output-gitlab,
--output-sarif, and --ratchet flags and their TOML keys were
removed; use --output-format and --diff instead. See the
migration guide
for each removed flag and key with its replacement.
Added¶
--suggest-refactorsis now a clippy-style lint system: stable rule IDs (C001–C005, C007, C011), category and applicability metadata,path:line:colanchors with caret spans, verbatim suggestion rendering, and a documentation link per rule. (#209)- Refactor-plan findings are included in JSON, SARIF, and GitLab exports
when
--suggest-refactorsis passed; the SARIF rule catalog is built dynamically from the plans encountered. (#209) compute_diff,has_regressions,DiffEntry, andDiffStatusare now part of the public Python API, so CI tools can consume diff results as objects instead of parsing terminal output;DiffStatusprovides named constants such asDiffStatus.REGRESSED. (#210)collect_removable_ignored_locations()andRemovableIgnoreare exported from the Python API. Every run now reports ignore comments that are no longer necessary (path:line function=X complexity=N <comment>) when the suppressed function is back under the allowed limit — the exit code is unaffected, the report is suppressed under--quiet, and it works under--plain. (#213)--stagedflag for git-index comparison — answers "what complexity am I about to commit?" instead of only what changed in the working tree;--stagedalone defaults the baseline toHEADand enforces, while--diff <ref> --stagedenforces against the ref. (#218)[tool.complexipy.diff]TOML section so the comparison policy lives in the repository config:branch = "main"makes a plaincomplexipy .run behave like--diff main(enforcement included),staged = trueenables staged comparison by default, andbranch = ""opts out. CLI flags take precedence over the section. (#219)- Refactor reductions are now measured instead of estimated: for every
machine-applicable suggestion (C002, C007) the replacement is spliced
into the source, re-parsed, and re-scored, so
estimated_reductionandestimated_complexity_afterreport the literal delta of applying the suggestion — and ranking, overlap resolution, and the noise filter all operate on measured values. The newreduction_is_measuredflag onRefactorPlanseparates measured plans from help-only formula estimates, which the CLI renders with a~qualifier (Estimated reduction: ~-2) while measured plans render plain (Reduction: -2). Guard suggestions are now faithful splices for loops with statements before or after the if-chain and for multi-line loop headers; measurement failures fall back to the formula estimate — never a panic, never a fabricated number. (#225)
Changed¶
- Refactor-plan reduction estimates are now honest: the reduction math was
rewritten and validated against measured before/after complexity, C004 no
longer suggests splitting
matchstatements, C006 was deleted because its gate could never fire, and C011 now fires ontry→with→trychains. Overlapping plans are deduped against every overlap and capped at 5, reporting dropped ones as "... and N more suggestions". (#209) - Condition extraction in the refactor rules now tracks bracket depth,
string literals, and walrus
:=instead of a naiverfind(':'). (#209) file_complexity()now returns cwd-relative paths (matchinggit diff --name-only), and nested invocations resolve git paths via agit ls-filesbasename lookup — without this, diffing per-file results silently marked every function as NEW. (#210)- Community standards files were added:
CODE_OF_CONDUCT.md,CONTRIBUTING.md,SECURITY.md, issue templates, and a pull request template. (#201)
Fixed¶
- Snapshot updates now merge with the existing snapshot instead of replacing it: only the files analyzed in a run are touched, so partial runs (e.g. pre-commit hooks analyzing only staged files) no longer erase the baseline for unanalyzed files. (#215)
- The docs footer now renders its links as styled links instead of raw markdown text, on both the English and Spanish landing pages. (#216)
Removed¶
RefactorPlan.steps— replaced by the concretesuggestion/helpfields on the plan. (#209)CodeSnippetfrom the public API;CodeSuggestionis exported in its place. (#209)--output-json/-j,--output-csv/-c,--output-gitlab, and--output-sarif/-sr— use--output-formatinstead. (#221)--ratchet/-R—--diffenforces the threshold by default. (#221)- TOML keys
output-json,output-csv,output-gitlab,output-sarif, flatstaged, flatratchet, and the undocumenteddetails = "low"alias. (#221)
These removals land in 7.0.0. See the migration guide for each removed flag and key with its replacement.
See the release notes for the full details.
[6.2.0] - 2026-07-23¶
Added¶
--excludeand--output-formatnow accept comma-separated values (--exclude tests/**,src/**), avoiding shell expansion issues. (#199)
Fixed¶
- Output now shows the correct relative path from the current working directory when analyzing a single file or a directory. (#198)
--output-sarifhelp text now carries a deprecation notice, clarifying that SARIF output is moving to a different mechanism. (#199)
Changed¶
- Decomposed the monolithic 316-line
main()function into a clean orchestrator (~80 lines) with extracted business logic in domain-specificutils/modules (config.py,paths.py,ignored.py). (#199) - Introduced
RunConfig,ExitReport, andSnapshotEvaluationdataclasses, replacing mutable accumulators and positional tuple unpacking. (#199) - Eliminated all
global consoledeclarations — theconsoleinstance is constructed once and passed explicitly. (#199) - Refactored
get_arguments_valuefrom a 20-parameter function returning a 15-element tuple to a dict-based approach. (#199) - Added 30 new tests covering config resolution and snapshot evaluation logic. (#199)
See the release notes for the full details.
[6.1.0] - 2026-07-21¶
Fixed¶
- Fixed git path resolution when running
--difffrom a nested subdirectory inside a repository, which previously caused "not a git repository" errors. (#196) - Fixed ruff lint configuration to use a glob pattern instead of a directory exclusion for test files. (#196)
Changed¶
- Simplified the diff CLI —
--diffnow always enforces--max-complexity-allowed, while--diff-onlyprovides the visual-only comparison.--ratchetis deprecated in favour of this model. (#196) - Integrated diff output into the main analysis flow instead of producing it as a separate post-processing step. (#196)
- Removed the redundant "Failed functions" output section — failed functions are now shown inline in the per-file summary. (#196)
- Added
AGENTS.mdfor AI agent context. - Added a CI workflow that notifies downstream repositories on new releases. (#197)
See the release notes for the full details.
[6.0.1] - 2026-07-03¶
Fixed¶
- Normalized Windows paths for wax glob compatibility in the exclude handling. (#194)
See the release notes for the full details.
[6.0.0] - 2026-06-26¶
Migration
This release brings the cognitive complexity algorithm into full
conformance with the SonarSource white paper (v1.7). Scores change for
files using match, try/except, with, comprehensions, lambdas,
recursion, or nested ternaries — in most cases they increase. Re-run
complexipy after upgrading and review the new scores; if you use
--max-complexity / --failed in CI you will likely need to raise
thresholds. See the migration guide
for upgrade guidance.
Fixed¶
matchstatements now apply a structural + nesting increment per the paper, instead of being scored as 0. (#192)try/else/finallyblocks are now collected at the current nesting level instead of+1, matching the paper's rule. (#192)excepthandlers now charge1 + nesting_levelinstead of a flat+1. (#192)withblocks no longer incorrectly raise the nesting level. (#192)- Direct recursion now emits
+1for each self-call via a scope-awareRecursionFinder, correctly skipping nested function/class definitions and lambdas. (#192) - Lambda expressions are now included in boolean-op counting, recursing
into the body at
nesting_level + 1. (#192) - Comprehensions (
ListComp,SetComp,DictComp,Generator) now charge1 + nesting_levelper generator and+1periffilter. (#192) - Nested ternaries now recurse at
nesting_level + 1, so inner ternaries receive the correct nesting increment. (#192) for/whileelseclauses are now collected at the loop's own nesting level, not+1. (#192)- Bare expression statements now count boolean ops (e.g.
foo(a and b)). (#192) - The
foriterable now counts boolean ops, for parity withwhile. (#192)
Changed¶
- Extracted all path orchestration (file I/O, directory traversal, URL
cloning) from
cognitive_complexity.rsinto a newsrc/runner.rsmodule, gated#[cfg(feature = "python")], which also resolves a pre-existing wasm build failure. (#192) - Extracted
push_line,absorb,absorb_with_regions,finalize_region,count_line_bool_ops,loop_complexity,is_ignored, andanalyze_functionhelpers to eliminate the repeated fold/push pattern across all statement arms. (#192) - Unified structurally identical
Stmt::ForandStmt::Whilehandling into a singleloop_complexitycall. (#192) - Collapsed 7 near-identical statement arms through
count_line_bool_ops. (#192) - Derived
DefaultonComplexityRegionandRegionKind. (#192) - Eliminated
merge_childand its internalchild.regions.clone(). (#192) - Hardened the Windows release unit-test job against transient Cargo HTTP/2 framing failures. (#189)
See the release notes for the full details.
[5.6.1] - 2026-06-16¶
Fixed¶
- Fixed a panic in
extract_comment_markerwhen a multi-byte UTF-8 character (em-dash, emoji, accented letters, CJK) straddles byte offset 16 of a comment, which previously aborted analysis of the entire directory. Error-prone byte-slicing was replaced with regex-based matching. (#187)
Removed¶
- Removed the unreliable
release-plz.ymlauto-release workflow and its supporting files (CHANGELOG.md,cliff.toml). Manual releases viarelease.yml(tag → build → test → publish) are now the standard path. (#188)
See the release notes for the full details.
[5.6.0] - 2026-06-14¶
Added¶
--no-ignoreflag to disregard# complexipy: ignoreand# noqa: complexipycomments. (#182)--report-ignoredflag to list all suppressed functions, with optional JSON export tocomplexipy-ignored.json. (#182)IgnoredLocationtype andcollect_all_ignored_locations()to the Python API. (#182)
Fixed¶
- Fixed diff mode showing all files as NEW on Windows. (#177)
Changed¶
- Migrated pyo3 to 0.29 and updated CI runners. (#185)
- Added musllinux_1_2 wheel builds for Alpine Linux support. (#180)
See the release notes for the full details.
[5.5.0] - 2026-05-22¶
Added¶
- Deterministic refactor plans: a new algorithm generates actionable, deterministic suggestions to reduce cognitive complexity. Plans are displayed in the rich CLI output and included in JSON output.
- Recursive exclude globs: exclude patterns now support
**(e.g.tests/**). The glob engine was replaced withwaxfor correct recursive matching relative to the caller's working directory.
Fixed¶
- Fixed unbounded growth of target-set entries in the cache that could degrade performance on large projects.
Changed¶
- Output internals now use typed
FunctionRow/FileEntrydataclasses instead of untypedDictstructures, extracted intocomplexipy/utils/dataclasses.py. - Docs deploys now trigger only on release events, not on every push.
See the release notes for the full details.
[5.4.1] - 2026-05-05¶
Fixed¶
- Stabilized snapshot output by omitting transient line-level fields from Python-facing serialized Rust structures.
- Moved shared output constants into
complexipy.utils.constantsso output filenames, legacy CLI flags, and legacy TOML keys are defined in one place. - Clarified deprecated output flag messaging for
--output-csv,--output-json, and--output-gitlabto point users at--output-format.
Changed¶
- Updated CI so pull requests run a faster quick-test matrix, while full wheel builds, source distribution builds, and full platform test jobs run for tags or manual workflow dispatches.
- Enabled uv dependency caching in CI jobs.
- Updated README and docs to match the current Python API return types and the current JSON array snapshot format.
See the release notes for the full details.
[5.4.0] - 2026-04-25¶
Removed¶
- Removed comprehension complexity scoring — rolls back the
ListComp/SetComp/Generator/DictCompAST node handling fromcount_bool_ops()and thecount_comprehension_complexity()helper added in v5.3.0. (#166)
Fixed¶
- Fixed feature gating for WASM builds and included version metadata. (#164)
See the release notes for the full details.
[5.3.0] - 2026-04-16¶
Added¶
--ratchetflag — CI fails only when complexity increases past the threshold; regressions are blocked, improvements always pass. (#159)--plainflag — machine-readable plain-text output for scripting/piping. (#158)--top Nflag — display the N most complex functions, globally sorted across all files. (#157)--check-script/--script-strictflags — analyse module-level (script) complexity in addition to functions. (#156)- Unified output destinations — consistent
--output-*routing across all report formats. (#155) - GitLab Code Quality report via
--output-gitlab. (#153) - SARIF 2.1.0 output via
--output-sariffor IDE and GitHub Advanced Security integration. (#141) - Git diff analysis —
--diff <ref>reports complexity changes relative to any git reference. (#140) - Comprehension complexity — list/dict/set comprehensions and generator expressions now contribute to cognitive complexity scores. (#139)
# complexipy: ignore— new canonical inline suppression comment;# noqa: complexipyis deprecated. (#146)- Glob patterns in the config
excludefield. (#142) - Spanish documentation. (#147)
Fixed¶
--topresults now preserve global descending order across multi-file runs.--top NrejectsN ≤ 0with a clear error.--script-strictnow correctly requires--check-script.- Ignore markers (
# complexipy: ignore) now work on multiline function definitions. - JSON output includes a final newline (POSIX compliance). (#148)
- Snapshot-allowed functions are now shown as
PASSEDin output. - The snapshot watermark correctly drives the exit code when active.
See the release notes for the full details.
[5.2.0] - 2026-01-28¶
Fixed¶
- Fixed
# noqa: complexipycomments on decorated functions. (#128)
Changed¶
- Updated the pre-commit complexipy version in the docs. (#126)
- Updated the documentation. (#132)
See the release notes for the full details.
[5.1.0] - 2025-12-09¶
Fixed¶
- Fixed invalid results output paths on Windows. (#120)
See the release notes for the full details.
[5.0.0] - 2025-11-26¶
Migration
Conditional scoring now counts each elif/else branch as +1
complexity (plus its boolean test), aligning with Sonar's
cognitive-complexity rules. Expect higher scores for branching. See the
migration guide
for upgrade guidance.
Added¶
- Snapshots:
--snapshot-createwritescomplexipy-snapshot.json; comparisons block regressions, auto-refresh on improvements, and can be bypassed with--snapshot-ignore. (#111) - Change tracking: a per-target cache in
.complexipy_cacheshows deltas/new failures for over-threshold functions using stable BLAKE2 keys. (#115) - Output controls:
--failedto show only violations (#114);--color auto|yes|no(#109); richer summaries of failing functions and invalid paths. - Python 3.14 support. (#106)
Changed¶
- Excludes and errors: exclude entries are resolved relative to the root and only applied when they match real files/dirs; missing paths are reported cleanly instead of panicking. (#113)
See the release notes for the full details.
[4.2.0] - 2025-09-21¶
Added¶
- Exclude files from analysis.
- Inline ignores to exclude functions from analysis.
Fixed¶
- Python 3.8 support. (#96)
See the release notes for the full details.
[4.1.0] - 2025-09-08¶
Added¶
- Version support. (#93)
See the release notes for the full details.
[4.0.2] - 2025-08-22¶
Patch release; no changes were recorded in its release notes.
See the release notes for the full details.
[4.0.1] - 2025-08-21¶
Fixed¶
- Fixed the PyPI README error.
See the release notes for the full details.
[4.0.0] - 2025-08-21¶
Migration
The logic for counting boolean operators in conditions was updated to align with the definition from the original paper. Existing functions may report higher complexities. See the migration guide for upgrade guidance.
Added¶
- Configuration support via
complexipy.tomlor[tool.complexipy]inpyproject.toml— users can now define default arguments.
Fixed¶
- Fixed an infinite loop when analyzing modules with invalid Python syntax. (#85, resolved in #88)
Changed¶
- Improved performance and Rust implementation details.
- Updated and improved documentation.
See the release notes for the full details.
[3.3.0] - 2025-07-17¶
Added¶
--max-complexity-allowed(-mx) — customize the maximum allowed cognitive complexity threshold per function. The default remains 15 to maintain existing behavior.- GitHub Actions integration for the custom threshold.
See the release notes for the full details.
[3.2.0] - 2025-07-09¶
Fixed¶
- Fixed an error when using complexipy on Windows, related to the
richlibrary used to draw the console output with emojis. - Fixed the
quietparameter still drawing output that wasn't handled in the Rust code.
See the release notes for the full details.
[3.1.1] - 2025-07-06¶
Changed¶
- The maximum complexity threshold is now
15, matching the Sonar threshold to make adoption of the library easier. (#78)
See the release notes for the full details.
[3.0.0] - 2025-06-16¶
Migration
--max-complexity was removed; complexipy now uses a fixed cognitive
complexity threshold of 15. The tool exits with an error when a function
meets or exceeds the threshold. Use --ignore-complexity (-i) to show
all functions regardless of their complexity score. See the
migration guide
for upgrade guidance.
Added¶
- WebAssembly (WASM) support — the core analysis engine can now be compiled to WebAssembly, enabling browser-based analysis and tools like the VSCode extension. (#72)
- JSON output via
--output-json(-j) for machine-readable results. (#74) --ignore-complexity(-i) flag to display all functions regardless of whether they exceed the complexity threshold. (#73)--details(-d) now also affects CSV and JSON outputs. (#73)- Sort results by complexity score (
asc,desc) or byname. (#73) - Pre-commit hook support with documentation for easy setup. (#75)
Removed¶
- The
--max-complexityargument. (#73)
See the release notes for the full details.
[2.1.1] - 2025-04-24¶
Fixed¶
- Fixed compatibility with Python 3.8. (#66)
See the release notes for the full details.
[2.1.0] - 2025-04-23¶
Fixed¶
- Fixed dictionary expression bool op counting. (#64)
See the release notes for the full details.
[2.0.0] - 2025-04-18¶
Changed¶
- Changed the parser from
rustpythontoruff_python_parser. (#62)
See the release notes for the full details.
[1.2.0] - 2024-12-15¶
Fixed¶
- Fixed the
output_summaryfunction call that was missing thefiles_complexitiesargument. (#58)
See the release notes for the full details.
[1.1.0] - 2024-12-14¶
Added¶
- Multiple paths support — pass several paths to analyze at once. (#56)
Removed¶
- The deprecated
-loption, simplifying the command-line interface. (#56) - File-level analysis, in order to focus on functions instead of the whole file. (#56)
See the release notes for the full details.
[0.5.0] - 2024-10-28¶
Added¶
- Python API — call complexipy from your own Python code with
file_complexity()andcode_complexity(). (#45) - Library usage documented in the README. (#49)
- Improved package usability. (#53)
- Updated documentation. (#54)
See the release notes for the full details.
[0.4.0] - 2024-06-21¶
Added¶
- The cognitive complexity now considers the
If Expressionused in the code, including when used inside aCall Expressionand so on. (#44)
Fixed¶
- Fixed an edge case that could cause a memory overflow by filtering the
cognitive complexity of the
orelsevalues in anIf Statementand keeping the nesting level subtraction propagation. (#44)
See the release notes for the full details.
[0.3.3] - 2024-04-27¶
Changed¶
- Updated CI and removed unused dependencies. (#43)
See the release notes for the full details.
[0.3.2] - 2024-03-22¶
Changed¶
- When using
--details low, an empty summary table is no longer printed; an informational message is shown instead. (#38)
See the release notes for the full details.
[0.3.1] - 2024-03-13¶
Added¶
-s/--sortoptional parameter to sort the output. (#30)- Python >= 3.8 requirement. (#35)
Fixed¶
- Fixed the logic used to calculate cognitive complexity: assignment
statements only add complexity when
IfExpis used, andBinOpby itself does not add complexity. (#34)
See the release notes for the full details.
[0.3.0] - 2024-03-07¶
Added¶
- Function-level complexity analysis by default — the maximum complexity is evaluated for each function inside the Python files; per-file cognitive complexity is still available. (#21)
- New parameters. (#14)
- Progress bars. (#24)
--quietoption. (#26)- Unit testing. (#20)
- Cognitive complexity explanation in the docs. (#22)
Changed¶
- Enhanced the algorithm to measure cognitive complexity — results are closer to the Sonar implementation. (#18)
- Reduced verbosity, with more information about the stages when running
complexipyover git repositories (using the URL). - CSV report generation is now implemented in Rust instead of Python, improving performance.
See the release notes for the full details.
[0.2.2] - 2024-02-27¶
Patch release; no changes were recorded in its release notes.
See the release notes for the full details.
[0.2.1] - 2024-02-27¶
Changed¶
- Updated the README.
See the release notes for the full details.
[0.2.0] - 2024-02-27¶
Added¶
- Ignore paths support. (#6)
- Git repository URL support. (#7)
- CSV output format. (#8)
- Cognitive complexity algorithm fixes. (#10)
- Updated README. (#9)
See the release notes for the full details.