|
22 | 22 | ) |
23 | 23 | from ..graphql import Mutation |
24 | 24 | from ..queries import SCHEMA_HASH_SYNC_STATUS |
| 25 | +from .export import RESTRICTED_NAMESPACES, NamespaceExport, SchemaExport, schema_to_export_dict |
25 | 26 | from .main import ( |
26 | 27 | AttributeSchema, |
27 | 28 | AttributeSchemaAPI, |
|
54 | 55 | "BranchSupportType", |
55 | 56 | "GenericSchema", |
56 | 57 | "GenericSchemaAPI", |
| 58 | + "NamespaceExport", |
57 | 59 | "NodeSchema", |
58 | 60 | "NodeSchemaAPI", |
59 | 61 | "ProfileSchemaAPI", |
60 | 62 | "RelationshipCardinality", |
61 | 63 | "RelationshipKind", |
62 | 64 | "RelationshipSchema", |
63 | 65 | "RelationshipSchemaAPI", |
| 66 | + "SchemaExport", |
64 | 67 | "SchemaRoot", |
65 | 68 | "SchemaRootAPI", |
66 | 69 | "TemplateSchemaAPI", |
| 70 | + "schema_to_export_dict", |
67 | 71 | ] |
68 | 72 |
|
69 | 73 |
|
@@ -118,6 +122,47 @@ def __init__(self, client: InfrahubClient | InfrahubClientSync) -> None: |
118 | 122 | self.client = client |
119 | 123 | self.cache = {} |
120 | 124 |
|
| 125 | + @staticmethod |
| 126 | + def _build_export_schemas( |
| 127 | + schema_nodes: MutableMapping[str, MainSchemaTypesAPI], |
| 128 | + namespaces: list[str] | None = None, |
| 129 | + ) -> SchemaExport: |
| 130 | + """Organize fetched schemas into a per-namespace export structure. |
| 131 | +
|
| 132 | + Filters out system types (Profile/Template) and restricted namespaces |
| 133 | + (see :data:`RESTRICTED_NAMESPACES`), and optionally limits to specific |
| 134 | + namespaces. If the caller requests restricted namespaces they are |
| 135 | + silently excluded and a :func:`warnings.warn` is emitted. |
| 136 | +
|
| 137 | + Returns: |
| 138 | + A :class:`SchemaExport` containing user-defined schemas by namespace. |
| 139 | + """ |
| 140 | + if namespaces: |
| 141 | + restricted = set(namespaces) & set(RESTRICTED_NAMESPACES) |
| 142 | + if restricted: |
| 143 | + warnings.warn( |
| 144 | + f"Restricted namespace(s) {sorted(restricted)} requested but will be excluded from export", |
| 145 | + stacklevel=3, |
| 146 | + ) |
| 147 | + |
| 148 | + ns_map: dict[str, NamespaceExport] = {} |
| 149 | + for schema in schema_nodes.values(): |
| 150 | + if isinstance(schema, (ProfileSchemaAPI, TemplateSchemaAPI)): |
| 151 | + continue |
| 152 | + if schema.namespace in RESTRICTED_NAMESPACES: |
| 153 | + continue |
| 154 | + if namespaces and schema.namespace not in namespaces: |
| 155 | + continue |
| 156 | + ns = schema.namespace |
| 157 | + if ns not in ns_map: |
| 158 | + ns_map[ns] = NamespaceExport() |
| 159 | + schema_dict = schema_to_export_dict(schema) |
| 160 | + if isinstance(schema, GenericSchemaAPI): |
| 161 | + ns_map[ns].generics.append(schema_dict) |
| 162 | + else: |
| 163 | + ns_map[ns].nodes.append(schema_dict) |
| 164 | + return SchemaExport(namespaces=ns_map) |
| 165 | + |
121 | 166 | def validate(self, data: dict[str, Any]) -> None: |
122 | 167 | SchemaRoot(**data) |
123 | 168 |
|
@@ -497,6 +542,32 @@ async def fetch( |
497 | 542 |
|
498 | 543 | return branch_schema.nodes |
499 | 544 |
|
| 545 | + async def export( |
| 546 | + self, |
| 547 | + branch: str | None = None, |
| 548 | + namespaces: list[str] | None = None, |
| 549 | + ) -> SchemaExport: |
| 550 | + """Export user-defined schemas organized by namespace. |
| 551 | +
|
| 552 | + Fetches schemas from the server, filters out system types and |
| 553 | + restricted namespaces (see :data:`RESTRICTED_NAMESPACES`), and returns |
| 554 | + a :class:`SchemaExport` object with per-namespace data. Restricted |
| 555 | + namespaces such as ``Core`` and ``Builtin`` are always excluded even if |
| 556 | + explicitly listed in *namespaces*; a warning is emitted when this |
| 557 | + happens. |
| 558 | +
|
| 559 | + Args: |
| 560 | + branch: Branch to export from. Defaults to default_branch. |
| 561 | + namespaces: Optional list of namespaces to include. If empty/None, |
| 562 | + all user-defined namespaces are exported. |
| 563 | +
|
| 564 | + Returns: |
| 565 | + A :class:`SchemaExport` containing user-defined schemas by namespace. |
| 566 | + """ |
| 567 | + branch = branch or self.client.default_branch |
| 568 | + schema_nodes = await self.fetch(branch=branch, namespaces=namespaces, populate_cache=False) |
| 569 | + return self._build_export_schemas(schema_nodes=schema_nodes, namespaces=namespaces) |
| 570 | + |
500 | 571 | async def get_graphql_schema(self, branch: str | None = None) -> str: |
501 | 572 | """Get the GraphQL schema as a string. |
502 | 573 |
|
@@ -739,6 +810,32 @@ def fetch( |
739 | 810 |
|
740 | 811 | return branch_schema.nodes |
741 | 812 |
|
| 813 | + def export( |
| 814 | + self, |
| 815 | + branch: str | None = None, |
| 816 | + namespaces: list[str] | None = None, |
| 817 | + ) -> SchemaExport: |
| 818 | + """Export user-defined schemas organized by namespace. |
| 819 | +
|
| 820 | + Fetches schemas from the server, filters out system types and |
| 821 | + restricted namespaces (see :data:`RESTRICTED_NAMESPACES`), and returns |
| 822 | + a :class:`SchemaExport` object with per-namespace data. Restricted |
| 823 | + namespaces such as ``Core`` and ``Builtin`` are always excluded even if |
| 824 | + explicitly listed in *namespaces*; a warning is emitted when this |
| 825 | + happens. |
| 826 | +
|
| 827 | + Args: |
| 828 | + branch: Branch to export from. Defaults to default_branch. |
| 829 | + namespaces: Optional list of namespaces to include. If empty/None, |
| 830 | + all user-defined namespaces are exported. |
| 831 | +
|
| 832 | + Returns: |
| 833 | + A :class:`SchemaExport` containing user-defined schemas by namespace. |
| 834 | + """ |
| 835 | + branch = branch or self.client.default_branch |
| 836 | + schema_nodes = self.fetch(branch=branch, namespaces=namespaces, populate_cache=False) |
| 837 | + return self._build_export_schemas(schema_nodes=schema_nodes, namespaces=namespaces) |
| 838 | + |
742 | 839 | def get_graphql_schema(self, branch: str | None = None) -> str: |
743 | 840 | """Get the GraphQL schema as a string. |
744 | 841 |
|
|
0 commit comments