fix: emit loadable YAML for cardinality-many relationships - #1306
fix: emit loadable YAML for cardinality-many relationships#1306rootsec1 wants to merge 5 commits into
Conversation
gmazoyer
left a comment
There was a problem hiding this comment.
The unit test proves the formatter output reaches MANY_REF and passes validation. It stops there. Nothing runs the real object get --output yaml then object load path against a server. test_get_list_yaml in tests/integration/test_enduser_cli.py only parses the YAML, and I found no object load call anywhere in tests/integration/. Issue #1274 says the failing round trip is covered by an integration test, but I could not find one in this repo. Maybe we should consider to add one.
| refs = [r for p in peers if (r := _related_node_ref(p)) is not None] | ||
| if refs: | ||
| entry[rel_name] = {"data": refs} | ||
| entry[rel_name] = refs |
There was a problem hiding this comment.
Seems like a correct a minimal fix that describe what our documentation actually says.
| Produces YAML that is round-trippable with ``infrahubctl object load``. | ||
| Empty/null attribute values and unset relationships are omitted so the | ||
| output can be loaded back without validation errors. |
There was a problem hiding this comment.
The module docstring says the output is round-trippable with infrahubctl object load. With #1275 open, many relationships of kind Generic are still dropped from the output (infrahub_sdk/node/node.py:1507-1508 skips them). A loaded document silently loses those. Not introduced by this PR though.
polmichel
left a comment
There was a problem hiding this comment.
This mocking pattern does exist in other tests in the project, but we're trying to move away from it. Let me know if it makes sense!
Thanks for the contribution
|
|
||
| assert rel_info.format == RelationshipDataFormat.MANY_REF | ||
| assert rel_info.is_reference | ||
| assert errors == [] |
There was a problem hiding this comment.
We try to avoid MagicMock() and similar mocking libraries in our unit tests. We recently added this rule to our LLM coding rules: .agents/rules/python-testing.md.
The reason is that we'd rather have a less isolated and slower test than one that looks like it protects against regressions but doesn't, because the mocks no longer match the real code.
Existing tests such tests.unit.sdk.spec.test_object.test_validate_object use InfrahubClient() and the client.schema.set_cache() method to do so.
There was a problem hiding this comment.
Updated in 49feedc: I replaced the mock-based regression setup with a real InfrahubClient and client.schema.set_cache(), following the existing project pattern. The formatter tests pass 21/21, and format, Ruff, ty, and mypy are all clean. Thanks for the guidance!
There was a problem hiding this comment.
1 issue found across 2 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="tests/integration/test_enduser_cli.py">
<violation number="1" location="tests/integration/test_enduser_cli.py:235">
P3: This test persists 3 named objects (two BuiltinTag, one InfraRack) in the shared Infrahub test instance and never deletes them, and it extends the shared schema via schema.load without reverting. tests/AGENTS.md requires cleaning up resources in integration tests, and sibling tests in this class follow a create/verify/delete pattern. Add a teardown/delete step for the created objects so repeated runs don't accumulate data in the persistent instance.</violation>
</file>
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
| tags.append(tag) | ||
|
|
||
| rack_name = f"yaml-round-trip-rack-{suffix}" | ||
| rack = await client.create(kind="InfraRack", name=rack_name, tags=tags) |
There was a problem hiding this comment.
P3: This test persists 3 named objects (two BuiltinTag, one InfraRack) in the shared Infrahub test instance and never deletes them, and it extends the shared schema via schema.load without reverting. tests/AGENTS.md requires cleaning up resources in integration tests, and sibling tests in this class follow a create/verify/delete pattern. Add a teardown/delete step for the created objects so repeated runs don't accumulate data in the persistent instance.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At tests/integration/test_enduser_cli.py, line 235:
<comment>This test persists 3 named objects (two BuiltinTag, one InfraRack) in the shared Infrahub test instance and never deletes them, and it extends the shared schema via schema.load without reverting. tests/AGENTS.md requires cleaning up resources in integration tests, and sibling tests in this class follow a create/verify/delete pattern. Add a teardown/delete step for the created objects so repeated runs don't accumulate data in the persistent instance.</comment>
<file context>
@@ -208,6 +212,46 @@ def test_create_missing_args(self, base_dataset: None) -> None:
+ tags.append(tag)
+
+ rack_name = f"yaml-round-trip-rack-{suffix}"
+ rack = await client.create(kind="InfraRack", name=rack_name, tags=tags)
+ await rack.save()
+
</file context>
There was a problem hiding this comment.
Good catch — the test now deletes the rack and both tags in a finally block, so cleanup also runs when the get/load round trip fails. The schema extension remains scoped to the disposable class-owned Infrahub instance.
There was a problem hiding this comment.
All reported issues were addressed across 1 file (changes from recent commits).
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
Fixes #1274.
object get --output yamlwraps populated cardinality-many HFID references in adatadictionary, which the loader reserves for nested objects and therefore rejects when it contains a string list. Emit the already-supported plain HFID list instead and cover the formatter-to-loader path with a regression test.Cardinality-one output, empty-relationship omission, and multi-component HFIDs are unchanged. Generic-kind relationship omission is excluded and remains tracked in #1275.
Tested with:
uv run pytest -q tests/unit/ctl/formatters/test_yaml.py tests/unit/sdk/spec/test_object.py(49 passed)COLUMNS=140 uv run pytest -q tests/unit(1819 passed, 1 xfailed)uv run invoke formatuv run invoke lint-codeuv run invoke docs-validateuv run invoke lint-docsuv run towncrier build --draft --version 1.23.2