💨 Fast, Async-ready, Openapi, type hints based framework for building APIs
This report presents the forensic synthetic code analysis of vitalik/django-ninja, a Python project with 9,179 GitHub stars. SynthScan v2.0 examined 32,738 lines of code across 271 source files, recording 467 pattern matches distributed across 14 syntactic categories. The overall adjusted score of 15.1 places this repository in the Moderate 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 467 distinct pattern matches across 14 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 | tests/test_csrf.py | 71 | def obtain_csrf_token_get_no_auth_route(request): | CODE |
| LOW | tests/test_csrf.py | 78 | def obtain_csrf_token_post_no_auth_route(request): | CODE |
| LOW | tests/test_csrf.py | 145 | def test_csrf_cookies_can_be_obtained(): | CODE |
| LOW | tests/test_filter_schema.py | 33 | def test_annotated_without_filter_lookup(): | CODE |
| LOW | tests/test_filter_schema.py | 44 | def test_improperly_configured_deprecated(): | CODE |
| LOW | tests/test_filter_schema.py | 55 | def test_improperly_configured_annotated(): | CODE |
| LOW | tests/test_filter_schema.py | 66 | def test_empty_q_when_none_ignored_deprecated(): | CODE |
| LOW | tests/test_filter_schema.py | 78 | def test_empty_q_when_none_ignored_annotated(): | CODE |
| LOW | tests/test_filter_schema.py | 149 | def test_q_is_a_list_deprecated(implicit_field_name): | CODE |
| LOW | tests/test_filter_schema.py | 168 | def test_q_is_a_list_annotated(implicit_field_name): | CODE |
| LOW | tests/test_filter_schema.py | 188 | def test_field_level_expression_connector_deprecated(): | CODE |
| LOW | tests/test_filter_schema.py | 205 | def test_field_level_expression_connector_annotated(): | CODE |
| LOW | tests/test_filter_schema.py | 225 | def test_class_level_expression_connector_deprecated(): | CODE |
| LOW | tests/test_filter_schema.py | 239 | def test_class_level_expression_connector_annotated(): | CODE |
| LOW | tests/test_filter_schema.py | 253 | def test_class_level_and_field_level_expression_connector_deprecated(): | CODE |
| LOW | tests/test_filter_schema.py | 272 | def test_class_level_and_field_level_expression_connector_annotated(): | CODE |
| LOW | tests/test_filter_schema.py | 294 | def test_ignore_none_deprecated(): | CODE |
| LOW | tests/test_filter_schema.py | 305 | def test_ignore_none_annotated(): | CODE |
| LOW | tests/test_filter_schema.py | 316 | def test_ignore_none_class_level_deprecated(): | CODE |
| LOW | tests/test_filter_schema.py | 330 | def test_ignore_none_class_level_annotated(): | CODE |
| LOW | tests/test_filter_schema.py | 344 | def test_field_level_custom_expression(): | CODE |
| LOW | tests/test_filter_schema.py | 367 | def test_class_level_custom_expression(): | CODE |
| LOW | tests/test_filter_schema.py | 393 | def test_multiple_filter_lookup_instances_error(): | CODE |
| LOW | tests/test_filter_schema.py | 406 | def test_pydantic_field_with_extra_warns(): | CODE |
| LOW | tests/test_export_openapi_schema.py | 50 | def test_export_default_without_api_endpoint(mock): | CODE |
| LOW | tests/test_inheritance_routers.py | 86 | def test_inheritance_responses(path, expected_status, expected_response): | CODE |
| LOW | tests/test_utils.py | 18 | def test_replace_path_param_notation(input, expected_output): | CODE |
| LOW | tests/test_utils.py | 22 | def test_contribute_operation_args(): | CODE |
| LOW | tests/test_pagination.py | 620 | def test_limit_offset_per_endpoint_max_limit(): | CODE |
| LOW | tests/test_pagination.py | 667 | def test_pagination_works_with_unnamed_classes(): | CODE |
| LOW | tests/test_pagination.py | 680 | def test_no_pagination_without_query_params(): | CODE |
| LOW | tests/test_pagination.py | 707 | def test_find_collection_response_skips_none_and_not_set(): | CODE |
| LOW | tests/test_pagination.py | 730 | def test_find_collection_response_raises_when_no_collection(): | CODE |
| LOW | tests/test_body.py | 59 | def test_body_validation_error(): | CODE |
| LOW | tests/test_body.py | 75 | def test_incorrect_annotation(): | CODE |
| LOW | tests/test_body.py | 90 | def validation_error_from_error_contexts( | CODE |
| LOW | tests/test_body.py | 118 | def test_body_custom_validation_error(): | CODE |
| LOW | tests/test_response.py | 202 | def test_pydantic_httpurl_schema(): | CODE |
| LOW | tests/test_annotations_py314.py | 38 | def test_paginated_route_with_deferred_annotations(): | CODE |
| LOW | tests/test_annotations_py314.py | 56 | def test_schema_with_self_referencing_resolver_annotation(): | CODE |
| LOW | tests/test_compatibility.py | 14 | def test_modelschema_custom_annotation(): | CODE |
| LOW | tests/test_compatibility.py | 34 | def test_modelschema_fk_schema_annotation(): | CODE |
| LOW | tests/test_openapi_schema.py | 165 | def method_union_payload_and_simple(request, data: Union[int, TypeB]): | CODE |
| LOW | tests/test_openapi_schema.py | 183 | def method_test_title_description( | CODE |
| LOW | tests/test_openapi_schema.py | 193 | def method_test_deprecated_example_examples( | CODE |
| LOW | tests/test_openapi_schema.py | 698 | def test_schema_title_description(schema): | CODE |
| LOW | tests/test_openapi_schema.py | 758 | def test_schema_deprecated_example_examples(schema): | CODE |
| LOW | tests/test_openapi_schema.py | 836 | def test_union_payload_simple(schema): | CODE |
| LOW | tests/test_openapi_schema.py | 860 | def test_new_union_payload_type(schema): | CODE |
| LOW | tests/test_openapi_schema.py | 895 | def test_unique_operation_ids(capsys): | CODE |
| LOW | tests/test_openapi_schema.py | 982 | def test_all_paths_typed_params_rendered(): | CODE |
| LOW | tests/test_openapi_schema.py | 1012 | def test_no_default_for_custom_items_attribute(): | CODE |
| LOW | tests/test_openapi_schema.py | 1047 | def test_by_alias_uses_serialization_alias_simple(): | CODE |
| LOW | tests/test_openapi_schema.py | 1072 | def test_by_alias_uses_validation_alias_simple(): | CODE |
| LOW | tests/test_openapi_schema.py | 1098 | def test_by_alias_uses_serialization_alias_model(): | CODE |
| LOW | tests/test_forms_and_files.py | 71 | def test_empty_multipart_body_field(): | CODE |
| LOW | tests/test_pydantic_migrate.py | 23 | def test_optional_pydantic_model(): | CODE |
| LOW | tests/test_orm_schemas.py | 376 | def test_textfield_max_length_validates_input_only(): | CODE |
| LOW | tests/test_orm_schemas.py | 405 | def test_textfield_max_length_api_flow(): | CODE |
| LOW | tests/test_orm_schemas.py | 603 | def test_duplicate_schema_names(): | CODE |
| 226 more matches not shown… | ||||
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | tests/test_docs/test_body.py | 11 | CODE | |
| LOW | tests/test_docs/test_body.py | 12 | CODE | |
| LOW | tests/test_docs/test_body.py | 13 | CODE | |
| LOW | tests/test_docs/test_auth.py | 30 | CODE | |
| LOW | tests/test_docs/test_auth.py | 31 | CODE | |
| LOW | tests/test_docs/test_auth.py | 32 | CODE | |
| LOW | tests/test_docs/test_auth.py | 33 | CODE | |
| LOW | tests/test_docs/test_auth.py | 34 | CODE | |
| LOW | tests/test_docs/test_auth.py | 35 | CODE | |
| LOW | tests/test_docs/test_auth.py | 36 | CODE | |
| LOW | tests/test_docs/test_auth.py | 37 | CODE | |
| LOW | tests/test_docs/test_auth.py | 38 | CODE | |
| LOW | tests/test_docs/test_form.py | 14 | CODE | |
| LOW | tests/test_docs/test_form.py | 15 | CODE | |
| LOW | tests/test_docs/test_form.py | 47 | CODE | |
| LOW | tests/test_docs/test_query.py | 11 | CODE | |
| LOW | tests/test_docs/test_query.py | 12 | CODE | |
| LOW | tests/test_docs/test_query.py | 13 | CODE | |
| LOW | tests/test_docs/test_query.py | 14 | CODE | |
| LOW | tests/test_docs/test_path.py | 11 | CODE | |
| LOW | tests/test_docs/test_path.py | 21 | CODE | |
| LOW | tests/test_docs/test_path.py | 22 | CODE | |
| LOW | docs/src/tutorial/query/code010.py | 1 | CODE | |
| LOW | ninja/__init__.py | 5 | CODE | |
| LOW | ninja/__init__.py | 7 | CODE | |
| LOW | ninja/__init__.py | 8 | CODE | |
| LOW | ninja/__init__.py | 8 | CODE | |
| LOW | ninja/__init__.py | 8 | CODE | |
| LOW | ninja/__init__.py | 9 | CODE | |
| LOW | ninja/__init__.py | 10 | CODE | |
| LOW | ninja/__init__.py | 10 | CODE | |
| LOW | ninja/__init__.py | 11 | CODE | |
| LOW | ninja/__init__.py | 12 | CODE | |
| LOW | ninja/__init__.py | 12 | CODE | |
| LOW | ninja/__init__.py | 12 | CODE | |
| LOW | ninja/__init__.py | 12 | CODE | |
| LOW | ninja/__init__.py | 12 | CODE | |
| LOW | ninja/__init__.py | 12 | CODE | |
| LOW | ninja/__init__.py | 12 | CODE | |
| LOW | ninja/__init__.py | 12 | CODE | |
| LOW | ninja/__init__.py | 12 | CODE | |
| LOW | ninja/__init__.py | 12 | CODE | |
| LOW | ninja/__init__.py | 12 | CODE | |
| LOW | ninja/__init__.py | 12 | CODE | |
| LOW | ninja/__init__.py | 12 | CODE | |
| LOW | ninja/__init__.py | 12 | CODE | |
| LOW | ninja/__init__.py | 12 | CODE | |
| LOW | ninja/__init__.py | 29 | CODE | |
| LOW | ninja/__init__.py | 30 | CODE | |
| LOW | ninja/__init__.py | 31 | CODE | |
| LOW | ninja/__init__.py | 32 | CODE | |
| LOW | ninja/__init__.py | 33 | CODE | |
| LOW | ninja/__init__.py | 33 | CODE | |
| LOW | ninja/errors.py | 13 | CODE | |
| LOW | ninja/errors.py | 14 | CODE | |
| LOW | ninja/router.py | 28 | CODE | |
| LOW | ninja/main.py | 38 | CODE | |
| LOW | ninja/signature/__init__.py | 1 | CODE | |
| LOW | ninja/signature/__init__.py | 2 | CODE | |
| LOW | ninja/security/__init__.py | 1 | CODE | |
| 15 more matches not shown… | ||||
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | ninja/files.py | 6 | __all__ = ["UploadedFile"] | CODE |
| LOW | ninja/responses.py | 10 | __all__ = [ | CODE |
| LOW | ninja/constants.py | 3 | __all__ = ["NOT_SET"] | CODE |
| LOW | ninja/__init__.py | 35 | __all__ = [ | CODE |
| LOW | ninja/renderers.py | 8 | __all__ = ["BaseRenderer", "JSONRenderer"] | CODE |
| LOW | ninja/types.py | 3 | __all__ = ["DictStrAny", "TCallable"] | CODE |
| LOW | ninja/operation.py | 51 | __all__ = ["Operation", "PathView", "ResponseObject"] | CODE |
| LOW | ninja/parser.py | 9 | __all__ = ["Parser"] | CODE |
| LOW | ninja/utils.py | 7 | __all__ = [ | CODE |
| LOW | ninja/errors.py | 16 | __all__ = [ | CODE |
| LOW | ninja/errors.py | 87 | def set_default_exc_handlers(api: "NinjaAPI") -> None: | CODE |
| LOW | ninja/router.py | 31 | __all__ = ["Router", "RouterMount", "BoundRouter"] | CODE |
| LOW | ninja/streaming.py | 8 | __all__ = ["StreamFormat", "SSE", "JSONL"] | CODE |
| LOW | ninja/main.py | 40 | __all__ = ["NinjaAPI"] | CODE |
| LOW⚡ | ninja/main.py | 610 | def set_default_exception_handlers(self) -> None: | CODE |
| LOW | ninja/schema.py | 48 | __all__ = ["BaseModel", "Field", "DjangoGetter", "Schema"] | CODE |
| LOW | ninja/compatibility/util.py | 4 | __all__ = ["UNION_TYPES", "get_annotations_from_namespace"] | CODE |
| LOW | ninja/signature/__init__.py | 4 | __all__ = ["ViewSignature", "is_async"] | CODE |
| LOW | ninja/signature/details.py | 30 | __all__ = [ | CODE |
| LOW | ninja/signature/utils.py | 13 | __all__ = [ | CODE |
| LOW | ninja/security/session.py | 8 | __all__ = ["SessionAuth", "SessionAuthSuperUser", "SessionAuthIsStaff"] | CODE |
| LOW | ninja/security/__init__.py | 5 | __all__ = [ | CODE |
| LOW | ninja/security/http.py | 12 | __all__ = ["HttpAuthBase", "HttpBearer", "DecodeError", "HttpBasicAuth"] | CODE |
| LOW | ninja/security/apikey.py | 10 | __all__ = ["APIKeyBase", "APIKeyQuery", "APIKeyCookie", "APIKeyHeader"] | CODE |
| LOW | ninja/security/base.py | 9 | __all__ = ["SecuritySchema", "AuthBase"] | CODE |
| LOW | ninja/openapi/__init__.py | 3 | __all__ = ["get_schema"] | CODE |
| LOW | ninja/openapi/urls.py | 11 | __all__ = ["get_openapi_urls", "get_root_url"] | CODE |
| LOW | ninja/testing/__init__.py | 3 | __all__ = ["TestClient", "TestAsyncClient"] | CODE |
| LOW | ninja/params/models.py | 26 | __all__ = [ | CODE |
| LOW | ninja/params/__init__.py | 7 | __all__ = [ | CODE |
| LOW | ninja/orm/fields.py | 17 | __all__ = ["create_m2m_link_type", "get_schema_field", "get_related_field_schema"] | CODE |
| LOW | ninja/orm/shortcuts.py | 6 | __all__ = ["S", "L"] | CODE |
| LOW | ninja/orm/__init__.py | 5 | __all__ = ["create_schema", "register_field", "ModelSchema"] | CODE |
| LOW | ninja/orm/factory.py | 25 | __all__ = ["SchemaFactory", "factory", "create_schema"] | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | ninja/operation.py | 55 | CODE | |
| LOW | ninja/operation.py | 574 | CODE | |
| LOW | ninja/router.py | 231 | CODE | |
| LOW | ninja/router.py | 271 | CODE | |
| LOW | ninja/router.py | 311 | CODE | |
| LOW | ninja/router.py | 351 | CODE | |
| LOW | ninja/router.py | 391 | CODE | |
| LOW | ninja/router.py | 431 | CODE | |
| LOW | ninja/router.py | 477 | CODE | |
| LOW | ninja/main.py | 52 | CODE | |
| LOW | ninja/main.py | 123 | CODE | |
| LOW | ninja/main.py | 166 | CODE | |
| LOW | ninja/main.py | 209 | CODE | |
| LOW | ninja/main.py | 252 | CODE | |
| LOW | ninja/main.py | 295 | CODE | |
| LOW | ninja/main.py | 338 | CODE | |
| LOW | ninja/params/functions.py | 11 | CODE | |
| LOW | ninja/params/functions.py | 50 | CODE | |
| LOW | ninja/params/functions.py | 89 | CODE | |
| LOW | ninja/params/functions.py | 128 | CODE | |
| LOW | ninja/params/functions.py | 167 | CODE | |
| LOW | ninja/params/functions.py | 206 | CODE | |
| LOW | ninja/params/functions.py | 245 | CODE | |
| LOW | ninja/params/models.py | 198 | CODE | |
| LOW | ninja/params/__init__.py | 77 | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | ninja/filter_schema.py | 155 | CODE | |
| LOW | ninja/operation.py | 312 | CODE | |
| LOW | ninja/operation.py | 548 | CODE | |
| LOW | ninja/router.py | 116 | CODE | |
| LOW | ninja/router.py | 170 | CODE | |
| LOW | ninja/router.py | 685 | CODE | |
| LOW | ninja/main.py | 468 | CODE | |
| LOW | ninja/schema.py | 61 | CODE | |
| LOW | ninja/signature/details.py | 356 | CODE | |
| LOW | ninja/signature/details.py | 126 | CODE | |
| LOW | ninja/signature/details.py | 187 | CODE | |
| LOW | ninja/signature/details.py | 221 | CODE | |
| LOW | ninja/management/utils.py | 7 | CODE | |
| LOW | ninja/openapi/schema.py | 345 | CODE | |
| LOW | ninja/openapi/schema.py | 63 | CODE | |
| LOW | ninja/openapi/schema.py | 158 | CODE | |
| LOW | ninja/testing/client.py | 144 | CODE | |
| LOW | ninja/orm/metaclass.py | 68 | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM | tests/test_csrf_async.py | 75 | # Define the async function and manually set csrf_exempt attribute | COMMENT |
| MEDIUM | ninja/operation.py | 647 | # Create a unique view function for this PathView | COMMENT |
| MEDIUM | ninja/operation.py | 650 | # Create a wrapper for async view | COMMENT |
| MEDIUM | ninja/operation.py | 662 | # Create a wrapper for sync view | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | ninja/signature/details.py | 275 | # 1) if type of the param is defined as one of the Param's subclasses - we just use that definition | COMMENT |
| MEDIUM⚡ | ninja/static/ninja/redoc.standalone.js | 2 | !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("null")):"function"==typeof de | CODE |
| MEDIUM⚡ | ninja/static/ninja/redoc.standalone.js | 2 | !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("null")):"function"==typeof de | CODE |
| MEDIUM⚡ | ninja/static/ninja/redoc.standalone.js | 2 | !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("null")):"function"==typeof de | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| CRITICAL | ninja/static/ninja/redoc.standalone.js | 41 | `;class As extends n.PureComponent{render(){return n.createElement("div",{style:{textAlign:"center"}},n.createElement(_s | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | tests/test_forms.py | 81 | # username: str | COMMENT |
| LOW | tests/test_union.py | 1 | # This is no longer the case in pydantic 2 | COMMENT |
| LOW | tests/test_union.py | 21 | # assert client.get("/test?value=today").json() == ["today", "str"] | COMMENT |
| LOW | …/docs/guides/response/django-pydantic-create-schema.md | 61 | # username: str | COMMENT |
| LOW | docs/docs/guides/response/django-pydantic.md | 61 | model = User | COMMENT |
| LOW | ninja/schema.py | 141 | COMMENT | |
| LOW | ninja/static/ninja/swagger-ui-init.js | 21 | // configObject.requestInterceptor = (req) => { | COMMENT |
| LOW | ninja/static/ninja/swagger-ui-init.js | 41 | // req.headers['X-CSRFToken'] = swaggerUi.dataset.csrfToken | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | tests/test_app.py | 98 | except Exception: | CODE |
| LOW | ninja/operation.py | 221 | except Exception as e: | CODE |
| LOW | ninja/operation.py | 321 | except Exception as exc: | CODE |
| LOW | ninja/operation.py | 500 | except Exception as e: | CODE |
| LOW | ninja/operation.py | 559 | except Exception as exc: | CODE |
| LOW | ninja/security/http.py | 85 | except Exception as e: # dear contributors please do not change to valueerror - here can be multiple exceptions | CODE |
| LOW | ninja/params/models.py | 137 | except Exception as e: | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | ninja/static/ninja/redoc.standalone.js | 41 | `;class As extends n.PureComponent{render(){return n.createElement("div",{style:{textAlign:"center"}},n.createElement(_s | CODE |
| LOW | ninja/static/ninja/redoc.standalone.js | 752 | `;var Bd=Object.defineProperty,Ud=Object.defineProperties,qd=Object.getOwnPropertyDescriptors,Vd=Object.getOwnPropertySy | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | tests/test_app.py | 16 | # make sure to check how this will work with versioning | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | ninja/pagination.py | 619 | # Check if Input schema has any fields | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | tests/test_auth.py | 349 | async def handle_request(request): | CODE |