|  | 
|  | 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 | +``` | 
0 commit comments