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