Python Classes Without Boilerplate
This report presents the forensic synthetic code analysis of python-attrs/attrs, a Python project with 5,827 GitHub stars. SynthScan v2.0 examined 28,597 lines of code across 101 source files, recording 357 pattern matches distributed across 12 syntactic categories. The overall adjusted score of 12.5 places this repository in the Low AI signal band.
The scanner applied 160+ deterministic lexical heuristics, multi-line block detectors, abstract syntax tree depth profilers, and a cross-file Jaccard similarity matrix to construct a statistically normalised synthetic code estimate. All matches are individually weighted by severity coefficient and contextual multiplier before summation, and the resulting headline score is temporally discounted to account for the repository's development history relative to the commercial emergence of large language model coding tooling (November 2022 onward).
Longitudinal tracking requires multiple scan runs. Once this repository is re-scanned after new commits land, this chart will visualise how the synthetic code signal evolves over time — enabling you to detect whether AI authorship is growing, stabilising, or being actively corrected by human engineers.
Classifies detected patterns by their diagnostic confidence and structural impact. CRITICAL patterns (coefficient 10) represent definitive synthetic signatures — hallucinated imports, explicit LLM attribution metadata — virtually never produced by human authors. HIGH (5) indicates strong structural tells such as cross-file repetition or cross-linguistic idioms. MEDIUM (2) covers recognisable conversational padding and AI-specific vocabulary. LOW (1) captures subtle indicators like tautological comments and generic boilerplate that require density to carry independent signal.
This horizontal bar chart decomposes the repository's raw synthetic code score by top-level directory, allowing you to pinpoint precisely which modules or components carry the highest AI authorship density. Directories with disproportionately high scores relative to their size warrant targeted manual review: concentrated AI signatures often trace back to mass-generated configuration layers, auto-ported test suites, LLM-scaffolded boilerplate classes, or entire subsystems authored under heavy copilot assistance. Use this view to prioritise your human code-review effort.
The scanner identified 357 distinct pattern matches across 12 syntactic categories. Each entry below represents a discrete location in the source code where the engine recorded a statistically significant AI authorship indicator. Expand any category row to inspect the individual file paths, line numbers, code snippets, and the lexical context (CODE, COMMENT, or STRING) in which each match was detected.
Reading the findings table: The Severity column indicates the diagnostic confidence level (CRITICAL / HIGH / MEDIUM / LOW). The Context column identifies whether the match occurred inside executable code, an inline comment, or a string literal — comment-context matches receive a ×1.5 weight because LLMs systematically over-annotate. The ⚡ bolt icon marks clustered matches: three or more patterns within a 10-line window, each receiving an additional ×1.5 density multiplier as dense clusters constitute far stronger evidence of synthetic authorship than isolated hits.
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | bench/test_benchmarks.py | 48 | def test_create_simple_class_make_class(): | CODE |
| LOW | bench/test_benchmarks.py | 72 | def test_instantiate_no_defaults(): | CODE |
| LOW | bench/test_benchmarks.py | 80 | def test_instantiate_with_defaults(): | CODE |
| LOW | bench/test_benchmarks.py | 218 | def test_create_cached_property_class(self): | CODE |
| LOW | tests/test_pyright.py | 89 | def test_pyright_attrsinstance_compat(tmp_path): | CODE |
| LOW | tests/test_pyright.py | 117 | def test_pyright_field_converters_tuple(tmp_path): | CODE |
| LOW | tests/test_funcs.py | 160 | def test_lists_tuples_retain_type(self, container, C): | CODE |
| LOW | tests/test_funcs.py | 214 | def test_asdict_preserve_order(self, cls): | CODE |
| LOW | tests/test_funcs.py | 223 | def test_retain_keys_are_tuples(self): | CODE |
| LOW | tests/test_funcs.py | 254 | def test_named_tuple_retain_type(self): | CODE |
| LOW | tests/test_funcs.py | 275 | def test_type_error_with_retain_type(self): | CODE |
| LOW | tests/test_funcs.py | 332 | def assert_proper_tuple_class(obj, obj_tuple): | CODE |
| LOW | tests/test_funcs.py | 413 | def test_lists_tuples_retain_type(self, container, C): | CODE |
| LOW | tests/test_funcs.py | 460 | def test_named_tuple_retain_type(self): | CODE |
| LOW | tests/test_funcs.py | 481 | def test_type_error_with_retain_type(self): | CODE |
| LOW | tests/test_funcs.py | 773 | def test_regression_attrs_classes(self): | CODE |
| LOW | tests/test_forward_references.py | 8 | def test_forward_class_reference(): | CODE |
| LOW | tests/test_utils.py | 15 | def test_returns_distinct_classes(self): | CODE |
| LOW | tests/test_converters.py | 95 | def test_annotations_if_last_in_pipe(self): | CODE |
| LOW | tests/strategies.py | 52 | def _create_hyp_nested_strategy(draw, simple_class_strategy): | CODE |
| LOW | tests/strategies.py | 90 | def simple_attrs_with_metadata(draw): | CODE |
| LOW | tests/test_functional.py | 225 | def test_subclassing_with_extra_attrs(self, cls): | CODE |
| LOW | tests/test_functional.py | 240 | def test_subclass_without_extra_attrs(self, base): | CODE |
| LOW | tests/test_functional.py | 332 | def test_subclassing_frozen_gives_frozen(self): | CODE |
| LOW | tests/test_functional.py | 420 | def test_handles_different_defaults(self): | CODE |
| LOW | tests/test_functional.py | 437 | def test_unsafe_hash_false_eq_false(self, slots): | CODE |
| LOW | tests/test_functional.py | 545 | def test_tuple_class_aliasing(self): | CODE |
| LOW | tests/test_functional.py | 660 | def test_no_setattr_if_validate_without_validators(self, slots): | CODE |
| LOW | tests/test_functional.py | 684 | def test_no_setattr_if_convert_without_converters(self, slots): | CODE |
| LOW | tests/test_functional.py | 705 | def test_no_setattr_with_ng_defaults(self, slots): | CODE |
| LOW | tests/test_functional.py | 733 | def test_on_setattr_detect_inherited_validators(self): | CODE |
| LOW | tests/test_setattr.py | 51 | def test_change_with_generator_hook(self): | CODE |
| LOW | tests/test_setattr.py | 71 | def test_generator_hook_executes_after_yielding(self): | CODE |
| LOW | tests/test_setattr.py | 194 | def test_generator_hook_not_called_in_init(self): | CODE |
| LOW | tests/test_setattr.py | 214 | def test_generator_hook_with_define(self): | CODE |
| LOW | tests/test_setattr.py | 234 | def test_generator_hook_class_level(self): | CODE |
| LOW | tests/test_setattr.py | 262 | def test_generator_pre_yield_exception(self): | CODE |
| LOW | tests/test_setattr.py | 282 | def test_generator_post_yield_exception(self): | CODE |
| LOW | tests/test_setattr.py | 303 | def test_generator_yields_multiple_times(self): | CODE |
| LOW | tests/test_setattr.py | 344 | def test_no_validator_no_converter(self): | CODE |
| LOW | tests/test_setattr.py | 359 | def test_validate_respects_run_validators_config(self): | CODE |
| LOW | tests/test_setattr.py | 383 | def test_frozen_on_setattr_class_is_caught(self): | CODE |
| LOW | tests/test_setattr.py | 395 | def test_frozen_on_setattr_attribute_is_caught(self): | CODE |
| LOW | tests/test_setattr.py | 409 | def test_frozen_on_setattr_nops(self, nop): | CODE |
| LOW | tests/test_setattr.py | 418 | def test_setattr_reset_if_no_custom_setattr(self, slots): | CODE |
| LOW | tests/test_setattr.py | 443 | def test_setattr_inherited_do_not_reset(self, slots): | CODE |
| LOW | tests/test_setattr.py | 470 | def test_pickling_retains_attrs_own(self, slots): | CODE |
| LOW | tests/test_setattr.py | 487 | def test_slotted_class_can_have_custom_setattr(self): | CODE |
| LOW | tests/test_setattr.py | 526 | def test_setattr_auto_detect_if_no_custom_setattr(self, slots): | CODE |
| LOW | tests/test_setattr.py | 545 | def test_setattr_restore_respects_auto_detect(self, slots): | CODE |
| LOW | tests/test_setattr.py | 558 | def test_setattr_auto_detect_frozen(self, slots): | CODE |
| LOW | tests/test_setattr.py | 571 | def test_setattr_auto_detect_on_setattr(self, slots): | CODE |
| LOW | tests/test_setattr.py | 591 | def test_setattr_inherited_do_not_reset_intermediate( | CODE |
| LOW | tests/test_setattr.py | 633 | def test_setattr_converter_piped(self): | CODE |
| LOW⚡ | tests/test_make.py | 2654 | def test_eq_callable_order_boolean(self): | CODE |
| LOW⚡ | tests/test_make.py | 2663 | def test_eq_callable_order_callable(self): | CODE |
| LOW⚡ | tests/test_make.py | 2672 | def test_eq_boolean_order_callable(self): | CODE |
| LOW⚡ | tests/test_make.py | 2682 | def test_order_mirrors_eq_by_default(self, eq): | CODE |
| LOW | tests/test_make.py | 67 | def _with_and_without_validation(request): | CODE |
| LOW | tests/test_make.py | 92 | def test_validators_lists_to_wrapped_tuples(self): | CODE |
| 189 more matches not shown… | ||||
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | bench/test_benchmarks.py | 5 | CODE | |
| LOW | tests/test_pyright.py | 3 | CODE | |
| LOW | tests/attr_import_star.py | 4 | CODE | |
| LOW | tests/test_import.py | 14 | CODE | |
| LOW | tests/test_hooks.py | 3 | CODE | |
| LOW | typing-examples/baseline.py | 8 | CODE | |
| LOW | typing-examples/pyrefly.py | 7 | CODE | |
| LOW | typing-examples/mypy.py | 7 | CODE | |
| LOW | src/attrs/setters.py | 3 | CODE | |
| LOW | src/attrs/validators.py | 3 | CODE | |
| LOW | src/attrs/__init__.py | 3 | CODE | |
| LOW | src/attrs/__init__.py | 3 | CODE | |
| LOW | src/attrs/__init__.py | 3 | CODE | |
| LOW | src/attrs/__init__.py | 3 | CODE | |
| LOW | src/attrs/__init__.py | 3 | CODE | |
| LOW | src/attrs/__init__.py | 3 | CODE | |
| LOW | src/attrs/__init__.py | 3 | CODE | |
| LOW | src/attrs/__init__.py | 3 | CODE | |
| LOW | src/attrs/__init__.py | 3 | CODE | |
| LOW | src/attrs/__init__.py | 3 | CODE | |
| LOW | src/attrs/__init__.py | 3 | CODE | |
| LOW | src/attrs/__init__.py | 3 | CODE | |
| LOW | src/attrs/__init__.py | 3 | CODE | |
| LOW | src/attrs/__init__.py | 3 | CODE | |
| LOW | src/attrs/__init__.py | 3 | CODE | |
| LOW | src/attrs/__init__.py | 3 | CODE | |
| LOW | src/attrs/__init__.py | 3 | CODE | |
| LOW | src/attrs/__init__.py | 3 | CODE | |
| LOW | src/attrs/__init__.py | 3 | CODE | |
| LOW | src/attrs/__init__.py | 25 | CODE | |
| LOW | src/attrs/__init__.py | 26 | CODE | |
| LOW | src/attrs/__init__.py | 26 | CODE | |
| LOW | src/attrs/__init__.py | 26 | CODE | |
| LOW | src/attrs/__init__.py | 28 | CODE | |
| LOW | src/attrs/__init__.py | 28 | CODE | |
| LOW | src/attrs/__init__.py | 28 | CODE | |
| LOW | src/attrs/exceptions.py | 3 | CODE | |
| LOW | src/attrs/converters.py | 3 | CODE | |
| LOW | src/attrs/filters.py | 3 | CODE | |
| LOW | src/attr/__init__.py | 12 | CODE | |
| LOW | src/attr/__init__.py | 12 | CODE | |
| LOW | src/attr/__init__.py | 13 | CODE | |
| LOW | src/attr/__init__.py | 14 | CODE | |
| LOW | src/attr/__init__.py | 14 | CODE | |
| LOW | src/attr/__init__.py | 15 | CODE | |
| LOW | src/attr/__init__.py | 15 | CODE | |
| LOW | src/attr/__init__.py | 15 | CODE | |
| LOW | src/attr/__init__.py | 15 | CODE | |
| LOW | src/attr/__init__.py | 15 | CODE | |
| LOW | src/attr/__init__.py | 16 | CODE | |
| LOW | src/attr/__init__.py | 16 | CODE | |
| LOW | src/attr/__init__.py | 16 | CODE | |
| LOW | src/attr/__init__.py | 16 | CODE | |
| LOW | src/attr/__init__.py | 16 | CODE | |
| LOW | src/attr/__init__.py | 16 | CODE | |
| LOW | src/attr/__init__.py | 16 | CODE | |
| LOW | src/attr/__init__.py | 16 | CODE | |
| LOW | src/attr/__init__.py | 30 | CODE | |
| LOW | src/attr/__init__.py | 30 | CODE | |
| LOW | src/attr/__init__.py | 30 | CODE | |
| 5 more matches not shown… | ||||
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| HIGH | src/attr/_make.py | 590 | Create a new instance, based on the first positional argument with *changes* applied. .. tip:: On | STRING |
| HIGH | src/attr/_make.py | 1925 | Return the tuple of *attrs* attributes for a class or instance. The tuple also allows accessing the fields by | STRING |
| HIGH | src/attr/_make.py | 1976 | Return an ordered dictionary of *attrs* attributes for a class, whose keys are the attribute names. Args: | STRING |
| HIGH | src/attr/_next_gen.py | 656 | Inspect the class and return its effective build parameters. Warning: This feature is currently **expe | STRING |
| HIGH | src/attr/_funcs.py | 34 | Return the *attrs* attribute values of *inst* as a dict. Optionally recurse into other *attrs*-decorated class | STRING |
| HIGH | src/attr/_funcs.py | 237 | Return the *attrs* attribute values of *inst* as a tuple. Optionally recurse into other *attrs*-decorated clas | STRING |
| HIGH | src/attr/_funcs.py | 353 | Check whether *cls* is a class with *attrs* attributes. Args: cls (type): Class to introspect. Ra | STRING |
| HIGH | src/attr/_funcs.py | 381 | Copy *inst* and apply *changes*. This is different from `evolve` that applies the changes to the arguments | STRING |
| HIGH | src/attr/_funcs.py | 428 | Resolve any strings and forward annotations in type annotations. This is only required if you need concrete ty | STRING |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | tests/test_funcs.py | 104 | CODE | |
| LOW | tests/test_funcs.py | 343 | CODE | |
| LOW | tests/test_funcs.py | 111 | CODE | |
| LOW | tests/test_funcs.py | 352 | CODE | |
| LOW | src/attr/_make.py | 381 | CODE | |
| LOW | src/attr/_make.py | 1353 | CODE | |
| LOW | src/attr/_make.py | 2187 | CODE | |
| LOW | src/attr/_make.py | 676 | CODE | |
| LOW | src/attr/_make.py | 823 | CODE | |
| LOW | src/attr/_make.py | 859 | CODE | |
| LOW | src/attr/_make.py | 1478 | CODE | |
| LOW | src/attr/_funcs.py | 26 | CODE | |
| LOW | src/attr/_funcs.py | 152 | CODE | |
| LOW | src/attr/_funcs.py | 230 | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | tests/utils.py | 11 | CODE | |
| LOW | tests/utils.py | 40 | CODE | |
| LOW | src/attr/_make.py | 104 | CODE | |
| LOW | src/attr/_make.py | 1353 | CODE | |
| LOW | src/attr/_make.py | 2531 | CODE | |
| LOW | src/attr/_next_gen.py | 23 | CODE | |
| LOW | src/attr/_next_gen.py | 434 | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | src/attrs/__init__.py | 31 | __all__ = [ | CODE |
| LOW | src/attr/validators.py | 19 | __all__ = [ | CODE |
| LOW | src/attr/__init__.py | 45 | __all__ = [ | CODE |
| LOW | src/attr/converters.py | 11 | __all__ = [ | CODE |
| LOW | src/attr/_config.py | 3 | __all__ = ["get_run_validators", "set_run_validators"] | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM | src/attr/_funcs.py | 494 | # Return the class so you can use it as a decorator too. | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM | pyproject.toml | 262 | "DTZ", # datetime best practices don't matter in tests | STRING |
| MEDIUM | pyproject.toml | 274 | "TRY", # exception best practices don't matter in tests | STRING |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM | tests/test_setattr.py | 269 | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | typing-examples/mypy.py | 161 | # ConvCPipe(3.4) | COMMENT |
| LOW | src/attr/_compat.py | 81 | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | src/attr/_make.py | 708 | # Check if the pre init method has more arguments than just `self` | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | src/attr/validators.py | 731 | except Exception: # noqa: BLE001, PERF203, S112 | STRING |