Skip to content

Commit 785fe6e

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

File tree

16 files changed

+24855
-52
lines changed

16 files changed

+24855
-52
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: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
---
2+
title: Strict Typing in Python
3+
---
4+
5+
# Overview
6+
7+
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.
8+
9+
:::note What is Python Typing
10+
11+
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.
12+
13+
```python
14+
# Basic type hints
15+
def percentage(num1: int, num2: int) -> float:
16+
return (num1 / num2) * 100
17+
```
18+
19+
:::
20+
21+
## Leveraging Python protocols
22+
23+
The Python SDK for Infrahub has been designed to automatically work with any schemas loaded into Infrahub.
24+
Internally, the Python SDK generates dynamic Python representations of your schemas.
25+
26+
While this approach improves code readability, it presents challenges with type checking because each object has a different signature based on your schema.
27+
28+
### Without protocols
29+
30+
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.
31+
32+
```python
33+
# Type checker cannot verify the existence of 'description'
34+
blue_tag = client.get("BuiltinTag", name__value="blue") # blue_tag is of type InfrahubNode or InfrahubNodeSync
35+
blue_tag.description.value = "The blue tag" # Mypy: error: "InfrahubNode" has no attribute "description"
36+
blue_tag.save()
37+
```
38+
39+
### With protocols
40+
41+
To provide strict type checking while maintaining platform extensibility, the Python SDK integrates with Python Protocols.
42+
43+
For all core and internal models, the protocols are included in the SDK under `infrahub_sdk.protocols`.
44+
Whenever you need to specify the kind of object you're working with as a string, you can use the corresponding protocol instead.
45+
46+
```python
47+
from infrahub_sdk.protocols import BuiltinTag
48+
49+
# Type checker can now verify all attributes
50+
blue_tag = client.get(BuiltinTag, name__value="blue") # blue_tag is of type BuiltinTag
51+
blue_tag.description.value = "The blue tag" # No type errors
52+
blue_tag.save()
53+
```
54+
55+
:::note Python Protocols
56+
57+
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.
58+
59+
:::
60+
61+
## Generating custom protocols based on your schema
62+
63+
You can generate Python Protocols for your own models using the `infrahubctl protocols` command. This supports both synchronous and asynchronous Python code.
64+
65+
```shell
66+
# Generate protocols for your schema
67+
infrahubctl protocols --schemas schemas/tag.schema.yml --out lib/protocols.py
68+
```
69+
70+
After generation, you can import and use your custom protocols:
71+
72+
```python
73+
from lib.protocols import MyOwnObject
74+
75+
# Use your custom protocol
76+
my_object = client.get(MyOwnObject, name__value="example")
77+
```

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/protocols_generator/__init__.py

Whitespace-only changes.
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
TEMPLATE_FILE_NAME = "template.j2"
2+
3+
ATTRIBUTE_KIND_MAP = {
4+
"ID": "String",
5+
"Text": "String",
6+
"TextArea": "String",
7+
"DateTime": "DateTime",
8+
"Email": "String",
9+
"Password": "String",
10+
"HashedPassword": "HashedPassword",
11+
"URL": "URL",
12+
"File": "String",
13+
"MacAddress": "MacAddress",
14+
"Color": "String",
15+
"Dropdown": "Dropdown",
16+
"Number": "Integer",
17+
"Bandwidth": "Integer",
18+
"IPHost": "IPHost",
19+
"IPNetwork": "IPNetwork",
20+
"Boolean": "Boolean",
21+
"Checkbox": "Boolean",
22+
"List": "ListAttribute",
23+
"JSON": "JSONAttribute",
24+
"Any": "AnyAttribute",
25+
}

0 commit comments

Comments
 (0)