Skip to content

Add the ability to export the schema in yaml#835

Open
BeArchiTek wants to merge 8 commits intostablefrom
bkr-add-schema-exporter
Open

Add the ability to export the schema in yaml#835
BeArchiTek wants to merge 8 commits intostablefrom
bkr-add-schema-exporter

Conversation

@BeArchiTek
Copy link
Contributor

@BeArchiTek BeArchiTek commented Feb 18, 2026

Fixes #151

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced infrahubctl schema export command to export schemas as YAML files, organized by namespace
    • Supports namespace filtering, custom output directories, and branch-specific exports via command-line options
  • Documentation

    • Added documentation for the new schema export command and its usage options

BeArchiTek and others added 5 commits February 18, 2026 15:06
Adds `infrahubctl schema export` to fetch user-defined schemas from an
Infrahub server and write them as YAML files (one per namespace).

Restricted namespaces (Core, Builtin, Internal, etc.) and auto-generated
types (ProfileSchemaAPI, TemplateSchemaAPI) are excluded by default.
RESTRICTED_NAMESPACES is mirrored from the Infrahub server constants so
the server can later consume it from the SDK.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Strip relationship fields that match schema loading defaults
  (direction: bidirectional, on_delete: no-action, cardinality: many,
  optional: true, min_count: 0, max_count: 0)
- Exclude branch from attribute/relationship dumps (inherited from node)
- Ensure scalar fields appear before attributes/relationships lists

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
read_only was unconditionally excluded from attribute dumps; move it to
_ATTR_EXPORT_DEFAULTS so it is stripped only when False (the default)
and kept when True (computed/read-only attributes).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…export

- Drop relationships with kind Group, Profile, or Hierarchy from export
  output — these are always auto-generated by Infrahub and must not be
  re-loaded manually (doing so caused validator_not_available errors for
  hierarchical generics)
- For GenericSchemaAPI objects that had Hierarchy relationships, restore
  the `hierarchical: true` flag so the schema round-trips cleanly
- Add read_only: false to _REL_EXPORT_DEFAULTS to stop it leaking into
  relationship output

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ints

- generics key now appears before nodes in the exported YAML payload
- uniqueness_constraints entries that are auto-generated from unique: true
  attributes (single-field ["<attr>__value"] entries) are removed on
  export; user-defined multi-field constraints are preserved

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@BeArchiTek BeArchiTek requested a review from a team as a code owner February 18, 2026 15:55
@cloudflare-workers-and-pages
Copy link

cloudflare-workers-and-pages bot commented Feb 18, 2026

Deploying infrahub-sdk-python with  Cloudflare Pages  Cloudflare Pages

Latest commit: e63783e
Status: ✅  Deploy successful!
Preview URL: https://74ae813b.infrahub-sdk-python.pages.dev
Branch Preview URL: https://bkr-add-schema-exporter.infrahub-sdk-python.pages.dev

View logs

@codecov
Copy link

codecov bot commented Feb 18, 2026

Codecov Report

❌ Patch coverage is 97.40260% with 2 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
infrahub_sdk/ctl/schema.py 91.66% 2 Missing ⚠️

❗ There is a different number of reports uploaded between BASE (9e0d8c1) and HEAD (e63783e). Click for more details.

HEAD has 5 uploads less than BASE
Flag BASE (9e0d8c1) HEAD (e63783e)
python-filler-3.12 2 1
python-3.14 2 1
python-3.13 2 1
integration-tests 2 0
@@            Coverage Diff             @@
##           stable     #835      +/-   ##
==========================================
- Coverage   80.36%   72.53%   -7.83%     
==========================================
  Files         115      116       +1     
  Lines        9875     9952      +77     
  Branches     1504     1517      +13     
==========================================
- Hits         7936     7219     -717     
- Misses       1417     2227     +810     
+ Partials      522      506      -16     
Flag Coverage Δ
integration-tests ?
python-3.10 51.58% <76.62%> (+0.21%) ⬆️
python-3.11 51.56% <76.62%> (?)
python-3.12 51.58% <76.62%> (+0.21%) ⬆️
python-3.13 51.56% <76.62%> (+0.17%) ⬆️
python-3.14 53.22% <79.22%> (+0.20%) ⬆️
python-filler-3.12 24.04% <20.77%> (-0.03%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
infrahub_sdk/constants.py 100.00% <100.00%> (ø)
infrahub_sdk/schema/__init__.py 69.14% <100.00%> (-0.20%) ⬇️
infrahub_sdk/schema/export.py 100.00% <100.00%> (ø)
infrahub_sdk/ctl/schema.py 60.86% <91.66%> (+5.39%) ⬆️

... and 31 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Move export helpers from ctl/schema.py to infrahub_sdk/schema/export.py
so the conversion logic is reusable outside the CLI. Regenerate
infrahubctl docs to include the new export subcommand.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions github-actions bot added the type/documentation Improvements or additions to documentation label Feb 19, 2026
"Schema",
"Profile",
"Template",
]
Copy link
Contributor

Choose a reason for hiding this comment

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

Instead of doing it like this I'd suggest that we have this part be included within the schema component of the SDK. The backend will return this information (to indicate if the namespace is editable by the user or not). It could be that the SDK doesn't yet deal with that part of the API. But we should not introduce a new list for this and support them separately.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Can we do it as part of another PR later on ?

@opsmill opsmill deleted a comment from coderabbitai bot Feb 19, 2026
@coderabbitai
Copy link

coderabbitai bot commented Feb 19, 2026

Walkthrough

This pull request implements schema export functionality for Infrahub. It introduces a new infrahubctl schema export CLI command that exports schemas to YAML files organized by namespace. The implementation adds support constants (RESTRICTED_NAMESPACES), schema transformation utilities (schema_to_export_dict), and export methods to schema classes. The feature supports filtering by namespace, excludes restricted and auto-generated namespaces, and omits internal fields for cleaner exports. Comprehensive tests validate CLI behavior and SDK export logic.

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description is minimal (only 'Fixes #151') and does not follow the provided template structure with Why, What changed, How to review, How to test, or Impact & rollout sections. Expand the description to include the Why section explaining the problem and goal, behavioral changes, implementation notes, and testing instructions aligned with the template structure.
Docstring Coverage ⚠️ Warning Docstring coverage is 47.83% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: adding schema export functionality to YAML format, which aligns with the primary objective.
Linked Issues check ✅ Passed All coding requirements from issue #151 are met: schema export CLI command supports namespace filtering, excludes restricted namespaces, removes server-generated fields, and provides clean YAML output for reimport.
Out of Scope Changes check ✅ Passed All changes are scoped to schema export functionality as defined in issue #151. Additions include export logic, CLI command, documentation, tests, and a new constant for restricted namespaces.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


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.

Copy link

@coderabbitai coderabbitai bot left a comment

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 (3)
infrahub_sdk/constants.py (1)

6-19: Consider using frozenset for RESTRICTED_NAMESPACES.

As a constant used exclusively for membership tests (in), frozenset gives O(1) lookup and prevents accidental mutation.

♻️ Proposed change
-RESTRICTED_NAMESPACES: list[str] = [
-    "Account",
-    "Branch",
-    "Builtin",
-    "Core",
-    "Deprecated",
-    "Diff",
-    "Infrahub",
-    "Internal",
-    "Lineage",
-    "Schema",
-    "Profile",
-    "Template",
-]
+RESTRICTED_NAMESPACES: frozenset[str] = frozenset({
+    "Account",
+    "Branch",
+    "Builtin",
+    "Core",
+    "Deprecated",
+    "Diff",
+    "Infrahub",
+    "Internal",
+    "Lineage",
+    "Schema",
+    "Profile",
+    "Template",
+})
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@infrahub_sdk/constants.py` around lines 6 - 19, RESTRICTED_NAMESPACES is
currently a mutable list but used only for membership checks; change its type to
an immutable frozenset to prevent accidental mutation and get O(1) lookups by
replacing the list literal with a frozenset literal (e.g., frozenset({...}))
where RESTRICTED_NAMESPACES is defined in infrahub_sdk/constants.py and ensure
any code that treats it as a sequence (indexing/ordering) is not relying on list
behavior.
infrahub_sdk/schema/__init__.py (1)

533-553: export() always fetches the full schema even when namespaces is specified.

The client-side namespace filtering in _build_export_schemas is applied after fetching all schemas from the server. For large deployments, passing the namespace filter to _fetch (already supported via the namespaces parameter of InfrahubSchema.fetch) would reduce payload size. Not a bug, but worth considering for performance at scale.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@infrahub_sdk/schema/__init__.py` around lines 533 - 553, The export() method
currently fetches the full schema then filters client-side; change it to pass
the provided namespaces to the server fetch to reduce payload. Update the call
in export (function export) from awaiting self.fetch(branch=branch) to await
self.fetch(branch=branch, namespaces=namespaces) so server-side filtering is
used before calling _build_export_schemas(schema_nodes=...,
namespaces=namespaces); ensure the namespaces parameter shape (None or
list[str]) matches InfrahubSchema.fetch's namespaces arg.
tests/unit/sdk/test_schema_export.py (1)

19-97: Duplicated test data builders across both test files.

_BASE_NODE, _BASE_GENERIC, _schema_response, and the _make_* helpers are defined in near-identical form in both tests/unit/sdk/test_schema_export.py and tests/unit/ctl/test_schema_export.py. Extracting these into a shared tests/helpers/schema.py module would eliminate the duplication.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/unit/sdk/test_schema_export.py` around lines 19 - 97, Duplicate test
data and builders (_BASE_NODE, _BASE_GENERIC, _schema_response and helpers
_make_node_schema, _make_generic_schema, _make_profile_schema,
_make_template_schema) should be extracted into a single shared helper module
and both test files should import them; create a new helpers module that exports
those constants and factory functions, replace the duplicated definitions in
tests/unit/sdk/test_schema_export.py and tests/unit/ctl/test_schema_export.py
with imports from the new module, and update any references to use the imported
symbols so tests still construct NodeSchemaAPI, GenericSchemaAPI,
ProfileSchemaAPI, and TemplateSchemaAPI using the shared builders.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@infrahub_sdk/ctl/schema.py`:
- Around line 217-219: The default export directory function
_default_export_directory currently returns a str while the export command's
directory parameter is annotated as Path; update _default_export_directory to
return a Path (e.g., wrap the formatted string with Path(...)) so the default
value matches the annotated type for export, and/or add a unit/integration test
that calls the export CLI without --directory to assert the resulting type is
Path and no AttributeError occurs (look for references to
_default_export_directory and the export command / directory parameter to modify
code and add tests).

---

Nitpick comments:
In `@infrahub_sdk/constants.py`:
- Around line 6-19: RESTRICTED_NAMESPACES is currently a mutable list but used
only for membership checks; change its type to an immutable frozenset to prevent
accidental mutation and get O(1) lookups by replacing the list literal with a
frozenset literal (e.g., frozenset({...})) where RESTRICTED_NAMESPACES is
defined in infrahub_sdk/constants.py and ensure any code that treats it as a
sequence (indexing/ordering) is not relying on list behavior.

In `@infrahub_sdk/schema/__init__.py`:
- Around line 533-553: The export() method currently fetches the full schema
then filters client-side; change it to pass the provided namespaces to the
server fetch to reduce payload. Update the call in export (function export) from
awaiting self.fetch(branch=branch) to await self.fetch(branch=branch,
namespaces=namespaces) so server-side filtering is used before calling
_build_export_schemas(schema_nodes=..., namespaces=namespaces); ensure the
namespaces parameter shape (None or list[str]) matches InfrahubSchema.fetch's
namespaces arg.

In `@tests/unit/sdk/test_schema_export.py`:
- Around line 19-97: Duplicate test data and builders (_BASE_NODE,
_BASE_GENERIC, _schema_response and helpers _make_node_schema,
_make_generic_schema, _make_profile_schema, _make_template_schema) should be
extracted into a single shared helper module and both test files should import
them; create a new helpers module that exports those constants and factory
functions, replace the duplicated definitions in
tests/unit/sdk/test_schema_export.py and tests/unit/ctl/test_schema_export.py
with imports from the new module, and update any references to use the imported
symbols so tests still construct NodeSchemaAPI, GenericSchemaAPI,
ProfileSchemaAPI, and TemplateSchemaAPI using the shared builders.

Comment on lines +217 to +219
def _default_export_directory() -> str:
timestamp = datetime.now(timezone.utc).astimezone().strftime("%Y%m%d-%H%M%S")
return f"infrahub-schema-export-{timestamp}"
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# First, examine the actual code in the file
cat -n infrahub_sdk/ctl/schema.py | sed -n '210,230p'

Repository: opsmill/infrahub-sdk-python

Length of output: 1088


🏁 Script executed:

# Find the Typer version being used
fd -e "txt" -e "toml" -e "cfg" -e "yaml" | xargs grep -l "typer" | head -5

Repository: opsmill/infrahub-sdk-python

Length of output: 85


🏁 Script executed:

# Check if there are CLI tests that exercise the default directory path
fd -e "test_*.py" -e "*_test.py" | xargs grep -l "schema" | head -10

Repository: opsmill/infrahub-sdk-python

Length of output: 53


🌐 Web query:

Typer callable default type coercion Path annotation documentation

💡 Result:

  • Callable defaults (dynamic defaults): Typer documents default_factory for both typer.Argument(...) and typer.Option(...). It must be a callable like Callable[[], Any] that Typer calls to produce the default value when the user doesn’t provide one. See Reference → Parameters → default_factory. [1]

  • Type coercion / parsing (custom coercion): If you need custom conversion from the CLI string token(s) to your Python type, Typer documents:

    • parser: a callable like Callable[[str], Any] that receives the raw string and returns your custom type.
    • click_type: provide a custom Click ParamType to handle conversion/validation.
      These are in the same Reference → Parameters page. [1]
  • Path annotation behavior: Typer documents that if you annotate a parameter as pathlib.Path (often via typing.Annotated[..., typer.Option(...)] / typer.Argument(...)), Typer/Click will coerce the CLI input into a Path object, and you can add path validations like exists, file_okay, dir_okay, readable, writable, resolve_path, plus advanced settings like allow_dash and path_type. See Tutorial → Parameter Types → Path. [2]

Sources: Typer “Parameters” reference [1]; Typer “Path” parameter type tutorial [2].


🏁 Script executed:

# Check Typer version in pyproject.toml
cat pyproject.toml | grep -A 5 -B 5 "typer"

Repository: opsmill/infrahub-sdk-python

Length of output: 1615


🏁 Script executed:

# Search for any tests that call export() without --directory argument
find . -name "test_*.py" -o -name "*_test.py" | xargs grep -l "export" | head -5

Repository: opsmill/infrahub-sdk-python

Length of output: 190


🏁 Script executed:

# Check if there's actual test coverage calling export without directory arg
rg "async def export|def export" infrahub_sdk/ctl/schema.py -A 20 | head -40

Repository: opsmill/infrahub-sdk-python

Length of output: 866


🏁 Script executed:

# Look for Click/Typer source or test to understand callable default behavior
rg "default_factory|default\(" --type py infrahub_sdk/ctl/ -B 2 -A 2 | head -60

Repository: opsmill/infrahub-sdk-python

Length of output: 53


🏁 Script executed:

# Examine the test file for schema export
cat -n tests/unit/ctl/test_schema_export.py | head -100

Repository: opsmill/infrahub-sdk-python

Length of output: 3224


🏁 Script executed:

# Search for any test that calls export() without --directory
rg "def test.*export|async def test.*export" tests/unit/ctl/test_schema_export.py -A 30 | head -80

Repository: opsmill/infrahub-sdk-python

Length of output: 2974


🏁 Script executed:

# Check if there's any test that exercises the default directory behavior
rg "from_cli|CliRunner|invoke" tests/unit/ctl/test_schema_export.py -B 3 -A 10

Repository: opsmill/infrahub-sdk-python

Length of output: 6496


Default directory code path is untested — add test coverage or apply explicit type conversion.

_default_export_directory() returns a str, but directory is annotated as Path. All tests explicitly supply --directory, leaving the default callable behavior untested. While Typer/Click applies type coercion for CLI input, callable return value coercion through type annotations is not documented. To eliminate the risk of AttributeError at runtime when the default is used, either:

  1. Add a test that invokes export without --directory to verify type coercion works, or
  2. Explicitly convert the return value: return Path(f"infrahub-schema-export-{timestamp}")
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@infrahub_sdk/ctl/schema.py` around lines 217 - 219, The default export
directory function _default_export_directory currently returns a str while the
export command's directory parameter is annotated as Path; update
_default_export_directory to return a Path (e.g., wrap the formatted string with
Path(...)) so the default value matches the annotated type for export, and/or
add a unit/integration test that calls the export CLI without --directory to
assert the resulting type is Path and no AttributeError occurs (look for
references to _default_export_directory and the export command / directory
parameter to modify code and add tests).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

type/documentation Improvements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feature: Ability to export the schema in YAML format using infrahubctl

2 participants

Comments