Releases: opsmill/infrahub-sdk-python
Release list
v1.23.1
1.23.1 - 2026-08-28
Fixed
- Fixed
client.branch.validate()andinfrahubctl branch validate, which raised aGraphQLErroragainst every supported Infrahub server because the mutation requested amessagesfield that was removed fromBranchValidatein Infrahub 1.1.0. (#1263) - The queries generated by
all(),filters(),get()and relationshipfetch()no longer requestcounton cardinality-many relationships. The SDK never read that value, and Infrahub resolved it with one extra database query per returned node and per relationship, on top of preventing the peer reads of those nodes from being batched into a single query.
v1.23.0
1.23.0 - 2026-08-19
Removed
- Removed
client.branch.diff_data()from both the async and sync clients. The method relied on aGET /api/diff/dataREST endpoint that does not exist in Infrahub, so every call returned a 404. Useclient.get_diff_tree()to retrieve the full diff of a branch against its base branch, orclient.get_diff_summary()for the list of changed nodes; both use theDiffTreeGraphQL query. (#325)
Added
- Added the Infrahub deployment ID to the
infrahubctl infocommand output and aget_server_information()method (returning the server version and deployment ID) on the async and sync clients. (#1017) - Added transparent retry of HTTP 429 (rate-limited) responses on both
InfrahubClientandInfrahubClientSync. Retries use jittered exponential backoff and honour a server-providedRetry-Afterheader (delta-seconds or HTTP-date). The behaviour is tunable through four newConfigfields (rate_limit_retry_enabled,rate_limit_max_retries,rate_limit_backoff_base,rate_limit_backoff_max), and a newRateLimitErrorexception is raised when retries are exhausted. (#1124) - Added support for tagging SDK requests with a priority via a new
X-Priorityheader. APriorityenum (high,medium,low) is available frominfrahub_sdk.constants; setConfig.priority(env varINFRAHUB_PRIORITY) for a client-wide default emitted on every request, or passpriority=to individual operations to override it per request. When unset, no header is sent. Works identically onInfrahubClientandInfrahubClientSync. (#1151) - Add
infrahubctl schema formatcommand, an opinionated offline formatter that normalises the key ordering of schema files. Optional flags can also strip redundant default values (--strip-defaults), sort attributes/relationships byorder_weight(--sort-by-order-weight), and backfill a missingorder_weight(--backfill-order-weight). - Added
retry()andcancel()methods to the task manager. TheTaskmodel now exposesavailable_actionsalong withcan_retry/can_cancelhelpers. - Added an opt-in
include_diagnosticsflag to the task manager'sall(),filter(), andget()methods. When enabled, tasks expose anerrorfield, andwebhook-sendtasks are returned asWebhookDeliveryTaskinstances carryinghttp_request/http_responsedelivery details. - Added support for the new
IPAddressattribute kind. Values are exposed as bareipaddress.IPv4Address/IPv6Addressobjects (no prefix) and serialized to a bare-address string when writing, alongside the existingIPHostandIPNetworkkinds. - The JSON schema generated for
.infrahub.ymlnow warns when a definition has not said what it depends on, so YAML language servers flag it while the file is being edited. A Python transform or generator definition with nowatchblock is flagged, and so is awatchvalue that is not a mapping, including the barewatch:that parses as null and records nothing. Both warnings are advisory only: the models still accept every one of those forms. An emptywatch: {}orfiles: []stays clean, since either one records that the author checked and nothing beyond what Infrahub detects needs watching. The generated schema also picks up thewatchblock on generator definitions, which it was previously rejecting as an unknown property. - The request priority (
X-Priorityheader) can now be carried on the client'sRequestContextvia a newpriorityfield, alongside the existing client-wideConfig.prioritydefault and per-callpriority=override. Resolution precedence is per-callpriority=>request_context.priority>Config.priority> no header. The priority is emitted as a header only and is never included in the mutation body. Works identically onInfrahubClientandInfrahubClientSync. - Import
pyarrowlazily in the line-delimited JSON importer so thatinfrahubctlcommands other thanobject loadno longer require thectlextra (and its heavypyarrowdependency) to be installed.
Changed
-
Paginated queries generated by
all(),filters(),get()and resource pool allocation lookups now passoffsetandlimitas GraphQL variables instead of inlining them in the query text. The query document stays identical across pages, allowing the Infrahub server to reuse its cached query analysis, and the query is now rendered once per call instead of once per page.generate_query_dataalso accepts variable placeholder strings (for example"$offset") for itsoffsetandlimitarguments. -
Raised the default
Config.rate_limit_max_retriesfrom 5 to 10, so a request shed with HTTP 429 keeps retrying (honouringRetry-After) for longer before raisingRateLimitError. This lets background work ride out a longer burst of server-side backpressure. Callers that prefer to give up sooner can lower the value. -
The hand-maintained schema models in
infrahub_sdk.schemaare now backed by the generated write/read contract (infrahub_sdk.schema.generated). Public names, import paths, and behavior methods are unchanged, but a few defaults and constraints now match the server contract:AttributeKind.STRINGhas been removed. It was deprecated andkind="String"was already rejected server-side; useAttributeKind.TEXTinstead.- Write and read models drop unknown fields silently (
extra="ignore"). A submitted field that is not part of the write contract — read-level, internal, or a typo — is dropped rather than rejected, and a read model tolerates additional fields returned by a newer server. - Write-model defaults now match the server contract: relationship
min_count/max_countdefault to0(wasNone), nodebranchdefaults to"aware",generate_profiledefaults toTrue, andgenerate_templatedefaults toFalse. This changes the round-trip output of programmatically-built schemas.
Constructing
AttributeSchema(name=..., kind=AttributeKind.TEXT, ...),NodeSchema,GenericSchema,RelationshipSchema,SchemaRoot, and the read-side*APImodels continues to work unchanged.
v1.22.3
1.22.3 - 2026-08-19
Fixed
- Register the
infrahub_integrationpytest marker under its real name. It was registered asinfrahub_integraton, so integration tests raised aPytestUnknownMarkWarningon every run and failed to collect under--strict-markers. (#1231) - Fixed the
loadandcheckcommand descriptions in theinfrahubctl schemahelp output and generated docs, which were cut off mid-sentence.
v1.23.0b0
1.23.0b0 - 2026-07-29
Added
- Added the Infrahub deployment ID to the
infrahubctl infocommand output and aget_server_information()method (returning the server version and deployment ID) on the async and sync clients. (#1017) - Added a
--dependenciesflag toinfrahubctl marketplace get. When downloading a schema or a collection, it now also resolves and downloads the schemas they depend on, via the marketplace API. Dependencies are grouped by the collection they belong to: prerequisite collections (and, for a single schema, dependencies that are members of a collection) are placed in their own<collection>/directory, while dependencies that belong to no collection land in the output root. Referenced kinds the marketplace cannot resolve are reported as unresolved dependencies. A schema that already exists in the output directory is reconciled to a single file rather than duplicated across directories — kept by default, or overwritten with the new-y/--yesflag. (#1117) - Added transparent retry of HTTP 429 (rate-limited) responses on both
InfrahubClientandInfrahubClientSync. Retries use jittered exponential backoff and honour a server-providedRetry-Afterheader (delta-seconds or HTTP-date). The behaviour is tunable through four newConfigfields (rate_limit_retry_enabled,rate_limit_max_retries,rate_limit_backoff_base,rate_limit_backoff_max), and a newRateLimitErrorexception is raised when retries are exhausted. (#1124) - Added support for tagging SDK requests with a priority via a new
X-Priorityheader. APriorityenum (high,medium,low) is available frominfrahub_sdk.constants; setConfig.priority(env varINFRAHUB_PRIORITY) for a client-wide default emitted on every request, or passpriority=to individual operations to override it per request. When unset, no header is sent. Works identically onInfrahubClientandInfrahubClientSync. (#1151) - Added
infrahubctl marketplace list,search, andshowcommands for browsing schemas and collections on the Infrahub Marketplace. - Added
retry()andcancel()methods to the task manager. TheTaskmodel now exposesavailable_actionsalong withcan_retry/can_cancelhelpers. - Added an opt-in
include_diagnosticsflag to the task manager'sall(),filter(), andget()methods. When enabled, tasks expose anerrorfield, andwebhook-sendtasks are returned asWebhookDeliveryTaskinstances carryinghttp_request/http_responsedelivery details. - Added support for the new
IPAddressattribute kind. Values are exposed as bareipaddress.IPv4Address/IPv6Addressobjects (no prefix) and serialized to a bare-address string when writing, alongside the existingIPHostandIPNetworkkinds. - The request priority (
X-Priorityheader) can now be carried on the client'sRequestContextvia a newpriorityfield, alongside the existing client-wideConfig.prioritydefault and per-callpriority=override. Resolution precedence is per-callpriority=>request_context.priority>Config.priority> no header. The priority is emitted as a header only and is never included in the mutation body. Works identically onInfrahubClientandInfrahubClientSync.
Changed
-
Paginated queries generated by
all(),filters(),get()and resource pool allocation lookups now passoffsetandlimitas GraphQL variables instead of inlining them in the query text. The query document stays identical across pages, allowing the Infrahub server to reuse its cached query analysis, and the query is now rendered once per call instead of once per page.generate_query_dataalso accepts variable placeholder strings (for example"$offset") for itsoffsetandlimitarguments. -
Raised the default
Config.rate_limit_max_retriesfrom 5 to 10, so a request shed with HTTP 429 keeps retrying (honouringRetry-After) for longer before raisingRateLimitError. This lets background work ride out a longer burst of server-side backpressure. Callers that prefer to give up sooner can lower the value. -
The hand-maintained schema models in
infrahub_sdk.schemaare now backed by the generated write/read contract (infrahub_sdk.schema.generated). Public names, import paths, and behavior methods are unchanged, but a few defaults and constraints now match the server contract:AttributeKind.STRINGhas been removed. It was deprecated andkind="String"was already rejected server-side; useAttributeKind.TEXTinstead.- Write and read models drop unknown fields silently (
extra="ignore"). A submitted field that is not part of the write contract — read-level, internal, or a typo — is dropped rather than rejected, and a read model tolerates additional fields returned by a newer server. - Write-model defaults now match the server contract: relationship
min_count/max_countdefault to0(wasNone), nodebranchdefaults to"aware",generate_profiledefaults toTrue, andgenerate_templatedefaults toFalse. This changes the round-trip output of programmatically-built schemas.
Constructing
AttributeSchema(name=..., kind=AttributeKind.TEXT, ...),NodeSchema,GenericSchema,RelationshipSchema,SchemaRoot, and the read-side*APImodels continues to work unchanged.
Fixed
- Fixed several cases where
InfrahubClientSynchad drifted fromInfrahubClient: syncbranch.mergenow applies the same 120-second minimum timeout floor as the async client, and synccreate(allow_upsert=True)now excludes thehfidfrom the mutation payload to avoid server-side upsert overhead. Also corrected an incorrect "feature not supported" message on async artifact fetch and a resource-pool error message typo. - Import
pyarrowlazily in the line-delimited JSON importer so thatinfrahubctlcommands other thanobject loadno longer require thectlextra (and its heavypyarrowdependency) to be installed.
Housekeeping
v1.22.2
1.22.2 - 2026-07-27
Added
- Added a
--dependenciesflag toinfrahubctl marketplace get. When downloading a schema or a collection, it now also resolves and downloads the schemas they depend on, via the marketplace API. Dependencies are grouped by the collection they belong to: prerequisite collections (and, for a single schema, dependencies that are members of a collection) are placed in their own<collection>/directory, while dependencies that belong to no collection land in the output root. Referenced kinds the marketplace cannot resolve are reported as unresolved dependencies. A schema that already exists in the output directory is reconciled to a single file rather than duplicated across directories — kept by default, or overwritten with the new-y/--yesflag. (#1117) - Added
infrahubctl marketplace list,search, andshowcommands for browsing schemas and collections on the Infrahub Marketplace.
Fixed
- Branch names containing URL-significant characters (such as
#or/) are now percent-encoded in the GraphQL URL, so requests against those branches resolve correctly instead of returning a 404. (#1209) - Fixed several cases where
InfrahubClientSynchad drifted fromInfrahubClient: syncbranch.mergenow applies the same 120-second minimum timeout floor as the async client, and synccreate(allow_upsert=True)now excludes thehfidfrom the mutation payload to avoid server-side upsert overhead. Also corrected an incorrect "feature not supported" message on async artifact fetch and a resource-pool error message typo.
Housekeeping
v1.22.1
1.22.1 - 2026-07-03
Added
- Added a
shortest_paths_onlyparameter toInfrahubClient.traverse_paths()and its sync equivalent (defaultNone, deferring to the server). Set it toFalseto return all loopless paths up tomax_pathsinstead of only the shortest one(s); previously path traversal always returned the shortest path(s) because the flag could not be set.PathTraversalResultnow also parsestruncated_at_depth, which is set when the search stopped atmax_depthbefore exhausting the graph andNonewhen it completed within budget. (#1119)
Fixed
- Clarified the
ValidationErrorraised when callingsave(allow_upsert=True)on a node whose human-friendly identifier includes aCoreNumberPool-sourced attribute. The message now explains that the pool assigns a new value on every creation, so the HFID is never stable and the upsert would silently create a duplicate on each run, and points to the idempotent alternatives (look the node up by a stable field and reuse it, or set an explicit id). The resource manager guide was updated to match.
v1.22.0
1.22.0 - 2026-06-23
Added
- Added
query_nameparameter toall(),filters(),count()andget()methods inInfrahubClientandInfrahubClientSyncto be used as meaningful GraphQL operation name for observability (#923) - Add
infrahubctl graphql query-reportto analyze a GraphQL query and report whether it targets unique nodes, which controls whether Infrahub limits artifact regeneration to changed nodes or regenerates all artifacts on any relevant node change. Supports--onlineto fetch the query from the server by name. - Added
OrderByEntryand anOrder.byfield so query results can be ordered by attributes, related-node attributes, or node metadata, e.g.Order(by=[OrderByEntry(field="name__value", direction=OrderDirection.DESC)]). TheOrder.node_metadatafield is deprecated; usebywith thenode_metadata__created_at/node_metadata__updated_atfields instead. - Added graph traversal support for Infrahub 1.10:
InfrahubClient.traverse_paths()(shortest path(s) between two nodes),InfrahubClient.reachable_nodes()(nodes of given kinds reachable from a source), andInfrahubClient.path_exists()(boolean convenience for checks) — all with sync equivalents. Source and destination accept either a node id or anInfrahubNode; kind filters accept kind strings or protocol classes; eachPathNodein the result exposes.fetch()to resolve the full node (store-backed). Calling these against a pre-1.10 server raises a clearVersionNotSupportedError.
Fixed
-
Calling
.save(allow_upsert=True)on a node whose human-friendly identifier contains a CoreNumberPool-sourced attribute now raises a clearValidationErrorinstead of crashing with an opaque backend error. (#339) -
RelatedNode,RelatedNodeSync,RelationshipManagerandRelationshipManagerSyncare now generic over their peer type, andinfrahubctl protocolsparameterises generated relationships accordingly (e.g.device: RelatedNode[NetworkDevice],interfaces: RelationshipManager[NetworkInterface]).Traversing a relationship via
.peer,.peersor indexing now preserves the peer's type instead of collapsing to the dynamicInfrahubNode, so chains such asdevice.rack.peer.name.valuetype-check under mypy/ty without casts. Existing un-parameterisedRelatedNode/RelationshipManagerusage is unaffected — the peer type defaults toInfrahubNode/InfrahubNodeSync, preserving current behaviour. (#1063) (#1063) -
Cardinality-one relationships in generated protocols are now typed with a
RelationshipAttribute[...]descriptor. It still reads back as a typedRelatedNode[Peer](so.peerkeeps the peer type), but it accepts assignment of an id string, an HFID, a peer node, orNone— mirroring the runtimeInfrahubNode.__setattr__, which wraps the assigned value in aRelatedNode.Previously relationships were typed read-only as
RelatedNode, so the documented way of setting a relationship (node.rel = "<id>"ornode.rel = peer_node) failed under mypy/ty with anassignmenterror. The descriptor only appears in generated protocols and is never instantiated at runtime.Because the new typing lives in the generated protocols, existing projects must regenerate them with
infrahubctl protocolsto pick up the change — it does not take effect for already-generated protocol files. (#1064) (#1064) -
Calling
.save(allow_upsert=True)on a node hydrated byfrom_graphqlno longer silently clears optional one-cardinality relationships that the GraphQL response didn't fetch. Explicitly assigningnode.rel = Nonestill clears the relationship. (#1080) -
Send the GraphQL operation name as
operationNamein the request payload so tracing and observability tools can identify each query.
v1.21.1
Changed
infrahubctl marketplace get --collectionnow downloads each member schema individually into a<output_dir>/<collection name>/<schema name>.ymllayout (for exampleschemas/base-schemas/dcim.yml), instead of dumping version-suffixed files flat into the output directory. Filenames no longer carry the version, matching single-schema downloads, so re-downloading a collection overwrites cleanly rather than accumulating stale versions. If two members share a schema name across namespaces, those members are written to<output_dir>/<collection name>/<namespace>/<schema name>.ymlinstead of overwriting each other. (#1057)
Fixed
- Fix
infrahubctlprinting a spuriousError: 1and Python traceback after the human-readable error message when a command exits withtyper.Exit. The CLI now exits cleanly with only the intended error output. (#1047)****
v1.21.0
1.21.0 - 2026-05-29
Added
- Add
infrahubctl marketplace getfor fetching schemas and collections from the Infrahub Marketplace. Auto-detects schemas vs collections by namespace/name, supports--versionfor pinning,--collectionto force the collection path,--stdoutto stream content for piping (status messages on stderr), and--marketplace-url/INFRAHUB_MARKETPLACE_URLto point at staging or local instances. (#952)
Changed
- Change default value of
sync_with_gitparameter inbranch.create()fromTruetoFalseto match UI behavior. (#224)
Fixed
- Improve error message when a single node is passed to a cardinality-many relationship. (#174)
v1.20.1
1.20.1 - 2026-05-20
Added
-
Added SHA-1 idempotency primitives for
CoreFileObjectnodes:InfrahubNode.matches_local_checksum(source)/ sync variant — compare a localbytes | Path | BinaryIOsource against the node's server-stored checksum without invoking a transfer.InfrahubNode.upload_if_changed(source, name=None)/ sync variant — stage + save only when the local source differs from the server, returning anUploadResult(was_uploaded, checksum)dataclass.download_file(..., skip_if_unchanged=True)— short-circuit the download whendestalready exists on disk with a matching SHA-1. Returns0bytes written when skipped.
A shared
sha1_of_sourcehelper (streaming, 64 KiB chunks) centralises the hashing convention ininfrahub_sdk.file_handler.
Fixed
- Skip mandatory field validation during object loading when
object_profileis specified. (#908) - Render schema rejections originating in an
extensions:block as a readable one-line message ininfrahubctl schema load, instead of crashing withValueError: invalid literal for int(). (#1007) - Add
MERGINGbranch status so that a merging branch can still be correctly retrieved. (#1037)