Skip to content

Python 3.13#7746

Merged
fatih-acar merged 17 commits into
developfrom
pog-python-3.13
Dec 18, 2025
Merged

Python 3.13#7746
fatih-acar merged 17 commits into
developfrom
pog-python-3.13

Conversation

@ogenstad

@ogenstad ogenstad commented Nov 28, 2025

Copy link
Copy Markdown
Contributor

Summary by CodeRabbit

  • Infrastructure

    • Bumped Python baseline to 3.13.x and parameterized CI/workflows to use a central Python version.
  • API Changes

    • Broadened OpenAPI response schemas to allow additional properties and more flexible JSON payloads.
  • Dependencies

    • Updated and pinned multiple libraries and packaging metadata to support newer Python versions.
  • Tests

    • Modernized async test fixtures and moved tests to use a scoped database provider for isolation.
  • Frontend

    • Widened generated API types to accept generic key-value JSON payloads.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai

coderabbitai Bot commented Nov 28, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

Dockerfiles and GitHub Actions were updated to use Python 3.13.11 via a new PYTHON_VERSION workflow output. pyproject.toml expanded the Python compatibility range to >=3.12,<3.14, added Python 3.13 classifier, and updated multiple dependencies. Many backend modules now access model_fields via class-level attributes (self.class.model_fields). Neo4j configuration uses NotificationDisabledClassification. Test infra was refactored to use build_database/get_database with optional singleton scoping via dependency provider.scope. Generated TypeScript types and OpenAPI schemas were widened to allow additional properties.

Pre-merge checks

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 10.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title "Python 3.13" accurately reflects the main objective of the pull request, which is to upgrade the project to Python 3.13 (from 3.12). This is evidenced by multiple changes across workflow files, Dockerfiles, and configuration files updating Python versions from 3.12 to 3.13.11 or 3.13.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions Bot added group/backend Issue related to the backend (API Server, Git Agent) group/ci Issue related to the CI pipeline labels Nov 28, 2025
@ogenstad ogenstad force-pushed the pog-python-3.13 branch 3 times, most recently from 409905c to 347a396 Compare November 28, 2025 12:17
@codspeed-hq

codspeed-hq Bot commented Nov 28, 2025

Copy link
Copy Markdown

CodSpeed Performance Report

Merging #7746 will not alter performance

Comparing pog-python-3.13 (e63c6d7) with develop (950e8cf)

Summary

✅ 12 untouched

@fatih-acar fatih-acar force-pushed the pog-python-3.13 branch 2 times, most recently from 96cb0de to 604719f Compare December 8, 2025 00:50
@github-actions github-actions Bot added the group/frontend Issue related to the frontend (React) label Dec 8, 2025
@fatih-acar fatih-acar force-pushed the pog-python-3.13 branch 2 times, most recently from 4ec7ddd to 46ff31d Compare December 8, 2025 01:17
@fatih-acar fatih-acar changed the title Python 3.13 Python 3.14 Dec 8, 2025
@fatih-acar fatih-acar force-pushed the pog-python-3.13 branch 6 times, most recently from 075e1b2 to 414ccd5 Compare December 10, 2025 23:50
Comment thread backend/infrahub/core/diff/model/diff.py Outdated
Comment thread .devcontainer/Dockerfile Outdated
@fatih-acar fatih-acar force-pushed the pog-python-3.13 branch 6 times, most recently from ebd9c6a to 9976fef Compare December 12, 2025 21:30
@fatih-acar fatih-acar marked this pull request as ready for review December 15, 2025 07:55
@fatih-acar fatih-acar requested a review from a team as a code owner December 15, 2025 07:55
@fatih-acar fatih-acar requested a review from a team as a code owner December 15, 2025 07:55

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
backend/infrahub/cli/db.py (1)

240-254: index() always uses Neo4j index manager, ignoring Memgraph branch

In index(), index_manager is set for Memgraph and then immediately overwritten:

if dbdriver.db_type is DatabaseType.MEMGRAPH:
    index_manager: IndexManagerBase = IndexManagerMemgraph(db=dbdriver)
index_manager = IndexManagerNeo4j(db=dbdriver)

This means Memgraph never uses IndexManagerMemgraph. You probably want an else:

-    if dbdriver.db_type is DatabaseType.MEMGRAPH:
-        index_manager: IndexManagerBase = IndexManagerMemgraph(db=dbdriver)
-    index_manager = IndexManagerNeo4j(db=dbdriver)
+    if dbdriver.db_type is DatabaseType.MEMGRAPH:
+        index_manager: IndexManagerBase = IndexManagerMemgraph(db=dbdriver)
+    else:
+        index_manager = IndexManagerNeo4j(db=dbdriver)

so each backend gets the correct index manager.

🧹 Nitpick comments (7)
backend/infrahub/core/graph/schema.py (1)

237-261: Align GRAPH_SCHEMA typing with get_graph_schema and constraint consumers

GRAPH_SCHEMA is now annotated as dict[str, dict[str, type[Any]]] while get_graph_schema() is still declared to return dict[str, dict[str, Any]], and ConstraintManagerBase.from_graph_schema expects dict[str, dict[str, type[BaseModel]]]. For clearer mypy/ruff checks and less Any leakage, consider tightening get_graph_schema() (and optionally GRAPH_SCHEMA) to a compatible type such as:

-def get_graph_schema() -> dict[str, dict[str, Any]]:
+def get_graph_schema() -> dict[str, dict[str, type[Any]]]:

or even a type[BaseModel]–based signature if you want to reflect the actual classes used.

Also applies to: 264-264

backend/infrahub/core/graph/constraints.py (1)

179-208: from_graph_schema typing tightened appropriately; consider aligning GRAPH_SCHEMA producer

Changing from_graph_schema to accept dict[str, dict[str, type[BaseModel]]] and annotating properties_class as type[BaseModel] better reflects that the schema holds model classes and matches how model_fields is used.

To fully benefit from this, you may want get_graph_schema() / GRAPH_SCHEMA (in backend/infrahub/core/graph/schema.py) to expose compatible typing instead of Any for the inner type, so callers and this method agree on the schema shape.

.github/workflows/keyword-scan.yml (1)

19-23: Consider sourcing Python version from define-versions for consistency

Hard‑coding python-version: 3.14 is fine, but to avoid future drift from PYTHON_VERSION in define-versions.yml, consider wiring this workflow through the same prepare-environment indirection used elsewhere and reading ${{ needs.prepare-environment.outputs.PYTHON_VERSION }}.

backend/tests/unit/api/conftest.py (1)

2-3: Non‑singleton DB override in client fixture looks correct and consistent

Using dependency_provider: Provider plus an internal async _db(singleton: bool = True) -> InfrahubDatabase that delegates to build_database(singleton=False) and scoping it via with dependency_provider.scope(build_database, _db) ensures API tests get a fresh, non‑singleton InfrahubDatabase through the DI path without affecting other call sites. This aligns with the updated build_database(singleton: bool = True) contract and the global dependency_provider fixture in backend/tests/conftest.py.

If you want to make the intent clearer, you could add a short docstring on _db stating that the singleton argument is only there for signature compatibility and is intentionally ignored in favor of always returning a non‑singleton instance, but the current implementation is functionally sound.

Also applies to: 13-14, 18-26

backend/infrahub/workers/dependencies.py (1)

63-72: build_database(singleton: bool) implementation correctly separates singleton and non‑singleton paths

The revised build_database cleanly handles both cases:

  • not singleton → always constructs a new InfrahubDatabase and skips _singletons caching.
  • singleton with no cache → constructs, caches in _singletons["database"], and returns it.
  • singleton with cache present → returns the cached instance.

This preserves the previous singleton behavior for default callers while enabling tests (and other consumers) to opt out with singleton=False without mutating global state.

Given this is now part of the public DI surface, it would be helpful to add a short Google‑style docstring explaining the semantics of the singleton flag and that singleton=False is primarily intended for scoped/test usage.

backend/tests/conftest.py (1)

50-51: DB fixture’s DI‑based non‑singleton override and teardown look correct

The updated db fixture now:

  • Uses an internal async _db(singleton: bool = True) -> InfrahubDatabase that always calls build_database(singleton=False), ensuring non‑singleton instances for tests.
  • Wraps its body in with provider.scope(build_database, _db): and obtains the database via await get_database(), so any DI path depending on build_database within this scope transparently uses the overridden factory.
  • Calls await add_indexes(db=driver) before yielding and await driver.close() afterwards, which keeps index setup and connection teardown explicit.

This pattern is consistent with the new build_database(singleton) API and the other test helpers. If you want to further clarify intent, you could add a brief comment or docstring on _db noting that singleton is present solely for signature compatibility with build_database.

Also applies to: 59-59, 125-147

backend/tests/helpers/test_app.py (1)

33-34: Scoped build_database override in test_client matches the new DI pattern

Importing build_database here and updating the test_client fixture to:

  • Accept dependency_provider: Provider and db: InfrahubDatabase (ensuring the global db fixture runs and the backing DB is initialised/indexed), and
  • Define _db(singleton: bool = True) -> InfrahubDatabase delegating to build_database(singleton=False), used within with dependency_provider.scope(build_database, _db): async with lifespan(app): ...

gives the FastAPI app a non‑singleton InfrahubDatabase through the same DI mechanism used in production code while still relying on the shared test DB server configuration.

This is consistent with the db fixture changes in backend/tests/conftest.py. As in other places, the unused singleton argument in _db is there for signature compatibility; if you find it confusing, a short comment/docstring could make that intent explicit, but the current behavior is sound.

Also applies to: 139-159

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1651099 and 9976fef.

⛔ Files ignored due to path filters (1)
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (37)
  • .devcontainer/Dockerfile (1 hunks)
  • .github/workflows/ci.yml (17 hunks)
  • .github/workflows/define-versions.yml (1 hunks)
  • .github/workflows/keyword-scan.yml (1 hunks)
  • .github/workflows/publish-pypi.yml (1 hunks)
  • .github/workflows/release.yml (1 hunks)
  • .github/workflows/update-compose-file-and-chart.yml (1 hunks)
  • .github/workflows/uv-check.yml (1 hunks)
  • .github/workflows/version-upgrade.yml (1 hunks)
  • backend/infrahub/cli/db.py (1 hunks)
  • backend/infrahub/core/diff/model/diff.py (1 hunks)
  • backend/infrahub/core/graph/constraints.py (1 hunks)
  • backend/infrahub/core/graph/schema.py (1 hunks)
  • backend/infrahub/core/models.py (5 hunks)
  • backend/infrahub/core/node/standard.py (1 hunks)
  • backend/infrahub/core/schema/attribute_schema.py (1 hunks)
  • backend/infrahub/core/schema/relationship_schema.py (1 hunks)
  • backend/infrahub/core/validators/determiner.py (2 hunks)
  • backend/infrahub/database/__init__.py (2 hunks)
  • backend/infrahub/workers/dependencies.py (1 hunks)
  • backend/tests/benchmark/conftest.py (3 hunks)
  • backend/tests/conftest.py (4 hunks)
  • backend/tests/helpers/test_app.py (2 hunks)
  • backend/tests/helpers/utils.py (1 hunks)
  • backend/tests/integration/diff/test_merge_rollback.py (1 hunks)
  • backend/tests/unit/api/conftest.py (2 hunks)
  • backend/tests/unit/api/test_50_internals.py (3 hunks)
  • backend/tests/unit/core/test_branch_rebase.py (1 hunks)
  • backend/tests/unit/git/conftest.py (1 hunks)
  • backend/tests/unit/git/test_git_repository.py (8 hunks)
  • backend/tests/unit/graphql/mutations/test_branch.py (1 hunks)
  • development/Dockerfile (1 hunks)
  • frontend/app/src/shared/api/rest/types.generated.ts (6 hunks)
  • pyproject.toml (5 hunks)
  • schema/openapi.json (7 hunks)
  • tasks/docs.py (2 hunks)
  • tasks/release.py (1 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
**/*.py

📄 CodeRabbit inference engine (.github/instructions/python-docstring.instructions.md)

**/*.py: Always use triple quotes (""") for Python docstrings
Follow Google-style docstring format for Python docstrings
Include brief one-line description in Python docstrings when applicable
Include detailed description in Python docstrings when applicable
Include Args/Parameters section without typing in Python docstrings when applicable
Include Returns section in Python docstrings when applicable
Include Raises section in Python docstrings when applicable
Include Examples section in Python docstrings when applicable

**/*.py: Use type hints for all function parameters and return values in Python
Use Async whenever possible in Python
Use async def for asynchronous functions in Python
Use await for asynchronous calls in Python
Use Pydantic models for dataclasses in Python
Use ruff and mypy for type checking and code validation in Python

Use ruff and mypy to validate and lint Python files

Files:

  • backend/infrahub/core/graph/schema.py
  • backend/infrahub/cli/db.py
  • backend/infrahub/core/schema/attribute_schema.py
  • backend/tests/unit/api/conftest.py
  • backend/infrahub/core/validators/determiner.py
  • backend/infrahub/core/node/standard.py
  • backend/tests/unit/api/test_50_internals.py
  • backend/tests/integration/diff/test_merge_rollback.py
  • backend/tests/unit/git/conftest.py
  • tasks/release.py
  • backend/tests/benchmark/conftest.py
  • backend/infrahub/core/graph/constraints.py
  • backend/tests/unit/core/test_branch_rebase.py
  • backend/tests/helpers/test_app.py
  • backend/infrahub/core/schema/relationship_schema.py
  • backend/infrahub/core/models.py
  • backend/infrahub/workers/dependencies.py
  • tasks/docs.py
  • backend/infrahub/core/diff/model/diff.py
  • backend/tests/helpers/utils.py
  • backend/tests/unit/git/test_git_repository.py
  • backend/tests/unit/graphql/mutations/test_branch.py
  • backend/infrahub/database/__init__.py
  • backend/tests/conftest.py
backend/infrahub/**/*.py

📄 CodeRabbit inference engine (backend/AGENTS.md)

backend/infrahub/**/*.py: Use async/await for all I/O operations to maintain async-first architecture
Type hint all function parameters and returns in Python code
Use Pydantic models for defining data structures instead of plain dictionaries
Use Query class pattern (extending infrahub.core.query.Query) for all database operations instead of unparameterized Cypher queries
Use Google-style docstrings with Args, Returns, and Raises sections for all functions
Use snake_case for function and variable names
Use PascalCase for class names
Use UPPER_SNAKE_CASE for constant definitions
Do not use unparameterized Cypher queries; always use parameterized queries to prevent injection
Do not block the event loop with synchronous I/O operations

Files:

  • backend/infrahub/core/graph/schema.py
  • backend/infrahub/cli/db.py
  • backend/infrahub/core/schema/attribute_schema.py
  • backend/infrahub/core/validators/determiner.py
  • backend/infrahub/core/node/standard.py
  • backend/infrahub/core/graph/constraints.py
  • backend/infrahub/core/schema/relationship_schema.py
  • backend/infrahub/core/models.py
  • backend/infrahub/workers/dependencies.py
  • backend/infrahub/core/diff/model/diff.py
  • backend/infrahub/database/__init__.py
backend/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Use type hints for all Python code in the backend

Files:

  • backend/infrahub/core/graph/schema.py
  • backend/infrahub/cli/db.py
  • backend/infrahub/core/schema/attribute_schema.py
  • backend/tests/unit/api/conftest.py
  • backend/infrahub/core/validators/determiner.py
  • backend/infrahub/core/node/standard.py
  • backend/tests/unit/api/test_50_internals.py
  • backend/tests/integration/diff/test_merge_rollback.py
  • backend/tests/unit/git/conftest.py
  • backend/tests/benchmark/conftest.py
  • backend/infrahub/core/graph/constraints.py
  • backend/tests/unit/core/test_branch_rebase.py
  • backend/tests/helpers/test_app.py
  • backend/infrahub/core/schema/relationship_schema.py
  • backend/infrahub/core/models.py
  • backend/infrahub/workers/dependencies.py
  • backend/infrahub/core/diff/model/diff.py
  • backend/tests/helpers/utils.py
  • backend/tests/unit/git/test_git_repository.py
  • backend/tests/unit/graphql/mutations/test_branch.py
  • backend/infrahub/database/__init__.py
  • backend/tests/conftest.py
backend/tests/**/*.py

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Run backend tests with pytest or via invoke tasks

Name test files as test_<module>.py and mirror source structure in tests directory

Files:

  • backend/tests/unit/api/conftest.py
  • backend/tests/unit/api/test_50_internals.py
  • backend/tests/integration/diff/test_merge_rollback.py
  • backend/tests/unit/git/conftest.py
  • backend/tests/benchmark/conftest.py
  • backend/tests/unit/core/test_branch_rebase.py
  • backend/tests/helpers/test_app.py
  • backend/tests/helpers/utils.py
  • backend/tests/unit/git/test_git_repository.py
  • backend/tests/unit/graphql/mutations/test_branch.py
  • backend/tests/conftest.py
frontend/app/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use TypeScript types for all frontend code

Files:

  • frontend/app/src/shared/api/rest/types.generated.ts
{pyproject.toml,uv.lock}

📄 CodeRabbit inference engine (.github/instructions/tooling.instructions.md)

Use uv to manage the Python project and its dependencies

Files:

  • pyproject.toml
🧠 Learnings (9)
📚 Learning: 2025-11-18T08:30:19.721Z
Learnt from: fatih-acar
Repo: opsmill/infrahub PR: 7669
File: .github/workflows/update-compose-file-and-chart.yml:52-53
Timestamp: 2025-11-18T08:30:19.721Z
Learning: The `uv version` command returns the project version from pyproject.toml (since astral-sh/uv PR #12349). Use `uv version --short` to extract project version for version checks and comparisons in workflows. The old behavior (showing UV's own tool version) is now `uv self version`.

Applied to files:

  • .github/workflows/uv-check.yml
📚 Learning: 2025-12-01T22:15:47.401Z
Learnt from: CR
Repo: opsmill/infrahub PR: 0
File: .github/instructions/tooling.instructions.md:0-0
Timestamp: 2025-12-01T22:15:47.401Z
Learning: Applies to {pyproject.toml,uv.lock} : Use uv to manage the Python project and its dependencies

Applied to files:

  • .github/workflows/uv-check.yml
  • .github/workflows/release.yml
  • .github/workflows/update-compose-file-and-chart.yml
  • .github/workflows/version-upgrade.yml
  • .github/workflows/ci.yml
📚 Learning: 2025-12-01T22:15:34.303Z
Learnt from: CR
Repo: opsmill/infrahub PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-01T22:15:34.303Z
Learning: Applies to backend/pyproject.toml : Use `uv` for dependency management in backend Python projects

Applied to files:

  • .github/workflows/uv-check.yml
  • .github/workflows/release.yml
  • .github/workflows/update-compose-file-and-chart.yml
  • .github/workflows/version-upgrade.yml
  • .github/workflows/ci.yml
  • pyproject.toml
📚 Learning: 2025-12-01T22:16:13.680Z
Learnt from: CR
Repo: opsmill/infrahub PR: 0
File: backend/AGENTS.md:0-0
Timestamp: 2025-12-01T22:16:13.680Z
Learning: Applies to backend/infrahub/core/schema/generated/**/*.py : Do not edit files in `infrahub/core/schema/generated/` as they are auto-generated

Applied to files:

  • backend/infrahub/core/schema/attribute_schema.py
📚 Learning: 2025-12-02T08:57:42.248Z
Learnt from: CR
Repo: opsmill/infrahub PR: 0
File: docs/docs/topics/AGENTS.md:0-0
Timestamp: 2025-12-02T08:57:42.248Z
Learning: Applies to docs/docs/topics/**/topics/**/*.mdx : Use consistent Infrahub terminology: 'Branch' (not 'workspace' or 'environment'), 'Schema' (not 'model definition'), 'Proposed change' (not 'pull request'), 'Attribute' (not 'field' or 'property')

Applied to files:

  • tasks/docs.py
📚 Learning: 2025-12-01T22:16:13.680Z
Learnt from: CR
Repo: opsmill/infrahub PR: 0
File: backend/AGENTS.md:0-0
Timestamp: 2025-12-01T22:16:13.680Z
Learning: Applies to backend/infrahub/**/*.py : Use Query class pattern (extending infrahub.core.query.Query) for all database operations instead of unparameterized Cypher queries

Applied to files:

  • backend/infrahub/database/__init__.py
📚 Learning: 2025-12-01T22:16:13.680Z
Learnt from: CR
Repo: opsmill/infrahub PR: 0
File: backend/AGENTS.md:0-0
Timestamp: 2025-12-01T22:16:13.680Z
Learning: Applies to backend/infrahub/**/*.py : Type hint all function parameters and returns in Python code

Applied to files:

  • pyproject.toml
📚 Learning: 2025-12-01T22:16:13.680Z
Learnt from: CR
Repo: opsmill/infrahub PR: 0
File: backend/AGENTS.md:0-0
Timestamp: 2025-12-01T22:16:13.680Z
Learning: Applies to backend/infrahub/**/*.py : Use PascalCase for class names

Applied to files:

  • pyproject.toml
📚 Learning: 2025-12-01T22:16:13.680Z
Learnt from: CR
Repo: opsmill/infrahub PR: 0
File: backend/AGENTS.md:0-0
Timestamp: 2025-12-01T22:16:13.680Z
Learning: Applies to backend/infrahub/**/*.py : Use UPPER_SNAKE_CASE for constant definitions

Applied to files:

  • pyproject.toml
🧬 Code graph analysis (9)
backend/infrahub/core/graph/schema.py (1)
backend/infrahub/types.py (1)
  • Any (312-319)
backend/infrahub/cli/db.py (1)
backend/infrahub/core/graph/schema.py (5)
  • GraphNodeProperties (37-45)
  • GraphRelationshipProperties (81-84)
  • GraphAttributeProperties (112-115)
  • GraphRelationshipIsPartOf (216-219)
  • GraphRelationshipDefault (222-234)
backend/tests/unit/api/conftest.py (3)
backend/infrahub/workers/dependencies.py (3)
  • build_database (63-72)
  • build_message_bus (93-100)
  • build_workflow (119-126)
backend/tests/unit/git/conftest.py (1)
  • client (31-32)
backend/tests/conftest.py (2)
  • dependency_provider (121-122)
  • _db (137-138)
backend/infrahub/core/validators/determiner.py (1)
backend/infrahub/core/schema/attribute_parameters.py (1)
  • AttributeParameters (24-25)
backend/tests/unit/api/test_50_internals.py (1)
backend/tests/unit/api/conftest.py (1)
  • client (18-26)
backend/tests/unit/core/test_branch_rebase.py (2)
backend/tests/conftest.py (1)
  • db (126-146)
backend/infrahub/workers/dependencies.py (1)
  • build_database (63-72)
backend/infrahub/workers/dependencies.py (1)
backend/tests/conftest.py (1)
  • db (126-146)
backend/tests/unit/graphql/mutations/test_branch.py (2)
backend/tests/conftest.py (2)
  • dependency_provider (121-122)
  • db (126-146)
backend/infrahub/workers/dependencies.py (1)
  • build_database (63-72)
backend/tests/conftest.py (2)
backend/infrahub/database/__init__.py (2)
  • InfrahubDatabase (141-445)
  • close (310-311)
backend/infrahub/workers/dependencies.py (2)
  • build_database (63-72)
  • get_database (76-77)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Cloudflare Pages
🔇 Additional comments (47)
backend/tests/integration/diff/test_merge_rollback.py (1)

34-45: LGTM! Fixes infinite recursion in test fixture.

Storing the original merge_graph method reference before replacing it (line 37) and then calling the stored reference (line 44) prevents infinite recursion. Without this change, line 44 would call the already-patched self.real_merger.diff_merger.merge_graph, which points back to self.merge_graph (set on line 38), creating an infinite loop.

The updated pattern correctly implements method wrapping: store original → replace with wrapper → wrapper calls stored original.

backend/tests/unit/git/conftest.py (1)

612-617: LGTM! Proper mock reusability configuration.

The is_reusable=True flag is appropriate here since the mock response uses a regex pattern that matches multiple branches and is likely consumed by multiple tests.

backend/tests/unit/git/test_git_repository.py (3)

481-481: LGTM! Selective mocking for prefect requests.

The decorator correctly filters out prefect-originated requests from mocking, allowing the test infrastructure to function properly while still mocking application HTTP calls.


506-506: LGTM! Mock reusability configured appropriately.

The is_reusable=True flag on the admin status mutation mock enables it to be matched multiple times during test execution.


582-582: LGTM! Consistent selective mocking across prefect-enabled tests.

The httpx_mock decorators are uniformly applied across all tests that use the prefect_test_fixture, ensuring that prefect infrastructure requests are not mocked while application HTTP calls remain under test control.

Also applies to: 644-644, 667-667, 703-703, 737-737, 773-773

tasks/release.py (1)

407-420: Class-level model_fields usage in gen_config_env looks good

Iterating over subset.__class__.model_fields keeps the recursion and env/default extraction logic unchanged while aligning with class-based metadata access used elsewhere. No issues spotted.

backend/infrahub/cli/db.py (1)

606-619: Tuple-based graph_*_schemas and variable renames are fine

Using tuples for graph_node_schemas / graph_edge_schemas and more specific loop variables is a readability win with no behavioral change; property extraction from model_fields remains the same.

tasks/docs.py (2)

200-210: Class-level parameters.model_fields access is appropriate

Iterating over init_schema.parameters.__class__.model_fields still examines the same parameter fields while relying on class metadata, which is consistent with other Pydantic-2-oriented changes. The filtering by json_schema_extra["update"] == "validate_constraint" is preserved.


494-505: _get_env_vars now correctly relies on settings class metadata

Using settings.__class__.model_fields.items() keeps env-var discovery semantics intact and makes the introspection independent of instance state. The mapping into env_vars remains unchanged.

backend/infrahub/core/schema/attribute_schema.py (1)

169-176: update_from_generic’s switch to class-level model_fields is fine

Looping over self.__class__.model_fields instead of self.model_fields keeps the update semantics identical while relying on class metadata, matching the pattern used elsewhere in the codebase.

backend/infrahub/core/node/standard.py (1)

257-288: to_db using self.class.model_fields matches existing from_db usage

The switch to iterating over self.__class__.model_fields keeps the to_db serialization behavior the same and is consistent with from_db, which already uses class-level model_fields. No issues found.

backend/infrahub/core/diff/model/diff.py (1)

21-35: BaseDiffElement.to_graphql class-level model_fields access is correct

Resolving field_info via self.__class__.model_fields[key] maintains the existing export logic (exclude handling, Enum/Timestamp/Node conversions) while using class metadata as intended. Looks good.

backend/infrahub/core/schema/relationship_schema.py (1)

84-91: Class-level model_fields usage in update_from_generic looks correct

Iterating over self.__class__.model_fields keeps behavior consistent with the rest of the codebase and Pydantic’s class-level field metadata; no functional issues spotted.

backend/infrahub/core/validators/determiner.py (2)

96-134: Schema property constraint introspection remains sound with class-level model_fields

Using schema.__class__.model_fields.items() for constraint discovery keeps the logic aligned with how fields are declared on the schema type and matches the broader refactor in this PR; no behavioral issues identified.


156-169: Field/parameter constraint discovery correctly moved to class-level model_fields

Switching to field.__class__.model_fields and p_value.__class__.model_fields preserves the existing semantics while ensuring parameter fields from subclasses (e.g., specific AttributeParameters variants) are included; try/except still safely handles missing metadata.

schema/openapi.json (4)

979-1102: GraphQL query response schemas correctly widened via additionalProperties: true

Allowing arbitrary top-level keys in the GraphQL query POST/GET 200 responses matches the dynamic nature of GraphQL results and aligns with the widened frontend types; no API surface change beyond more accurate documentation.


3971-3974: ComputedAttribute-Output now models an open object, which matches usage

Defining it as { "type": "object", "additionalProperties": true } correctly reflects that computed attributes may emit arbitrary key/value pairs; this improves spec accuracy without tightening server behavior.


4478-4583: JSONSchema meta-schema relaxed to accept arbitrary nested schema properties

Adding "additionalProperties": true to the various JSONSchema object/array contexts (properties, items, nested items, and additionalProperties branch) reflects real JSON Schema flexibility and avoids over-constraining tooling generated from this OpenAPI definition; looks intentional and consistent.


5305-5315: QueryPayload.variables correctly modeled as a free-form map

Changing variables to { "type": "object", "additionalProperties": true } matches GraphQL’s Record<string, any> variable bag and aligns with the TS client widening; this is a good compatibility improvement.

backend/infrahub/core/models.py (5)

260-307: Constraint routing now uses class-level field metadata; logic unchanged

Using field.__class__.model_fields[prop_name] and then prop_field.__class__.model_fields[param_field_name] keeps the existing constraint-routing behavior while standardizing on class-based field metadata; the surrounding try/except still gracefully handles missing or non-model parameter fields.


308-325: Node-level attribute constraint resolution correctly uses schema.__class__.model_fields

Looking up node_field_name via schema.__class__.model_fields is consistent with the rest of the refactor and still drives _process_field off the same json_schema_extra["update"] hints as before; no functional regression spotted.


417-443: Hash computation over self.__class__.model_fields remains deterministic and compatible

Iterating over sorted(self.__class__.model_fields.keys()) keeps the hash derivation ordered and based solely on declared model fields, matching prior behavior while standardizing on class-level metadata; no new edge cases identified given extra="forbid" usage in these models.


569-607: update now iterates class-level fields of other; semantics are preserved

Looping over other.__class__.model_fields.keys() matches the previous intent of only considering declared model fields, and the existing guards (hasattr(self, field_name), type checks, list/HashableModel handling) remain unchanged; cross-type updates should behave as before.


615-617: Diff field-name discovery via class-level model_fields is consistent with hashing/updating

Returning list(self.__class__.model_fields.keys()) for _get_field_names_for_diff keeps diff computation aligned with the same declared field set used by get_hash and update, which is desirable for consistent change detection.

frontend/app/src/shared/api/rest/types.generated.ts (4)

1306-1308: Looser but still type‑safe ComputedAttribute-Output looks appropriate

Widening ComputedAttribute-Output to { [key: string]: unknown } better reflects a dynamic payload while keeping type safety via unknown instead of any. Given this is generated code, this shape is reasonable and matches TypeScript best practices.


1536-1538: JSONSchema field widening matches generic JSON Schema semantics

Using { [key: string]: unknown } for properties, items, and additionalProperties aligns better with real JSON Schema objects than the previous “no props” shape, while still avoiding any. This should make consumers’ intent clearer without sacrificing type safety.

Also applies to: 1543-1547, 1562-1564


1927-1929: QueryPayload.variables as a generic map is a sensible GraphQL model

Typing variables as { [key: string]: unknown } matches how GraphQL variables are used in practice and keeps things type‑safe (consumers must narrow). This is a good improvement over an effectively empty record.


2827-2829: Generic GraphQL response maps are reasonable given dynamic query shapes

Modeling the GraphQL 200 "application/json" bodies as { [key: string]: unknown } is pragmatic since the schema can’t express per‑query shapes. This pairs well with the widened QueryPayload.variables; consumers that need stronger typing can define narrower interfaces at call sites.

Also applies to: 2874-2876

development/Dockerfile (1)

4-4: Dev image Python version aligned with 3.14.2 baseline

Using ARG PYTHON_VER=3.14.2 matches the centralized PYTHON_VERSION output and the devcontainer image; this keeps local dev and CI images consistent.

.devcontainer/Dockerfile (1)

1-1: Devcontainer base image correctly moved to Python 3.14.2

Pinning to python:3.14.2 keeps the devcontainer in sync with the development Dockerfile and the workflow PYTHON_VERSION output, avoiding “works in container but not in CI” drift.

backend/tests/helpers/utils.py (1)

47-52: Prefect test container tag aligned with Python 3.14

Switching to prefecthq/prefect:3.5.0-python3.14 matches the project’s Python baseline and the pinned prefect==3.5.0 dependency, so Prefect tests run against the same major/minor runtime as the rest of the stack.

.github/workflows/define-versions.yml (1)

7-10: Centralized PYTHON_VERSION output looks good

Adding PYTHON_VERSION: "3.14.2" here gives a single source of truth that other workflows can consume, keeping CI, Docker images, and requires-python in sync.

backend/tests/benchmark/conftest.py (1)

2-22: Async benchmark helpers updated for newer pytest‑asyncio; double‑check event loop behavior

Using inspect.iscoroutinefunction and dropping the event_loop fixture in favor of asyncio.get_event_loop().run_until_complete(...) matches pytest‑asyncio’s newer patterns and should keep these fixtures working under pytest 9.x. However, this now depends on a globally available loop (especially with asyncio_default_fixture_loop_scope = "session"), and synchronous callers of exec_async / aio_benchmark will fail if no loop is set.

Please verify that:

  • Both sync and async tests using these fixtures still behave as expected under Python 3.14 with the new pytest/pytest‑asyncio versions.
  • There are no call sites passing coroutine objects instead of coroutine functions, since the iscoroutinefunction check would skip those.

Also applies to: 25-38

pyproject.toml (3)

6-16: Python version metadata matches the 3.14 rollout

Updating requires-python to >=3.12,<3.15 and adding classifiers for 3.13 and 3.14 is consistent with the Docker images and workflow PYTHON_VERSION output, and keeps 3.15+ explicitly out until tested.


18-21: Dependency and uv source updates look coherent; confirm compatibility is fully captured in uv.lock

The dependency bumps (e.g. pydantic>=2.12,<2.13, pytest>=9.0,<9.1, pytest-asyncio>=1.3,<1.4, updated OpenTelemetry exporters/instrumentation, aiodataloader==0.4.3, fast-depends==3.0.5, prefect-redis==0.2.7, asyncpg==0.31.0) and the move to git‑backed neo4j / neo4j-rust-ext via [tool.uv.sources] align with the code changes (e.g. new Neo4j notification API) and the “use uv for dependency management” guideline. Based on learnings, this is the right direction.

Given that some deps now have wide or no upper bounds (neo4j via VCS, pyarrow>=14, numpy>=1.26.2), please make sure:

  • uv.lock pins concrete versions/commits for all of these so CI and production are reproducible.
  • The pinned neo4j version is the one that supports NotificationDisabledClassification and notifications_disabled_classifications used in backend/infrahub/database/__init__.py.
  • The newer pytest/pytest‑asyncio and OpenTelemetry versions don’t introduce breaking changes in existing tests or telemetry setup.

Also applies to: 23-24, 31-33, 34-34, 41-47, 47-55, 59-61, 63-70, 77-82, 84-115


89-90: Pytest asyncio configuration and dev deps align with new fixtures; validate end‑to‑end

Bumping pytest-asyncio to >=1.3,<1.4 and adding asyncio_default_fixture_loop_scope = "session" in [tool.pytest.ini_options] matches the fixture changes in backend/tests/benchmark/conftest.py and the switch away from the deprecated event_loop fixture. This should reduce flakiness but also means a single loop is reused widely.

Please run the test suite under Python 3.14 to confirm:

  • No deprecation/runtime warnings from pytest‑asyncio regarding fixture modes.
  • Fixtures like exec_async / aio_benchmark and any others relying on the event loop behave correctly with a session‑scoped loop (no cross‑test interference).

Also applies to: 143-147

backend/infrahub/database/__init__.py (1)

16-23: Neo4j notification config correctly migrated to NotificationDisabledClassification

The import and driver initialization at lines 16-23 and 490-499 are correct. The migration from the old NotificationDisabledCategory API to the new NotificationDisabledClassification is complete across the codebase, with no stale references remaining. The Neo4j Python driver version (sourced from the latest git repository) supports this API signature.

.github/workflows/release.yml (1)

28-33: Use of centralized PYTHON_VERSION output in release workflow looks correct

check_release already needs: prepare-environment, so switching python-version to ${{ needs.prepare-environment.outputs.PYTHON_VERSION }} keeps things consistent with other workflows and avoids hard‑coding. No further changes needed.

.github/workflows/version-upgrade.yml (1)

55-63: Version‑upgrade workflow now correctly follows centralized Python version

migration-tests depends on prepare-environment, so using ${{ needs.prepare-environment.outputs.PYTHON_VERSION }} for actions/setup-python is safe and aligns with the new single‑source versioning.

.github/workflows/update-compose-file-and-chart.yml (1)

36-45: Dynamic Python version in compose/chart updater is consistent with tooling approach

Using ${{ needs.prepare-environment.outputs.PYTHON_VERSION }} here matches the central version definition and the uv‑based workflow everywhere else. This reduces drift between CI and dev images.

.github/workflows/publish-pypi.yml (1)

41-46: Publish‑to‑PyPI job correctly switched to the shared Python version

Referencing ${{ needs.prepare-environment.outputs.PYTHON_VERSION }} for actions/setup-python keeps package builds aligned with the defined project Python version; the rest of the uv‑based flow is unchanged.

backend/tests/unit/core/test_branch_rebase.py (1)

93-103: DB override lambda now correctly matches build_database’s singleton signature

Adapting the override to lambda singleton=True: db makes it compatible with build_database(singleton: bool = True) while still forcing use of the injected db instance. This keeps the test insulated from the global singleton cache and is consistent with the new dependency pattern shown in backend/tests/conftest.py.

backend/tests/unit/api/test_50_internals.py (1)

96-101: Using with client: around TestClient calls is an improvement

Wrapping the client.get calls in with client: for the search docs tests ensures proper TestClient lifecycle management and resource cleanup in these async tests, consistent with how other tests in this file already use the context manager.

Also applies to: 107-116, 118-128

.github/workflows/ci.yml (1)

82-87: Centralizing CI Python version via prepare-environment outputs is coherent across jobs

All updated actions/setup-python@v6 steps now use ${{ needs.prepare-environment.outputs.PYTHON_VERSION }}, and each of those jobs already lists prepare-environment in needs, so the output is available at runtime. This keeps linting, tests, docs, E2E, benchmarks, and even the commented‑out memgraph job aligned on the same Python version and avoids future drift from hard‑coded values.

Also applies to: 170-175, 248-253, 347-352, 401-406, 448-453, 498-503, 542-543, 567-570, 600-604, 666-670, 692-696, 729-733, 766-770, 881-885, 1057-1062, 1153-1157

backend/tests/unit/graphql/mutations/test_branch.py (1)

276-287: local_services DB override now matches build_database’s call signature

Updating the scope override to lambda singleton=True: db keeps the behavior (“reuse this test db instance”) while making it signature‑compatible with build_database(singleton: bool = True). This aligns with the new DI pattern and should avoid surprises if the provider starts passing singleton explicitly.

.github/workflows/uv-check.yml (1)

12-16: Aligning python-version with prepare-environment output is the right move

Switching actions/setup-python to python-version: ${{ needs.prepare-environment.outputs.PYTHON_VERSION }} keeps this workflow in sync with the centrally defined Python version (3.14.2) and mirrors how UV_VERSION is already sourced from the same job. Just double‑check that define-versions.yml actually exposes the output under the exact key PYTHON_VERSION so this continues to resolve correctly. Based on learnings, this also keeps uv and Python versions aligned.

Also applies to: 23-29

backend/tests/conftest.py (1)

13-14: Automatic session‑scoped asyncio marker for async tests is reasonable but may affect explicitly‑marked tests

Using pytest_collection_modifyitems with pytest_asyncio.is_async_test(item) to apply pytest.mark.asyncio(loop_scope="session") centralizes loop configuration and removes the need for a custom session‑loop fixture, which is a nice cleanup.

One thing to keep in mind: tests that already declare their own @pytest.mark.asyncio(...) (e.g. with loop_scope="function" or "module") will now receive an additional marker. That may or may not be what you want depending on how pytest‑asyncio resolves multiple markers, so it’s worth scanning for such tests and verifying that their intended loop scope is preserved.

Also applies to: 113-118

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (5)
backend/tests/unit/git/test_git_repository.py (1)

481-481: Extract the repeated decorator to reduce duplication.

The @pytest.mark.httpx_mock decorator with the identical should_mock lambda is repeated across 7 test functions (lines 481, 582, 644, 667, 703, 737, 773). While functionally correct, this creates maintenance burden if the filtering logic changes.

Define a module-level constant instead:

# At module level, near line 43
HTTPX_MOCK_SHOULD_MOCK = lambda request: "prefect" not in request.headers.get("User-Agent", "")

# Then use in tests:
@pytest.mark.httpx_mock(should_mock=HTTPX_MOCK_SHOULD_MOCK)
async def test_sync_new_branch(...):

Alternatively, if this pattern is used across multiple test files, consider creating a custom pytest marker.

backend/tests/unit/core/test_branch_rebase.py (1)

101-102: Consider extracting the dependency scoping pattern into a reusable helper.

The comment indicates this scoping pattern could benefit other tests. Consider creating a test fixture or helper function that provides this scoped database pattern.

Would you like me to generate a reusable helper implementation or open an issue to track this refactoring?

pyproject.toml (1)

81-82: Document the rationale for neo4j git-based sources.

The neo4j and neo4j-rust-ext dependencies use git sources pointing to specific commits in forks rather than upstream PyPI releases. While this provides reproducibility, it's non-standard and may complicate dependency resolution or maintenance. Clarify in code comments or documentation:

  • Why forks are necessary (features not in upstream? bug fixes?)
  • Whether upstream releases will be used in the future
  • Any compatibility considerations for these specific commits
backend/tests/conftest.py (1)

137-146: Consider removing or using the singleton parameter in the _db factory.

The internal _db factory function accepts a singleton parameter with a default value of True, but it's never used—build_database(singleton=False) is always called. This could be confusing to future maintainers.

Apply this diff to remove the unused parameter:

-    async def _db(singleton: bool = True) -> InfrahubDatabase:
+    async def _db() -> InfrahubDatabase:
         return await build_database(singleton=False)

Alternatively, if the parameter is intended for future use or interface consistency, pass it through:

     async def _db(singleton: bool = True) -> InfrahubDatabase:
-        return await build_database(singleton=False)
+        return await build_database(singleton=singleton)
backend/tests/helpers/test_app.py (1)

153-158: Consider removing or using the singleton parameter in the _db factory.

Similar to the pattern in backend/tests/conftest.py, the internal _db factory function accepts a singleton parameter that is never used. The function always calls build_database(singleton=False) regardless of the parameter value.

Apply this diff to remove the unused parameter:

-        async def _db(singleton: bool = True) -> InfrahubDatabase:
+        async def _db() -> InfrahubDatabase:
             return await build_database(singleton=False)

Alternatively, if the parameter is intended for interface consistency with build_database, pass it through:

         async def _db(singleton: bool = True) -> InfrahubDatabase:
-            return await build_database(singleton=False)
+            return await build_database(singleton=singleton)
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9976fef and 80f26c5.

⛔ Files ignored due to path filters (1)
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (31)
  • .devcontainer/Dockerfile (1 hunks)
  • .github/workflows/ci.yml (17 hunks)
  • .github/workflows/define-versions.yml (1 hunks)
  • .github/workflows/publish-pypi.yml (1 hunks)
  • .github/workflows/release.yml (1 hunks)
  • .github/workflows/update-compose-file-and-chart.yml (1 hunks)
  • .github/workflows/uv-check.yml (1 hunks)
  • .github/workflows/version-upgrade.yml (1 hunks)
  • backend/infrahub/cli/db.py (1 hunks)
  • backend/infrahub/core/diff/model/diff.py (1 hunks)
  • backend/infrahub/core/graph/constraints.py (1 hunks)
  • backend/infrahub/core/graph/schema.py (2 hunks)
  • backend/infrahub/core/models.py (5 hunks)
  • backend/infrahub/core/node/standard.py (1 hunks)
  • backend/infrahub/core/schema/attribute_schema.py (1 hunks)
  • backend/infrahub/core/schema/relationship_schema.py (1 hunks)
  • backend/infrahub/core/validators/determiner.py (2 hunks)
  • backend/infrahub/database/__init__.py (2 hunks)
  • backend/tests/benchmark/conftest.py (3 hunks)
  • backend/tests/conftest.py (4 hunks)
  • backend/tests/helpers/test_app.py (2 hunks)
  • backend/tests/integration/diff/test_merge_rollback.py (1 hunks)
  • backend/tests/unit/api/conftest.py (2 hunks)
  • backend/tests/unit/core/test_branch_rebase.py (1 hunks)
  • backend/tests/unit/git/conftest.py (1 hunks)
  • backend/tests/unit/git/test_git_repository.py (8 hunks)
  • backend/tests/unit/graphql/mutations/test_branch.py (1 hunks)
  • development/Dockerfile (1 hunks)
  • pyproject.toml (5 hunks)
  • tasks/docs.py (2 hunks)
  • tasks/release.py (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (18)
  • tasks/docs.py
  • .github/workflows/version-upgrade.yml
  • backend/tests/unit/api/conftest.py
  • backend/infrahub/core/validators/determiner.py
  • backend/infrahub/core/graph/constraints.py
  • .github/workflows/update-compose-file-and-chart.yml
  • .github/workflows/publish-pypi.yml
  • tasks/release.py
  • backend/tests/unit/git/conftest.py
  • backend/infrahub/core/graph/schema.py
  • backend/infrahub/cli/db.py
  • backend/tests/unit/graphql/mutations/test_branch.py
  • backend/infrahub/core/schema/relationship_schema.py
  • .github/workflows/release.yml
  • backend/tests/benchmark/conftest.py
  • backend/tests/integration/diff/test_merge_rollback.py
  • .devcontainer/Dockerfile
  • backend/infrahub/core/schema/attribute_schema.py
🧰 Additional context used
📓 Path-based instructions (5)
**/*.py

📄 CodeRabbit inference engine (.github/instructions/python-docstring.instructions.md)

**/*.py: Always use triple quotes (""") for Python docstrings
Follow Google-style docstring format for Python docstrings
Include brief one-line description in Python docstrings when applicable
Include detailed description in Python docstrings when applicable
Include Args/Parameters section without typing in Python docstrings when applicable
Include Returns section in Python docstrings when applicable
Include Raises section in Python docstrings when applicable
Include Examples section in Python docstrings when applicable

**/*.py: Use type hints for all function parameters and return values in Python
Use Async whenever possible in Python
Use async def for asynchronous functions in Python
Use await for asynchronous calls in Python
Use Pydantic models for dataclasses in Python
Use ruff and mypy for type checking and code validation in Python

Use ruff and mypy to validate and lint Python files

Files:

  • backend/infrahub/core/models.py
  • backend/infrahub/core/diff/model/diff.py
  • backend/tests/helpers/test_app.py
  • backend/infrahub/database/__init__.py
  • backend/tests/unit/core/test_branch_rebase.py
  • backend/tests/unit/git/test_git_repository.py
  • backend/infrahub/core/node/standard.py
  • backend/tests/conftest.py
backend/infrahub/**/*.py

📄 CodeRabbit inference engine (backend/AGENTS.md)

backend/infrahub/**/*.py: Use async/await for all I/O operations to maintain async-first architecture
Type hint all function parameters and returns in Python code
Use Pydantic models for defining data structures instead of plain dictionaries
Use Query class pattern (extending infrahub.core.query.Query) for all database operations instead of unparameterized Cypher queries
Use Google-style docstrings with Args, Returns, and Raises sections for all functions
Use snake_case for function and variable names
Use PascalCase for class names
Use UPPER_SNAKE_CASE for constant definitions
Do not use unparameterized Cypher queries; always use parameterized queries to prevent injection
Do not block the event loop with synchronous I/O operations

Files:

  • backend/infrahub/core/models.py
  • backend/infrahub/core/diff/model/diff.py
  • backend/infrahub/database/__init__.py
  • backend/infrahub/core/node/standard.py
backend/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Use type hints for all Python code in the backend

Files:

  • backend/infrahub/core/models.py
  • backend/infrahub/core/diff/model/diff.py
  • backend/tests/helpers/test_app.py
  • backend/infrahub/database/__init__.py
  • backend/tests/unit/core/test_branch_rebase.py
  • backend/tests/unit/git/test_git_repository.py
  • backend/infrahub/core/node/standard.py
  • backend/tests/conftest.py
backend/tests/**/*.py

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Run backend tests with pytest or via invoke tasks

Name test files as test_<module>.py and mirror source structure in tests directory

Files:

  • backend/tests/helpers/test_app.py
  • backend/tests/unit/core/test_branch_rebase.py
  • backend/tests/unit/git/test_git_repository.py
  • backend/tests/conftest.py
{pyproject.toml,uv.lock}

📄 CodeRabbit inference engine (.github/instructions/tooling.instructions.md)

Use uv to manage the Python project and its dependencies

Files:

  • pyproject.toml
🧠 Learnings (7)
📚 Learning: 2025-12-01T22:16:13.680Z
Learnt from: CR
Repo: opsmill/infrahub PR: 0
File: backend/AGENTS.md:0-0
Timestamp: 2025-12-01T22:16:13.680Z
Learning: Applies to backend/infrahub/**/*.py : Use Pydantic models for defining data structures instead of plain dictionaries

Applied to files:

  • backend/infrahub/core/models.py
📚 Learning: 2025-12-01T22:15:47.401Z
Learnt from: CR
Repo: opsmill/infrahub PR: 0
File: .github/instructions/tooling.instructions.md:0-0
Timestamp: 2025-12-01T22:15:47.401Z
Learning: Applies to {pyproject.toml,uv.lock} : Use uv to manage the Python project and its dependencies

Applied to files:

  • .github/workflows/ci.yml
  • .github/workflows/uv-check.yml
📚 Learning: 2025-12-01T22:15:34.303Z
Learnt from: CR
Repo: opsmill/infrahub PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-01T22:15:34.303Z
Learning: Applies to backend/pyproject.toml : Use `uv` for dependency management in backend Python projects

Applied to files:

  • .github/workflows/ci.yml
  • pyproject.toml
  • .github/workflows/uv-check.yml
📚 Learning: 2025-12-01T22:16:13.680Z
Learnt from: CR
Repo: opsmill/infrahub PR: 0
File: backend/AGENTS.md:0-0
Timestamp: 2025-12-01T22:16:13.680Z
Learning: Applies to backend/infrahub/**/*.py : Type hint all function parameters and returns in Python code

Applied to files:

  • pyproject.toml
📚 Learning: 2025-12-01T22:16:13.680Z
Learnt from: CR
Repo: opsmill/infrahub PR: 0
File: backend/AGENTS.md:0-0
Timestamp: 2025-12-01T22:16:13.680Z
Learning: Applies to backend/infrahub/**/*.py : Use PascalCase for class names

Applied to files:

  • pyproject.toml
📚 Learning: 2025-12-01T22:16:13.680Z
Learnt from: CR
Repo: opsmill/infrahub PR: 0
File: backend/AGENTS.md:0-0
Timestamp: 2025-12-01T22:16:13.680Z
Learning: Applies to backend/infrahub/**/*.py : Use UPPER_SNAKE_CASE for constant definitions

Applied to files:

  • pyproject.toml
📚 Learning: 2025-11-18T08:30:19.721Z
Learnt from: fatih-acar
Repo: opsmill/infrahub PR: 7669
File: .github/workflows/update-compose-file-and-chart.yml:52-53
Timestamp: 2025-11-18T08:30:19.721Z
Learning: The `uv version` command returns the project version from pyproject.toml (since astral-sh/uv PR #12349). Use `uv version --short` to extract project version for version checks and comparisons in workflows. The old behavior (showing UV's own tool version) is now `uv self version`.

Applied to files:

  • .github/workflows/uv-check.yml
🧬 Code graph analysis (3)
backend/tests/unit/core/test_branch_rebase.py (3)
backend/tests/conftest.py (2)
  • dependency_provider (121-122)
  • db (126-146)
backend/tests/helpers/test_app.py (1)
  • dependency_provider (80-81)
backend/infrahub/workers/dependencies.py (1)
  • build_database (63-72)
backend/tests/unit/git/test_git_repository.py (6)
backend/infrahub/message_bus/operations/send/echo.py (1)
  • request (10-16)
backend/infrahub/message_bus/operations/git/file.py (1)
  • get (14-35)
backend/infrahub/services/adapters/cache/__init__.py (1)
  • get (21-23)
backend/infrahub/services/adapters/cache/redis.py (1)
  • get (29-33)
backend/infrahub/services/adapters/cache/nats.py (1)
  • get (86-94)
backend/tests/adapters/cache.py (1)
  • get (13-14)
backend/tests/conftest.py (3)
backend/infrahub/workers/dependencies.py (2)
  • build_database (63-72)
  • get_database (76-77)
backend/tests/helpers/test_app.py (1)
  • _db (153-154)
backend/tests/unit/api/conftest.py (1)
  • _db (22-23)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (13)
  • GitHub Check: E2E-testing-playwright
  • GitHub Check: backend-benchmark
  • GitHub Check: backend-tests-unit
  • GitHub Check: backend-tests-integration
  • GitHub Check: backend-tests-functional
  • GitHub Check: json-schema
  • GitHub Check: graphql-schema
  • GitHub Check: validate-generated-documentation
  • GitHub Check: frontend-tests
  • GitHub Check: backend-docker-integration
  • GitHub Check: documentation
  • GitHub Check: backend-validate-generated
  • GitHub Check: Cloudflare Pages
🔇 Additional comments (14)
backend/tests/unit/git/test_git_repository.py (2)

506-506: LGTM! Response reusability configured appropriately.

The is_reusable=True parameter enables this mock response for mutation-repository-update-admin-status to be used across multiple requests, which appears correct if the admin status endpoint is called more than once during repo.sync(). The operational status mock at line 511 remains single-use, suggesting different request patterns for these endpoints.


481-520: Well-structured selective HTTP mocking improvements.

The changes successfully implement selective HTTP mocking that allows Prefect-related requests to pass through while mocking other HTTP traffic. This approach:

  • Aligns with the existing non_mocked_hosts fixture (line 45) targeting 127.0.0.1
  • Maintains test reliability by controlling which requests are mocked
  • Preserves all test logic and assertions unchanged
development/Dockerfile (1)

4-4: Python 3.14.2 and Docker image are available. The official Docker image python:3.14.2-slim-bookworm is published on Docker Hub, and Python 3.14.2 was released on December 5, 2025. The Dockerfile change is sound.

.github/workflows/define-versions.yml (1)

9-10: ✓ Centralizing Python version via workflow output.

Adding PYTHON_VERSION as a workflow output is a clean approach to maintain a single source of truth for Python versions across the CI/CD pipeline. This ensures consistency and simplifies future version updates.

.github/workflows/uv-check.yml (1)

25-25: ✓ Dynamic Python version reference correctly configured.

The workflow properly uses the centralized PYTHON_VERSION output from prepare-environment, with correct dependency declaration. This maintains consistency with the new versioning approach.

.github/workflows/ci.yml (1)

86-86: ✓ Consistent use of dynamic PYTHON_VERSION across all jobs.

All references to Python version have been properly updated to use the centralized needs.prepare-environment.outputs.PYTHON_VERSION output. The changes are consistent in syntax and properly depend on the prepare-environment job. The backend-testcontainers-unit matrix (lines 290–295) correctly retains hard-coded versions for multi-version testing, which is the right approach.

Also applies to: 174-174, 252-252, 351-351, 405-405, 452-452, 502-502, 603-603, 669-669, 695-695, 732-732, 769-769, 884-884, 1061-1061, 1156-1156

pyproject.toml (3)

145-145: This setting is already correctly implemented with proper test isolation.

The asyncio_default_fixture_loop_scope = "session" configuration in pyproject.toml is intentional and working as designed. Test isolation is maintained through fixture design:

  • Database isolation: The db fixture is module-scoped (not session), so each test module gets its own fresh database connection and state is cleared via the empty_database fixture (which calls delete_all_nodes and recreates the root node).
  • Registry isolation: The reset_registry fixture clears application state between tests.
  • Consistent async handling: The pytest_collection_modifyitems hook explicitly marks all async tests with session-scoped loop scope, ensuring consistent behavior.
  • Proper container scoping: Session-scoped infrastructure fixtures (neo4j, rabbitmq, redis, etc.) are correctly scoped since they manage containers, not test state.

Event loop scope (session) is independent of fixture scope (module/function), so state isolation is preserved. No test failures or isolation issues are evident in the codebase.


19-20: Remove or clarify the unpinned dependency concern — the git sources in [tool.uv.sources] already pin exact versions via revision hashes.

Lines 19–20 list neo4j and neo4j-rust-ext without version constraints in the dependencies list, but lines 81–82 define them in [tool.uv.sources] with explicit git revisions (rev hashes). This is correct uv usage and provides exact, reproducible versions. However, neo4j is sourced from a fork (fatih-acar/neo4j-python-driver) rather than the official repository, with no documentation explaining why. Consider adding a comment to clarify whether the fork is intentional and what it addresses, or confirm that the official neo4j/neo4j-python-driver should be used instead.

Likely an incorrect or invalid review comment.


23-23: Pytest 9.0 compatibility verified—no breaking changes detected.

The upgrade to pytest 9.0.x is complete and compatible with the codebase. All major plugins (pytest-asyncio 1.3+, pytest-cov 7.0.0, pytest-xdist 3.4+) support pytest 9. Custom plugins use only public APIs (no private config access), and Python 3.12+ requirement exceeds pytest 9's minimum. No fixture, assertion introspection, or plugin interaction issues identified.

backend/infrahub/core/diff/model/diff.py (1)

21-35: Class-level model_fields access in to_graphql looks correct

Using self.__class__.model_fields[key] keeps field metadata lookup on the class, matching Pydantic’s recommended access pattern and the wider refactor, without changing the filtering/serialization behavior for GraphQL export.

Please re-run the existing diff/GraphQL tests to confirm output remains byte-for-byte identical for representative models.

backend/infrahub/core/node/standard.py (1)

257-288: to_db now correctly uses class-level model_fields

Iterating over self.__class__.model_fields.items() cleanly ties the DB payload to the concrete model’s field definitions while preserving the existing exclusion and serialization logic.

Please make sure the StandardNode persistence tests (create/update round-trips) still pass under Python 3.14 in CI.

backend/infrahub/core/models.py (1)

260-307: Consistent normalization to class-level model_fields across schema and hash helpers

The switch to X.__class__.model_fields[...] in _process_attrs_rels, _process_node_attributes, get_hash, update, and _get_field_names_for_diff makes all schema-diff and HashableModel utilities depend on the concrete class’s field definitions, matching the rest of the refactor and Pydantic v2’s expectations. Error handling and diff/migration semantics remain the same.

Please run the schema update validation and hash/diff test suites (including any migration/validator selection tests) to confirm no behavioral deltas under Python 3.14.

Also applies to: 309-325, 417-443, 580-608, 615-639

backend/tests/conftest.py (1)

113-117: LGTM!

The pytest collection modifier correctly applies session-scoped asyncio markers to async tests, enabling proper async test execution.

backend/infrahub/database/__init__.py (1)

16-16: The import and usage of NotificationDisabledClassification are correct. This represents the current neo4j Python driver API; NotificationDisabledCategory is the deprecated predecessor. The implementation properly uses the new notifications_disabled_classifications parameter with the correct enum value.

ogenstad and others added 16 commits December 15, 2025 14:55
Some packages require an upgrade in order to install directly from
wheels.

Signed-off-by: Fatih Acar <[email protected]>
Post dependency w/ Py3.14 upgrade.

Signed-off-by: Fatih Acar <[email protected]>
Otherwise driver may get closed and fail with an error.

Signed-off-by: Fatih Acar <[email protected]>
This is required to remove py3.14 deprecation warnings.

Signed-off-by: Fatih Acar <[email protected]>
Required for py3.14 deprecation warnings.

Signed-off-by: Fatih Acar <[email protected]>
Also use stricter version pinning for Python.

Signed-off-by: Fatih Acar <[email protected]>
mypy typing issue.

Signed-off-by: Fatih Acar <[email protected]>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
backend/tests/conftest.py (1)

137-147: db fixture lifecycle via provider.scope is sound; consider clarifying _db override

The module-scoped db fixture now:

  • Adjusts config.SETTINGS for neo4j/memgraph.
  • Overrides build_database within provider.scope using the local async _db, which always calls build_database(singleton=False).
  • Acquires a database via await get_database(), adds indexes, yields it, and then closes it.

This cleanly encapsulates database setup/teardown and ensures tests don’t use the global singleton from build_database, which is appropriate for isolation.

One small clarity nit: _db(singleton: bool = True) ignores its singleton parameter and always passes singleton=False to build_database. If the intent is “never use the singleton in tests”, consider either:

  • Adding a short comment about intentionally forcing singleton=False, or
  • Forwarding the argument (return await build_database(singleton=singleton)) and letting the caller decide.

Functionally this is fine as-is, so treat this as a readability tweak rather than a blocker.

backend/infrahub/cli/db.py (1)

606-618: LGTM! Improved code clarity with tuples and descriptive names.

The changes improve code quality:

  • Using tuples instead of lists for immutable collections of schema classes is more appropriate
  • Renaming loop variables from generic graph_schema to specific graph_node_schema and graph_edge_schema improves readability
  • No functional impact

The same loop pattern appears in the load_export function (around line 762-775 based on context). Consider applying the same tuple and naming improvements there for consistency.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 80f26c5 and b96e0ab.

⛔ Files ignored due to path filters (1)
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (37)
  • .devcontainer/Dockerfile (1 hunks)
  • .github/workflows/ci.yml (17 hunks)
  • .github/workflows/define-versions.yml (1 hunks)
  • .github/workflows/keyword-scan.yml (1 hunks)
  • .github/workflows/publish-pypi.yml (1 hunks)
  • .github/workflows/release.yml (1 hunks)
  • .github/workflows/update-compose-file-and-chart.yml (1 hunks)
  • .github/workflows/uv-check.yml (1 hunks)
  • .github/workflows/version-upgrade.yml (1 hunks)
  • backend/infrahub/cli/db.py (1 hunks)
  • backend/infrahub/core/diff/model/diff.py (1 hunks)
  • backend/infrahub/core/graph/constraints.py (1 hunks)
  • backend/infrahub/core/graph/schema.py (2 hunks)
  • backend/infrahub/core/models.py (5 hunks)
  • backend/infrahub/core/node/standard.py (1 hunks)
  • backend/infrahub/core/schema/attribute_schema.py (1 hunks)
  • backend/infrahub/core/schema/relationship_schema.py (1 hunks)
  • backend/infrahub/core/validators/determiner.py (2 hunks)
  • backend/infrahub/database/__init__.py (2 hunks)
  • backend/infrahub/workers/dependencies.py (1 hunks)
  • backend/tests/benchmark/conftest.py (3 hunks)
  • backend/tests/conftest.py (4 hunks)
  • backend/tests/helpers/test_app.py (2 hunks)
  • backend/tests/helpers/utils.py (1 hunks)
  • backend/tests/integration/diff/test_merge_rollback.py (1 hunks)
  • backend/tests/unit/api/conftest.py (2 hunks)
  • backend/tests/unit/api/test_50_internals.py (3 hunks)
  • backend/tests/unit/core/test_branch_rebase.py (1 hunks)
  • backend/tests/unit/git/conftest.py (1 hunks)
  • backend/tests/unit/git/test_git_repository.py (8 hunks)
  • backend/tests/unit/graphql/mutations/test_branch.py (1 hunks)
  • development/Dockerfile (1 hunks)
  • frontend/app/src/shared/api/rest/types.generated.ts (6 hunks)
  • pyproject.toml (5 hunks)
  • schema/openapi.json (7 hunks)
  • tasks/docs.py (2 hunks)
  • tasks/release.py (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (18)
  • .devcontainer/Dockerfile
  • .github/workflows/define-versions.yml
  • backend/infrahub/core/validators/determiner.py
  • .github/workflows/ci.yml
  • development/Dockerfile
  • tasks/docs.py
  • backend/infrahub/workers/dependencies.py
  • .github/workflows/publish-pypi.yml
  • .github/workflows/version-upgrade.yml
  • backend/infrahub/core/diff/model/diff.py
  • .github/workflows/keyword-scan.yml
  • backend/infrahub/core/graph/constraints.py
  • backend/infrahub/core/schema/attribute_schema.py
  • backend/tests/integration/diff/test_merge_rollback.py
  • backend/tests/unit/git/conftest.py
  • backend/tests/helpers/test_app.py
  • backend/tests/helpers/utils.py
  • backend/tests/benchmark/conftest.py
🧰 Additional context used
📓 Path-based instructions (6)
**/*.py

📄 CodeRabbit inference engine (.github/instructions/python-docstring.instructions.md)

**/*.py: Always use triple quotes (""") for Python docstrings
Follow Google-style docstring format for Python docstrings
Include brief one-line description in Python docstrings when applicable
Include detailed description in Python docstrings when applicable
Include Args/Parameters section without typing in Python docstrings when applicable
Include Returns section in Python docstrings when applicable
Include Raises section in Python docstrings when applicable
Include Examples section in Python docstrings when applicable

**/*.py: Use type hints for all function parameters and return values in Python
Use Async whenever possible in Python
Use async def for asynchronous functions in Python
Use await for asynchronous calls in Python
Use Pydantic models for dataclasses in Python
Use ruff and mypy for type checking and code validation in Python

Use ruff and mypy to validate and lint Python files

Files:

  • backend/tests/unit/api/test_50_internals.py
  • backend/infrahub/cli/db.py
  • backend/infrahub/core/models.py
  • backend/infrahub/core/node/standard.py
  • backend/infrahub/database/__init__.py
  • backend/infrahub/core/graph/schema.py
  • backend/tests/unit/git/test_git_repository.py
  • tasks/release.py
  • backend/infrahub/core/schema/relationship_schema.py
  • backend/tests/unit/core/test_branch_rebase.py
  • backend/tests/conftest.py
  • backend/tests/unit/api/conftest.py
  • backend/tests/unit/graphql/mutations/test_branch.py
backend/tests/**/*.py

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Run backend tests with pytest or via invoke tasks

Name test files as test_<module>.py and mirror source structure in tests directory

Files:

  • backend/tests/unit/api/test_50_internals.py
  • backend/tests/unit/git/test_git_repository.py
  • backend/tests/unit/core/test_branch_rebase.py
  • backend/tests/conftest.py
  • backend/tests/unit/api/conftest.py
  • backend/tests/unit/graphql/mutations/test_branch.py
backend/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Use type hints for all Python code in the backend

Files:

  • backend/tests/unit/api/test_50_internals.py
  • backend/infrahub/cli/db.py
  • backend/infrahub/core/models.py
  • backend/infrahub/core/node/standard.py
  • backend/infrahub/database/__init__.py
  • backend/infrahub/core/graph/schema.py
  • backend/tests/unit/git/test_git_repository.py
  • backend/infrahub/core/schema/relationship_schema.py
  • backend/tests/unit/core/test_branch_rebase.py
  • backend/tests/conftest.py
  • backend/tests/unit/api/conftest.py
  • backend/tests/unit/graphql/mutations/test_branch.py
backend/infrahub/**/*.py

📄 CodeRabbit inference engine (backend/AGENTS.md)

backend/infrahub/**/*.py: Use async/await for all I/O operations to maintain async-first architecture
Type hint all function parameters and returns in Python code
Use Pydantic models for defining data structures instead of plain dictionaries
Use Query class pattern (extending infrahub.core.query.Query) for all database operations instead of unparameterized Cypher queries
Use Google-style docstrings with Args, Returns, and Raises sections for all functions
Use snake_case for function and variable names
Use PascalCase for class names
Use UPPER_SNAKE_CASE for constant definitions
Do not use unparameterized Cypher queries; always use parameterized queries to prevent injection
Do not block the event loop with synchronous I/O operations

Files:

  • backend/infrahub/cli/db.py
  • backend/infrahub/core/models.py
  • backend/infrahub/core/node/standard.py
  • backend/infrahub/database/__init__.py
  • backend/infrahub/core/graph/schema.py
  • backend/infrahub/core/schema/relationship_schema.py
frontend/app/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use TypeScript types for all frontend code

Files:

  • frontend/app/src/shared/api/rest/types.generated.ts
{pyproject.toml,uv.lock}

📄 CodeRabbit inference engine (.github/instructions/tooling.instructions.md)

Use uv to manage the Python project and its dependencies

Files:

  • pyproject.toml
🧠 Learnings (7)
📚 Learning: 2025-11-18T08:30:19.721Z
Learnt from: fatih-acar
Repo: opsmill/infrahub PR: 7669
File: .github/workflows/update-compose-file-and-chart.yml:52-53
Timestamp: 2025-11-18T08:30:19.721Z
Learning: The `uv version` command returns the project version from pyproject.toml (since astral-sh/uv PR #12349). Use `uv version --short` to extract project version for version checks and comparisons in workflows. The old behavior (showing UV's own tool version) is now `uv self version`.

Applied to files:

  • .github/workflows/uv-check.yml
📚 Learning: 2025-12-01T22:15:47.401Z
Learnt from: CR
Repo: opsmill/infrahub PR: 0
File: .github/instructions/tooling.instructions.md:0-0
Timestamp: 2025-12-01T22:15:47.401Z
Learning: Applies to {pyproject.toml,uv.lock} : Use uv to manage the Python project and its dependencies

Applied to files:

  • .github/workflows/uv-check.yml
  • .github/workflows/update-compose-file-and-chart.yml
  • .github/workflows/release.yml
📚 Learning: 2025-12-01T22:15:34.303Z
Learnt from: CR
Repo: opsmill/infrahub PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-01T22:15:34.303Z
Learning: Applies to backend/pyproject.toml : Use `uv` for dependency management in backend Python projects

Applied to files:

  • .github/workflows/uv-check.yml
  • .github/workflows/update-compose-file-and-chart.yml
  • .github/workflows/release.yml
  • pyproject.toml
📚 Learning: 2025-12-01T22:16:13.680Z
Learnt from: CR
Repo: opsmill/infrahub PR: 0
File: backend/AGENTS.md:0-0
Timestamp: 2025-12-01T22:16:13.680Z
Learning: Applies to backend/infrahub/**/*.py : Use Pydantic models for defining data structures instead of plain dictionaries

Applied to files:

  • backend/infrahub/core/models.py
📚 Learning: 2025-12-01T22:16:13.680Z
Learnt from: CR
Repo: opsmill/infrahub PR: 0
File: backend/AGENTS.md:0-0
Timestamp: 2025-12-01T22:16:13.680Z
Learning: Applies to backend/infrahub/**/*.py : Type hint all function parameters and returns in Python code

Applied to files:

  • pyproject.toml
📚 Learning: 2025-12-01T22:16:13.680Z
Learnt from: CR
Repo: opsmill/infrahub PR: 0
File: backend/AGENTS.md:0-0
Timestamp: 2025-12-01T22:16:13.680Z
Learning: Applies to backend/infrahub/**/*.py : Use PascalCase for class names

Applied to files:

  • pyproject.toml
📚 Learning: 2025-12-01T22:16:13.680Z
Learnt from: CR
Repo: opsmill/infrahub PR: 0
File: backend/AGENTS.md:0-0
Timestamp: 2025-12-01T22:16:13.680Z
Learning: Applies to backend/infrahub/**/*.py : Use UPPER_SNAKE_CASE for constant definitions

Applied to files:

  • pyproject.toml
🧬 Code graph analysis (7)
backend/tests/unit/api/test_50_internals.py (2)
backend/tests/helpers/test_app.py (1)
  • client (161-188)
backend/tests/unit/api/conftest.py (1)
  • client (18-26)
backend/infrahub/cli/db.py (1)
backend/infrahub/core/graph/schema.py (5)
  • GraphNodeProperties (37-45)
  • GraphRelationshipProperties (81-84)
  • GraphAttributeProperties (112-115)
  • GraphRelationshipIsPartOf (216-219)
  • GraphRelationshipDefault (222-234)
backend/infrahub/core/graph/schema.py (1)
backend/infrahub/types.py (1)
  • Any (312-319)
backend/tests/unit/core/test_branch_rebase.py (3)
backend/tests/conftest.py (2)
  • dependency_provider (121-122)
  • db (126-146)
backend/tests/helpers/test_app.py (1)
  • dependency_provider (80-81)
backend/infrahub/workers/dependencies.py (1)
  • build_database (63-72)
backend/tests/conftest.py (3)
backend/infrahub/database/__init__.py (1)
  • InfrahubDatabase (141-445)
backend/infrahub/workers/dependencies.py (2)
  • build_database (63-72)
  • get_database (76-77)
backend/tests/unit/api/conftest.py (1)
  • _db (22-23)
backend/tests/unit/api/conftest.py (2)
backend/infrahub/workers/dependencies.py (1)
  • build_database (63-72)
backend/tests/conftest.py (2)
  • dependency_provider (121-122)
  • _db (137-138)
backend/tests/unit/graphql/mutations/test_branch.py (3)
backend/tests/conftest.py (2)
  • dependency_provider (121-122)
  • db (126-146)
backend/tests/helpers/test_app.py (1)
  • dependency_provider (80-81)
backend/infrahub/workers/dependencies.py (1)
  • build_database (63-72)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (11)
  • GitHub Check: E2E-testing-version-upgrade / From 1.3.0
  • GitHub Check: backend-tests-unit
  • GitHub Check: documentation
  • GitHub Check: backend-tests-functional
  • GitHub Check: E2E-testing-playwright
  • GitHub Check: backend-benchmark
  • GitHub Check: validate-generated-documentation
  • GitHub Check: backend-tests-integration
  • GitHub Check: backend-docker-integration
  • GitHub Check: frontend-tests
  • GitHub Check: Cloudflare Pages
🔇 Additional comments (28)
.github/workflows/release.yml (1)

28-32: Python version consistently parameterized across job chain.

The check_release job now uses the dynamic Python version from prepare-environment, consistent with the pattern in other workflows. The dependency chain is properly maintained for all downstream jobs that rely on check_release outputs.

.github/workflows/uv-check.yml (1)

22-25: Reusable workflow properly parameterized for dynamic Python version.

The uv_check workflow correctly uses the dynamic Python version. This is important for a reusable workflow since it ensures consistent Python versions across all callers of this workflow.

.github/workflows/update-compose-file-and-chart.yml (1)

38-41: Dynamic Python version properly parameterized.

The workflow correctly sources the Python version from the prepare-environment job output, which invokes define-versions.yml where PYTHON_VERSION is defined as a workflow output. The job dependency is properly declared and the output reference syntax is correct.

backend/tests/unit/graphql/mutations/test_branch.py (1)

281-286: LGTM!

The updated lambda signature with singleton=True keyword argument correctly matches the build_database function signature from backend/infrahub/workers/dependencies.py. The # noqa: ARG005 comment appropriately suppresses the unused argument warning since the test fixture intentionally ignores the singleton flag and always returns the test database instance.

backend/tests/unit/core/test_branch_rebase.py (1)

101-118: LGTM!

The lambda signature update is consistent with the dependency injection pattern used throughout this PR. The test correctly scopes the database dependency for the branch rebase conflict test.

backend/tests/unit/api/test_50_internals.py (3)

96-105: LGTM!

Wrapping the TestClient usage in a context manager ensures proper startup/shutdown lifecycle handling. This aligns with the pattern already used in other tests in this file (e.g., test_config_endpoint, test_info_endpoint).


107-116: LGTM!

Consistent application of the context manager pattern.


118-128: LGTM!

Consistent application of the context manager pattern for the missing search index test case.

backend/infrahub/database/__init__.py (2)

495-497: Configuration parameter renamed to match new Neo4j API.

The driver configuration correctly uses notifications_disabled_classifications with NotificationDisabledClassification.UNRECOGNIZED to match the updated import. This is consistent with the import change on line 16.


16-16: The import is correct and already uses the current Neo4j Python driver API. NotificationDisabledClassification is the valid enum in Neo4j driver v5.22+ (stabilized in v6.0), and the parameter notifications_disabled_classifications matches the current API. No legacy API references exist in the codebase.

backend/tests/unit/git/test_git_repository.py (8)

481-488: LGTM!

The @pytest.mark.httpx_mock(should_mock=...) decorator correctly filters out Prefect HTTP requests based on User-Agent header while still allowing other requests to be mocked. This is a cleaner approach than modifying non_mocked_hosts when you need header-based filtering.


505-507: LGTM!

Adding is_reusable=True allows this mock response to be consumed multiple times during the test, which is appropriate when the same admin mutation may be called more than once.


582-588: LGTM!

Consistent application of the httpx_mock filter pattern.


644-650: LGTM!

Consistent application of the httpx_mock filter pattern.


667-680: LGTM!

Consistent application of the httpx_mock filter pattern for artifact generation tests.


703-714: LGTM!

Consistent application of the httpx_mock filter pattern.


737-750: LGTM!

Consistent application of the httpx_mock filter pattern.


773-786: LGTM!

Consistent application of the httpx_mock filter pattern for Jinja2 artifact generation test.

backend/tests/unit/api/conftest.py (1)

17-26: LGTM!

The fixture correctly implements the dependency injection pattern for database scoping. The _db function accepts the singleton parameter for signature compatibility but correctly forces singleton=False to ensure test isolation. This is consistent with the pattern used in backend/tests/conftest.py.

backend/tests/conftest.py (2)

13-13: Imports for async testing and database DI look consistent

The added pytest_asyncio import and the switch to using InfrahubDatabase plus build_database / get_database from infrahub.workers.dependencies align with the new async/DI setup and are consistent with the rest of the file. I don’t see issues here.

Also applies to: 50-50, 58-58


113-117: Async test collection hook is aligned with pytest-asyncio’s loop scoping

Using pytest_collection_modifyitems(items) with pytest_asyncio.is_async_test(item) and adding pytest.mark.asyncio(loop_scope="session") is a valid way to force all async tests onto a session-scoped loop with pytest-asyncio ≥0.17. Combined with asyncio_mode = "auto" and asyncio_default_fixture_loop_scope = "session" in pyproject.toml, this should effectively recreate your old session-wide loop behavior.

Please watch for any tests that accidentally rely on per-test loop isolation (e.g., background tasks leaking between tests) and adjust marks or scopes if you see flakiness.

pyproject.toml (1)

6-6: Python 3.14 support, async-testing stack, and neo4j VCS sources look coherent; verify across environments

  • Expanding requires-python to >=3.12,<3.15 and adding 3.13/3.14 classifiers matches the PR goal and is in line with current pytest-asyncio and pytest support for Python 3.14 and pytest 9.
  • Upgrading to pytest>=9.0,<9.1 plus pytest-asyncio>=1.3,<1.4 and configuring asyncio_mode="auto" together with asyncio_default_fixture_loop_scope = "session" fits the new async test strategy you wired in backend/tests/conftest.py (session-scoped loop for async tests/fixtures).
  • Moving neo4j / neo4j-rust-ext to bare names in [project.dependencies] and pinning them via [tool.uv.sources] to specific git revisions is a good fit for uv-based workflows and reproducibility. Just be aware that non-uv installers (plain pip install infrahub-server) will ignore [tool.uv.sources] and pull the published PyPI versions of neo4j/neo4j-rust-ext instead; if you still support that path, you may want to document the expectation that uv is the supported resolver. Based on learnings, this aligns with the “use uv for dependency management” guidance.
  • Removing upper bounds for pyarrow and numpy increases flexibility but also trusts future releases not to break you; given the breadth of your test suite this is probably acceptable, but keep an eye on CI when those libraries ship major updates.

Given the number of coordinated upgrades (Python range, pytest/pytest-asyncio, neo4j driver, numerical/telemetry stack), I’d strongly recommend re-running the matrix (at least 3.12, 3.13, 3.14) with uv to confirm there are no hidden resolver or runtime issues.

Also applies to: 14-15, 19-22, 23-24, 32-33, 47-55, 59-61, 63-66, 77-82, 89-89, 107-108, 145-145

schema/openapi.json (1)

979-987: Loosening schema contracts for dynamic payloads looks intentional; ensure client expectations match

Allowing additionalProperties: true on GraphQL responses, ComputedAttribute-Output, JSONSchema sub-schemas, and QueryPayload.variables makes sense for inherently dynamic shapes and should reduce spurious validation errors. It does, however, weaken strict contract guarantees, so it’s worth double‑checking that:

  • Any codegen/typed clients aren’t relying on the previous, stricter schemas.
  • Server‑side validation for security/consistency still happens at the application/model level rather than assuming OpenAPI will catch unknown keys.

Also applies to: 1091-1099, 3971-3974, 4478-4583, 5306-5311

backend/infrahub/core/models.py (1)

270-281: Switch to class-level model_fields is consistent with Pydantic v2 usage

Using field.__class__.model_fields[...], schema.__class__.model_fields[...], and iterating over self/other.__class__.model_fields.keys() keeps behavior aligned with how model metadata is exposed in Pydantic v2 and should be equivalent to the previous instance access for these BaseModel subclasses. It also future‑proofs against possible removal of instance‑level model_fields.

I’d just recommend re‑running the existing tests that cover:

  • SchemaUpdateValidationResult._process_attrs_rels / _process_node_attributes
  • HashableModel.get_hash(), .update(), and .diff()

to catch any subtle regressions in hashing, diffing, or schema‑update routing.

Also applies to: 308-325, 425-443, 580-607, 615-617

tasks/release.py (1)

407-420: Class-level model_fields in fetch_fields keeps env discovery consistent with Settings metadata

Iterating over subset.__class__.model_fields.items() while still recursing via the actual subset instance preserves the previous behavior and matches how BaseSettings exposes field definitions in current Pydantic Settings. No new edge cases stand out, given that defaults are still taken from field.get_default() and env names from EnvSettingsSource._extract_field_info.

It’s worth sanity‑checking this by running gen_config_env against a representative Settings tree to confirm that:

  • Nested settings still have their env vars discovered.
  • env_defaults matches the expected defaults (including those from default factories).
backend/infrahub/core/schema/relationship_schema.py (1)

84-91: LGTM! Class-level model_fields access aligns with Pydantic v2 patterns.

The change from self.model_fields to self.__class__.model_fields is more explicit about accessing class-level metadata and aligns with the broader pattern applied across the codebase. In Pydantic v2, model_fields is a ClassVar, so this change clarifies intent without altering behavior.

backend/infrahub/core/graph/schema.py (1)

237-264: LGTM! Improved type precision for graph schema.

The type annotations have been refined from dict[str, Any] to dict[str, type[Any]] for the inner dictionary values. This accurately reflects that the values are class types (like GraphNodeNode, GraphRelationshipNode) rather than arbitrary values, improving static type checking.

backend/infrahub/core/node/standard.py (1)

257-289: LGTM! Consistent class-level model_fields access.

The change from self.model_fields to self.__class__.model_fields in the to_db() method is consistent with the pattern applied across the codebase and follows Pydantic v2 best practices for accessing class-level field metadata.

Comment on lines +1306 to +1308
"ComputedAttribute-Output": {
[key: string]: unknown;
};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash

# First, check if the file exists and examine the specific lines
echo "=== Checking TypeScript file ==="
if [ -f "frontend/app/src/shared/api/rest/types.generated.ts" ]; then
  wc -l "frontend/app/src/shared/api/rest/types.generated.ts"
  echo "--- Lines 1306-1308 ---"
  sed -n '1306,1308p' "frontend/app/src/shared/api/rest/types.generated.ts"
else
  echo "File not found at frontend/app/src/shared/api/rest/types.generated.ts"
  # Try to find it
  find . -name "types.generated.ts" -type f 2>/dev/null | head -5
fi

Repository: opsmill/infrahub

Length of output: 258


🏁 Script executed:

#!/bin/bash

# Check if OpenAPI schema exists and examine the specified sections
echo "=== Checking OpenAPI schema ==="
if [ -f "schema/openapi.json" ]; then
  echo "--- ComputedAttribute-Output schema ---"
  cat schema/openapi.json | jq '.components.schemas."ComputedAttribute-Output"' 2>/dev/null || echo "Schema path not found"
  
  echo -e "\n--- JSONSchema schema ---"
  cat schema/openapi.json | jq '.components.schemas.JSONSchema' 2>/dev/null || echo "Schema path not found"
  
  echo -e "\n--- QueryPayload schema ---"
  cat schema/openapi.json | jq '.components.schemas.QueryPayload' 2>/dev/null || echo "Schema path not found"
else
  echo "OpenAPI schema not found at schema/openapi.json"
  find . -name "openapi.json" -type f 2>/dev/null | head -5
fi

Repository: opsmill/infrahub

Length of output: 2699


🏁 Script executed:

#!/bin/bash

# Search for how the TypeScript types file is generated
echo "=== Searching for code generation configuration ==="
find . -type f \( -name "*.json" -o -name "*.yaml" -o -name "*.yml" -o -name "*.config.js" -o -name "*.config.ts" \) 2>/dev/null | xargs grep -l "types.generated" 2>/dev/null | head -10

Repository: opsmill/infrahub

Length of output: 225


🏁 Script executed:

#!/bin/bash

# Look for Record<string, never> vs { [key: string]: unknown } types in the file
echo "=== Searching for type patterns in generated file ==="
if [ -f "frontend/app/src/shared/api/rest/types.generated.ts" ]; then
  echo "--- Occurrences of Record<string, never> ---"
  grep -n "Record<string, never>" "frontend/app/src/shared/api/rest/types.generated.ts" | wc -l
  
  echo "--- Occurrences of [key: string]: unknown ---"
  grep -n "\[key: string\]: unknown" "frontend/app/src/shared/api/rest/types.generated.ts" | wc -l
  
  echo "--- ComputedAttribute-Output context (lines 1300-1315) ---"
  sed -n '1300,1315p' "frontend/app/src/shared/api/rest/types.generated.ts"
fi

Repository: opsmill/infrahub

Length of output: 781


🏁 Script executed:

#!/bin/bash

# Check package.json for code generation configuration
echo "=== Checking frontend/app/package.json for generation config ==="
cat frontend/app/package.json | jq '.scripts | keys[] | select(. | contains("generate") or contains("api") or contains("openapi"))'
cat frontend/app/package.json | jq '.devDependencies | keys[] | select(. | contains("openapi") or contains("swagger") or contains("codegen"))'

Repository: opsmill/infrahub

Length of output: 216


🏁 Script executed:

#!/bin/bash

# Look for generation configuration files
echo "=== Searching for OpenAPI/CodeGen config ==="
find . -type f \( -name "*openapi*" -o -name "*codegen*" -o -name "*.openapirc*" \) 2>/dev/null | grep -v node_modules | grep -v ".git" | head -20

Repository: opsmill/infrahub

Length of output: 170


🏁 Script executed:

#!/bin/bash

# Check for git history of the OpenAPI schema
echo "=== Git history of OpenAPI schema changes ==="
git log --oneline -20 -- schema/openapi.json 2>/dev/null || echo "Git history not available"

Repository: opsmill/infrahub

Length of output: 153


🏁 Script executed:

#!/bin/bash

# Check if there are Python dependencies or setup files related to OpenAPI generation
echo "=== Looking for Python-related OpenAPI generation ==="
find . -maxdepth 2 -type f \( -name "pyproject.toml" -o -name "setup.py" -o -name "setup.cfg" \) 2>/dev/null | head -5
ls -la | grep -E "pyproject|setup|requirements"

Repository: opsmill/infrahub

Length of output: 236


🏁 Script executed:

#!/bin/bash

# Search for configuration that might be generating the types file
echo "=== Searching for openapi-generator or similar configuration ==="
grep -r "openapi" frontend/app/package.json 2>/dev/null | head -10
grep -r "swagger" frontend/app/package.json 2>/dev/null | head -10

Repository: opsmill/infrahub

Length of output: 316


🏁 Script executed:

#!/bin/bash

# Check the actual git diff of the OpenAPI schema
echo "=== Recent changes to OpenAPI schema ==="
git log -p --follow -5 -- schema/openapi.json 2>/dev/null | grep -A 50 "ComputedAttribute-Output" | head -100 || echo "Could not retrieve full git history"

Repository: opsmill/infrahub

Length of output: 100


🏁 Script executed:

#!/bin/bash

# Check the commit that modified the schema
echo "=== Checking commit b96e0ab46 ==="
git show b96e0ab46 --stat 2>/dev/null | head -50

Repository: opsmill/infrahub

Length of output: 2827


🏁 Script executed:

#!/8in/bash

# Look for actual PR or recent changes mentioning ComputedAttribute or Python 3.14
echo "=== Searching for Python 3.14 or related changes ==="
grep -r "3.14" . --include="*.toml" --include="*.txt" --include="*.yml" --include="*.yaml" 2>/dev/null | head -20
grep -r "python_requires" . --include="*.toml" --include="*.py" 2>/dev/null | head -10

Repository: opsmill/infrahub

Length of output: 438


🏁 Script executed:

#!/bin/bash

# Check if the generated file actually shows a change or if it was always like this
echo "=== Git history of types.generated.ts for ComputedAttribute-Output ==="
git log --oneline -10 -- frontend/app/src/shared/api/rest/types.generated.ts 2>/dev/null || echo "No history found"
git log -p -2 -- frontend/app/src/shared/api/rest/types.generated.ts 2>/dev/null | grep -A 5 -B 5 "ComputedAttribute-Output" | head -50

Repository: opsmill/infrahub

Length of output: 178


🏁 Script executed:

#!/bin/bash

# Check the backend code that generates the OpenAPI schema
echo "=== Looking at backend OpenAPI generation ==="
grep -r "ComputedAttribute" backend/ --include="*.py" | grep -i "additional\|schema" | head -20

Repository: opsmill/infrahub

Length of output: 2443


🏁 Script executed:

#!/bin/bash

# Check what files were modified in the last commit
echo "=== Files modified in latest commit ==="
git show --name-status b96e0ab46 2>/dev/null | head -50
git show --name-status b96e0ab46 2>/dev/null | grep -E "types.generated|openapi.json"

Repository: opsmill/infrahub

Length of output: 1881


🏁 Script executed:

#!/bin/bash

# Check the OpenAPI schema generation in backend
echo "=== Looking for OpenAPI schema generation code ==="
find backend/ -name "*.py" -type f -exec grep -l "openapi\|OpenAPI" {} \; 2>/dev/null | head -10

Repository: opsmill/infrahub

Length of output: 240


🏁 Script executed:

#!/bin/bash

# Verify the ComputedAttribute schema definition in backend
echo "=== ComputedAttribute schema definition ==="
grep -A 20 "class ComputedAttribute" backend/infrahub/core/schema/computed_attribute.py 2>/dev/null | head -30

Repository: opsmill/infrahub

Length of output: 945


🏁 Script executed:

#!/bin/bash

# Check if there's a specific Pydantic model that generates the schema
echo "=== Searching for model_json_schema or similar ==="
grep -r "model_json_schema\|schema_extra\|ConfigDict" backend/infrahub/core/schema/computed_attribute.py 2>/dev/null | head -20

Repository: opsmill/infrahub

Length of output: 226


🏁 Script executed:

#!/bin/bash

# Check the full ComputedAttribute model configuration
echo "=== Full ComputedAttribute model definition ==="
cat backend/infrahub/core/schema/computed_attribute.py

Repository: opsmill/infrahub

Length of output: 1916


🏁 Script executed:

#!/bin/bash

# Check if there's a separate output/response model for ComputedAttribute
echo "=== Searching for ComputedAttribute response/output models ==="
grep -r "ComputedAttribute.*Output\|ComputedAttribute.*Response" backend/ --include="*.py" 2>/dev/null | head -20

Repository: opsmill/infrahub

Length of output: 122


🏁 Script executed:

#!/bin/bash

# Check the OpenAPI generation to understand where ComputedAttribute-Output comes from
echo "=== Checking API endpoints that use ComputedAttribute ==="
grep -r "ComputedAttribute" backend/infrahub/api/ --include="*.py" 2>/dev/null | head -20

Repository: opsmill/infrahub

Length of output: 117


🏁 Script executed:

#!/bin/bash

# Check the server/API initialization for OpenAPI schema generation
echo "=== Checking OpenAPI schema generation setup ==="
cat backend/infrahub/server.py | grep -A 30 -B 5 "openapi\|OpenAPI" | head -100

Repository: opsmill/infrahub

Length of output: 1276


🏁 Script executed:

#!/bin/bash

# Look for FastAPI app setup that might generate the schemas
echo "=== Searching for schemas generation in API init ==="
cat backend/infrahub/api/__init__.py | head -150

Repository: opsmill/infrahub

Length of output: 2294


🏁 Script executed:

#!/bin/bash

# Check if there's a custom OpenAPI schema generator
echo "=== Checking for custom schema generation ==="
grep -r "get_openapi\|OpenAPI\|schema" backend/infrahub/api/__init__.py 2>/dev/null | head -30

Repository: opsmill/infrahub

Length of output: 276


🏁 Script executed:

#!/bin/bash

# Look for where the "-Output" suffix might be added
echo "=== Searching for Output suffix in schema generation ==="
grep -r "\-Output\|Output" backend/infrahub/api/ --include="*.py" 2>/dev/null | grep -i "schema\|model" | head -20

Repository: opsmill/infrahub

Length of output: 116


🏁 Script executed:

#!/bin/bash

# Check if ComputedAttribute appears in route handlers
echo "=== Checking for ComputedAttribute in routes ==="
find backend/infrahub/api/routes -name "*.py" -exec grep -l "ComputedAttribute\|computed" {} \; 2>/dev/null

Repository: opsmill/infrahub

Length of output: 108


🏁 Script executed:

#!/bin/bash

# Check if the schema/openapi.json and types.generated.ts are new files (initial commit)
echo "=== Checking if files were newly added ==="
git log --oneline --all -- schema/openapi.json frontend/app/src/shared/api/rest/types.generated.ts 2>/dev/null

# Check previous commits to see if there's any history
git log --oneline --all 2>/dev/null | head -10

Repository: opsmill/infrahub

Length of output: 276


🏁 Script executed:

#!/bin/bash

# Check the total number of commits
echo "=== Repository commit history ==="
git rev-list --all --count 2>/dev/null
git log --oneline --all 2>/dev/null | tail -20

Repository: opsmill/infrahub

Length of output: 182


🏁 Script executed:

#!/bin/bash

# Verify the mismatch: backend forbids extra properties but schema allows them
echo "=== Backend model configuration ==="
grep -A 50 "model_config = ConfigDict" backend/infrahub/core/schema/computed_attribute.py | head -60
echo ""
echo "=== OpenAPI schema for ComputedAttribute-Output ==="
cat schema/openapi.json | jq '.components.schemas."ComputedAttribute-Output"'

Repository: opsmill/infrahub

Length of output: 1265


🏁 Script executed:

#!/bin/bash

# Double-check the backend model to confirm it forbids extra properties
echo "=== Backend ComputedAttribute model configuration (full) ==="
grep -B 5 -A 60 "class ComputedAttribute" backend/infrahub/core/schema/computed_attribute.py | grep -E "extra|forbid|class|json_schema"

Repository: opsmill/infrahub

Length of output: 212


🏁 Script executed:

#!/bin/bash

# Check if there's any conversion or transformation that might explain the discrepancy
echo "=== Searching for OpenAPI schema generation customization ==="
grep -r "additionalProperties\|extra" backend/infrahub/api/ --include="*.py" 2>/dev/null | head -20

Repository: opsmill/infrahub

Length of output: 1133


🏁 Script executed:

#!/bin/bash

# Check the test file for OpenAPI to see what's expected
echo "=== OpenAPI tests ==="
cat backend/tests/unit/api/test_70_openapi.py | head -100

Repository: opsmill/infrahub

Length of output: 484


🏁 Script executed:

#!/bin/bash

# Check the schema.py file for additionalProperties handling
echo "=== Backend schema.py - additionalProperties handling ==="
grep -B 10 -A 10 "additionalProperties" backend/infrahub/api/schema.py

Repository: opsmill/infrahub

Length of output: 1435


🏁 Script executed:

#!/bin/bash

# Check if JSONSchema model has special handling
echo "=== Looking for JSONSchema model definition ==="
grep -r "class JSONSchema" backend/ --include="*.py" 2>/dev/null

Repository: opsmill/infrahub

Length of output: 167


🏁 Script executed:

#!/bin/bash

# Look at how FastAPI generates the schema from Pydantic models
echo "=== Checking for model_serializer impact on schema generation ==="
grep -B 20 -A 5 "model_serializer" backend/infrahub/core/schema/computed_attribute.py

Repository: opsmill/infrahub

Length of output: 927


🏁 Script executed:

#!/bin/bash

# Check if there's a custom OpenAPI schema customization function
echo "=== Searching for custom OpenAPI generation hooks ==="
grep -r "get_openapi\|modify_openapi_schema\|openapi_schema" backend/infrahub/ --include="*.py" 2>/dev/null | head -20

Repository: opsmill/infrahub

Length of output: 113


🏁 Script executed:

#!/bin/bash

# Check the git diff for the initial commit to see if Record<string, never> ever existed
echo "=== Checking the actual diff from initial commit ==="
git show b96e0ab46:frontend/app/src/shared/api/rest/types.generated.ts 2>/dev/null | grep -A 3 -B 3 "ComputedAttribute-Output" | head -20

Repository: opsmill/infrahub

Length of output: 659


🏁 Script executed:

#!/bin/bash

# Verify the schema generation matches what the backend model should produce
echo "=== Checking if schema contradicts backend model ==="
echo "Backend says: extra='forbid'"
echo "Schema says: additionalProperties: true"
echo ""
echo "This is a contract violation - the schema allows what the backend forbids."

Repository: opsmill/infrahub

Length of output: 257


The schema-to-implementation contract is violated: backend forbids extra properties while the OpenAPI schema declares additionalProperties: true.

The backend ComputedAttribute model has extra="forbid" in its Pydantic config, but the OpenAPI schema for ComputedAttribute-Output allows arbitrary properties via additionalProperties: true. This creates a mismatch between what the backend will actually reject at runtime and what the generated TypeScript type ({ [key: string]: unknown }) suggests is valid, risking integration failures.

Either:

  • The backend model should have extra="allow" if the schema intends to support dynamic properties, or
  • The schema should have additionalProperties: false to match the backend's strict validation

Verify that the OpenAPI schema generation intentionally overrides the backend model's extra="forbid" setting, or correct the schema to match the backend constraints.

Stay with 3.13 due to compat issues with external packages.

Signed-off-by: Fatih Acar <[email protected]>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
pyproject.toml (1)

62-63: Consider adding upper bounds for stability.

Removing upper bounds on pyarrow and numpy provides flexibility but may expose the project to unexpected breaking changes in future major versions. If stability is a concern, consider adding upper bounds like pyarrow>=14,<19 and numpy>=1.26.2,<3.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b96e0ab and e63c6d7.

⛔ Files ignored due to path filters (1)
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (5)
  • .devcontainer/Dockerfile (1 hunks)
  • .github/workflows/define-versions.yml (1 hunks)
  • .github/workflows/keyword-scan.yml (1 hunks)
  • development/Dockerfile (1 hunks)
  • pyproject.toml (5 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • development/Dockerfile
  • .devcontainer/Dockerfile
  • .github/workflows/keyword-scan.yml
🧰 Additional context used
📓 Path-based instructions (1)
{pyproject.toml,uv.lock}

📄 CodeRabbit inference engine (.github/instructions/tooling.instructions.md)

Use uv to manage the Python project and its dependencies

Files:

  • pyproject.toml
🧠 Learnings (2)
📚 Learning: 2025-12-01T22:15:34.303Z
Learnt from: CR
Repo: opsmill/infrahub PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-01T22:15:34.303Z
Learning: Applies to backend/pyproject.toml : Use `uv` for dependency management in backend Python projects

Applied to files:

  • pyproject.toml
📚 Learning: 2025-12-01T22:16:13.680Z
Learnt from: CR
Repo: opsmill/infrahub PR: 0
File: backend/AGENTS.md:0-0
Timestamp: 2025-12-01T22:16:13.680Z
Learning: Applies to backend/infrahub/**/*.py : Type hint all function parameters and returns in Python code

Applied to files:

  • pyproject.toml
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: yaml-lint
🔇 Additional comments (6)
.github/workflows/define-versions.yml (1)

9-10: LGTM! Valid Python version.

Python 3.13.11 is a valid maintenance release, and this change correctly establishes a centralized version definition that can be consumed by multiple workflows. The PR title mentions "Python 3.14" while using 3.13.11, which makes sense as Python 3.14 is now the latest feature release, and the project appears to be ensuring compatibility with 3.13 while preparing for 3.14 support (as indicated by the pyproject.toml range <3.14 mentioned in the AI summary).

pyproject.toml (5)

6-6: LGTM!

The Python version constraint correctly expands support to include Python 3.13 while maintaining 3.12 compatibility. The classifier accurately reflects the supported versions.

Also applies to: 14-14


18-20: LGTM!

Exact version pinning for neo4j and neo4j-rust-ext ensures a known-good combination, and pydantic>=2.12 includes improved Python 3.13 compatibility.


50-53: LGTM!

OpenTelemetry packages are correctly pinned and the instrumentation (0.60b0) and exporter (1.39.0) versions are properly aligned as expected for their release cadence.


31-31: LGTM!

Minor and patch version updates for prefect-redis, aiodataloader, and dev dependencies are straightforward. The inline comments on API server dependencies improve maintainability.

Also applies to: 45-48, 57-57, 103-104


58-58: Verify if fast-depends 3.0.5 has breaking changes from 2.4.12.

The codebase uses standard FastDepends APIs (Depends, inject, Provider, dependency_provider.scope()) that appear compatible with version 3.0.5 based on current documentation. However, confirm the major version upgrade (2.x → 3.x) introduces no breaking changes affecting these APIs by reviewing the official FastDepends 3.0 release notes or changelog.

Comment thread pyproject.toml
"mypy>=1.15,<1.16",
"ipython>=8,<9",
"pytest-asyncio>=0.21.1,<0.22",
"pytest-asyncio>=1.3,<1.4",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Correct asyncio_default_fixture_loop_scope to function scope.

The configuration should be set to "function" to address the deprecation warning about the unset configuration option. The default value should be function, and asyncio_default_fixture_loop_scope should not be set explicitly unless necessary. By default, each test runs in the event loop provided by the Function collector, which uses the loop with the narrowest scope and gives the highest level of isolation between tests. Setting this to "session" can cause compatibility issues with fixture management.

🤖 Prompt for AI Agents
In pyproject.toml around line 85, the pytest-asyncio configuration currently
sets asyncio_default_fixture_loop_scope incorrectly (or to session); change this
option to "function" (or remove the explicit setting to rely on the default) to
eliminate the deprecation/compatibility warning and ensure each test uses a
function-scoped event loop for proper fixture isolation.

@fatih-acar fatih-acar changed the title Python 3.14 Python 3.13 Dec 18, 2025
@fatih-acar fatih-acar merged commit d594715 into develop Dec 18, 2025
83 of 85 checks passed
@fatih-acar fatih-acar deleted the pog-python-3.13 branch December 18, 2025 22:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

group/backend Issue related to the backend (API Server, Git Agent) group/ci Issue related to the CI pipeline group/frontend Issue related to the frontend (React)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants