Skip to content

Commit d107906

Browse files
committed
Update protocols to support Template and fix support for Sync
1 parent 0510d52 commit d107906

File tree

18 files changed

+25010
-154
lines changed

18 files changed

+25010
-154
lines changed

.vale/styles/Infrahub/branded-terms-case-swap.yml

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,31 @@ ignorecase: false
66
action:
77
name: replace
88
swap:
9-
(?i:[^/]Github): GitHub
10-
(?i:gitpod): GitPod
11-
(?i:[^/]Graphql): GraphQL
9+
(?:ansible): Ansible
10+
(?:[^"]docker): Docker
11+
(?:[Dd]ockerhub): DockerHub
12+
(?:[^/][Gg]ithub): GitHub
13+
(?:[Gg]itlab): GitLab
14+
(?:gitpod): GitPod
15+
(?:grafana): Grafana
16+
(?:[^/][Gg]raphql): GraphQL
17+
(?:[Ii]nflux[Dd]b): InfluxDB
1218
infrahub(?:\s|$): Infrahub
13-
(?i:Openconfig): OpenConfig
19+
(?:jinja2): Jinja2
20+
(?:k3s): K3s
21+
(?:k8s): K8s
22+
(?:kubernetes): Kubernetes
23+
(?:[^/][Mm]y[Ss]ql): MySQL
24+
(?:neo4j): Neo4j
25+
(?:[^/][Nn]ginx): NGINX
26+
(?:[Nn]odejs): Node.js
27+
(?:[^/][Oo]penapi): OpenAPI
28+
(?:Openconfig): OpenConfig
1429
opsmill(?:\s|$): OpsMill
30+
(?:[Pp]ostgre[Ss]ql): PostgreSQL
31+
(?:[^/]prometheus): Prometheus
32+
(?:[^/-]python): Python
33+
(?:[Rr]abbitmq): RabbitMQ
34+
(?:[^/]terraform): Terraform
35+
(?:ubuntu): Ubuntu
36+
(?:[Vv]s\W?[Cc]ode): VS Code
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add `invoke lint-doc` command to help run the docs linters locally

changelog/+guide-typing.added.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add a Guide related to Python Typing

changelog/+protocol-sync.fixed.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix support for Sync when generating Python Protocols

changelog/329.added.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add support for object Template when generating protocols
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
---
2+
title: Strict Typing in Python
3+
---
4+
5+
import Tabs from '@theme/Tabs';
6+
import TabItem from '@theme/TabItem';
7+
8+
# Overview
9+
10+
This guide explains how to use Python's type system effectively with the Infrahub SDK, focusing on the use of Protocols for type-safe development.
11+
12+
:::note What is Python Typing
13+
14+
Python typing allows you to specify the expected data types of variables, function arguments, and return values to improve code clarity and catch bugs early.
15+
16+
```python
17+
# Basic type hints
18+
def percentage(num1: int, num2: int) -> float:
19+
return (num1 / num2) * 100
20+
```
21+
22+
:::
23+
24+
## Leveraging Python protocols
25+
26+
The Python SDK for Infrahub has been designed to automatically work with any schemas loaded into Infrahub.
27+
Internally, the Python SDK generates dynamic Python representations of your schemas.
28+
29+
While this approach improves code readability, it presents challenges with type checking because each object has a different signature based on your schema.
30+
31+
### Without protocols
32+
33+
In the example below, type checkers like Mypy will typically complain about `blue_tag.description.value` because `description` is a dynamic parameter generated by the SDK.
34+
35+
```python
36+
# Type checker cannot verify the existence of 'description'
37+
blue_tag = client.get("BuiltinTag", name__value="blue") # blue_tag is of type InfrahubNode or InfrahubNodeSync
38+
blue_tag.description.value = "The blue tag" # Mypy: error: "InfrahubNode" has no attribute "description"
39+
blue_tag.save()
40+
```
41+
42+
### With protocols
43+
44+
To provide strict type checking while maintaining platform extensibility, the Python SDK integrates with Python Protocols.
45+
46+
For all core and internal models, the protocols are included in the SDK under `infrahub_sdk.protocols`.
47+
Whenever you need to specify the kind of object you're working with as a string, you can use the corresponding protocol instead.
48+
49+
```python
50+
from infrahub_sdk.protocols import BuiltinTag
51+
52+
# Type checker can now verify all attributes
53+
blue_tag = client.get(BuiltinTag, name__value="blue") # blue_tag is of type BuiltinTag
54+
blue_tag.description.value = "The blue tag" # No type errors
55+
blue_tag.save()
56+
```
57+
58+
:::note Python Protocols
59+
60+
Python Protocols, introduced in PEP 544, define a set of method and property signatures that a class must implement to be considered a match, enabling structural subtyping (also known as "duck typing" with static checks). They allow you to specify behavior without requiring inheritance, making code more flexible and type-safe.
61+
62+
More information about Python Protocols can be found [here](https://typing.python.org/en/latest/spec/protocol.html)
63+
64+
:::
65+
66+
## Generating custom protocols based on your schema
67+
68+
You can generate Python Protocols for your own models using the `infrahubctl protocols` command. This supports both synchronous and asynchronous Python code.
69+
70+
It's possible to provide the schema from a local directory or from an existing Infrahub Instance.
71+
72+
<Tabs groupId="local-remote">
73+
<TabItem value="Existing Infrahub Instance" default>
74+
75+
```shell
76+
export INFRAHUB_ADDRESS=https://infrahub.example.com
77+
infrahubctl protocols --out lib/protocols.py --sync
78+
```
79+
80+
</TabItem>
81+
<TabItem value="Local Directory" default>
82+
83+
```shell
84+
infrahubctl protocols --schemas schemas/tag.schema.yml --out lib/protocols.py
85+
```
86+
87+
</TabItem>
88+
</Tabs>
89+
90+
> When using a local directory, Protocols for Profiles and Object Templates won't be generated.
91+
92+
## Using custom protocols
93+
94+
After generation, you can import and use your custom protocols as describe below.
95+
96+
```python
97+
from lib.protocols import MyOwnObject
98+
99+
# Use your custom protocol
100+
my_object = client.get(MyOwnObject, name__value="example")
101+
```
102+
103+
> if you don't have your own Python module, it's possible to use relative path by having the `procotols.py` in the same directory as your script/transform/generator

docs/sidebars-python-sdk.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ const sidebars: SidebarsConfig = {
2121
'guides/branches',
2222
'guides/store',
2323
'guides/tracking',
24+
'guides/python-typing',
2425
'guides/batch',
2526
'guides/object-storage',
2627
'guides/resource-manager',

infrahub_sdk/ctl/cli_commands.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020

2121
from .. import __version__ as sdk_version
2222
from ..async_typer import AsyncTyper
23-
from ..code_generator import CodeGenerator
2423
from ..ctl import config
2524
from ..ctl.branch import app as branch_app
2625
from ..ctl.check import run as run_check
@@ -42,6 +41,7 @@
4241
)
4342
from ..ctl.validate import app as validate_app
4443
from ..exceptions import GraphQLError, ModuleImportError
44+
from ..protocols_generator.generator import CodeGenerator
4545
from ..schema import MainSchemaTypesAll, SchemaRoot
4646
from ..template import Jinja2Template
4747
from ..template.exceptions import JinjaTemplateError

infrahub_sdk/ctl/constants.py

Lines changed: 0 additions & 115 deletions
This file was deleted.

infrahub_sdk/protocols_generator/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)