Component
Python SDK
Infrahub SDK version
1.23.1 (verified on develop @ 9b39ab4)
Current Behavior
InfrahubNode.artifact_fetch() documents that it parses JSON-typed artifacts, but it always returns a string.
infrahub_sdk/node/node.py, sync at :2261 (async at :1026):
def artifact_fetch(self, name: str) -> str | dict[str, Any]:
"""Fetch the stored content of a named artifact for this node.
Returns:
str | dict[str, Any]: The artifact content. Returns a parsed object for
JSON-typed artifacts and a string for text-typed artifacts.
...
"""
self._validate_artifact_support(ARTIFACT_FETCH_FEATURE_NOT_SUPPORTED_MESSAGE)
artifact = self._client.get(kind="CoreArtifact", name__value=name, object__ids=[self.id])
return self._client.object_store.get(identifier=artifact._get_attribute(name="storage_id").value)
No parsing happens. ObjectStore.get() is declared -> str (infrahub_sdk/object_store.py:131) and ends with return resp.text. The artifact's content_type is never consulted, so a application/json artifact comes back as a raw JSON string while the docstring and the str | dict[str, Any] return type both promise otherwise.
Expected Behavior
The docstring, the annotation and the behaviour should agree. Two ways to get there, and the choice is a product decision rather than an obvious fix:
- Make the implementation match the docs — read the artifact's
content_type and json.loads() the body for JSON-typed artifacts. This is the behaviour the docstring describes and, in our experience, the behaviour callers want; it keeps the existing str | dict[str, Any] annotation honest.
- Make the docs match the implementation — narrow the return to
-> str and drop the parsing claim, leaving the caller to parse.
Worth noting that the artifact node is already fetched in the method, so content_type is available without an extra request — the parsing option costs nothing in round trips.
We would suggest the first: the str | dict[str, Any] signature indicates parsing was the intent, and a caller who has to parse anyway gains nothing from the union type.
Steps to Reproduce
client = InfrahubClientSync(address="http://localhost:8000")
node = client.get(kind="MyArtifactTarget", id="<node id>")
content = node.artifact_fetch(name="<name of a JSON artifact>")
print(type(content)) # <class 'str'> — docstring says a parsed object
Additional Information
This has a concrete downstream effect. The opsmill.infrahub Ansible collection currently fetches artifacts through hand-built REST calls and does branch on content_type to parse JSON. It is being moved onto this supported method (opsmill/infrahub-ansible#37), and taking the docstring at face value would silently change the module's return shape from parsed JSON to a string — so the discrepancy is a migration hazard, not only a documentation nit.
Adjacent: #1195 (enforce docstring↔signature consistency rules, incl. DOC201) would not catch this, since the docstring does document a Returns section — it is the content that is wrong, not the presence.
Component
Python SDK
Infrahub SDK version
1.23.1 (verified on
develop@ 9b39ab4)Current Behavior
InfrahubNode.artifact_fetch()documents that it parses JSON-typed artifacts, but it always returns a string.infrahub_sdk/node/node.py, sync at:2261(async at:1026):No parsing happens.
ObjectStore.get()is declared-> str(infrahub_sdk/object_store.py:131) and ends withreturn resp.text. The artifact'scontent_typeis never consulted, so aapplication/jsonartifact comes back as a raw JSON string while the docstring and thestr | dict[str, Any]return type both promise otherwise.Expected Behavior
The docstring, the annotation and the behaviour should agree. Two ways to get there, and the choice is a product decision rather than an obvious fix:
content_typeandjson.loads()the body for JSON-typed artifacts. This is the behaviour the docstring describes and, in our experience, the behaviour callers want; it keeps the existingstr | dict[str, Any]annotation honest.-> strand drop the parsing claim, leaving the caller to parse.Worth noting that the artifact node is already fetched in the method, so
content_typeis available without an extra request — the parsing option costs nothing in round trips.We would suggest the first: the
str | dict[str, Any]signature indicates parsing was the intent, and a caller who has to parse anyway gains nothing from the union type.Steps to Reproduce
Additional Information
This has a concrete downstream effect. The
opsmill.infrahubAnsible collection currently fetches artifacts through hand-built REST calls and does branch oncontent_typeto parse JSON. It is being moved onto this supported method (opsmill/infrahub-ansible#37), and taking the docstring at face value would silently change the module's return shape from parsed JSON to a string — so the discrepancy is a migration hazard, not only a documentation nit.Adjacent: #1195 (enforce docstring↔signature consistency rules, incl. DOC201) would not catch this, since the docstring does document a
Returnssection — it is the content that is wrong, not the presence.