Overview
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.
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.
# Basic type hints
def percentage(num1: int, num2: int) -> float:
return (num1 / num2) * 100
Leveraging Python protocols
The Python SDK for Infrahub has been designed to automatically work with any schemas loaded into Infrahub. Internally, the Python SDK generates dynamic Python representations of your schemas.
While this approach improves code readability, it presents challenges with type checking because each object has a different signature based on your schema.
Without protocols
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.
# Type checker cannot verify the existence of 'description'
blue_tag = client.get("BuiltinTag", name__value="blue") # blue_tag is of type InfrahubNode or InfrahubNodeSync
blue_tag.description.value = "The blue tag" # Mypy: error: "InfrahubNode" has no attribute "description"
blue_tag.save()
With protocols
To provide strict type checking while maintaining platform extensibility, the Python SDK integrates with Python Protocols.
For all core and internal models, the protocols are included in the SDK under infrahub_sdk.protocols
.
Whenever you need to specify the kind of object you're working with as a string, you can use the corresponding protocol instead.
from infrahub_sdk.protocols import BuiltinTag
# Type checker can now verify all attributes
blue_tag = client.get(BuiltinTag, name__value="blue") # blue_tag is of type BuiltinTag
blue_tag.description.value = "The blue tag" # No type errors
blue_tag.save()
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.
More information about Python Protocols can be found here
Generating custom protocols based on your schema
You can generate Python Protocols for your own models using the infrahubctl protocols
command. This supports both synchronous and asynchronous Python code.
It's possible to provide the schema from a local directory or from an existing Infrahub Instance.
- Existing Infrahub Instance
- Local Directory
export INFRAHUB_ADDRESS=https://infrahub.example.com
infrahubctl protocols --out lib/protocols.py --sync
infrahubctl protocols --schemas schemas/tag.schema.yml --out lib/protocols.py
When using a local directory, Protocols for Profiles and Object Templates won't be generated.
Using custom protocols
After generation, you can import and use your custom protocols as describe below.
from lib.protocols import MyOwnObject
# Use your custom protocol
my_object = client.get(MyOwnObject, name__value="example")
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