-
Notifications
You must be signed in to change notification settings - Fork 7
Prep release v1.16.0 #671
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Prep release v1.16.0 #671
Conversation
Configure RichHandler to only show file paths (e.g., object.py:568) when the --debug flag is used. This provides cleaner output for normal usage while preserving detailed logging for troubleshooting. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
fix(cli): hide file paths in log output unless debug mode enabled
Merge develop into infrahub-develop
Merge stable into develop
Merge develop into infrahub-develop
* Convert project to UV
Merge stable into develop
Merge develop into infrahub-develop
Merge 'stable' into 'develop' with resolved conflicts
Update infrahub-testcontainers
Merge develop into infrahub-develop
Remove support for Python 3.9
Upgrade ruff
Use ruff version from uv.lock in CI
Signed-off-by: Fatih Acar <fatih@opsmill.com>
Allow recursive convertion to InfrahubNode objects
* merge develop to infrahub-develop * fix python lint
…114-infp388-branch-cleanup-mechanism # Conflicts: # infrahub_sdk/node/constants.py # tests/unit/sdk/test_node.py
…hub-develop Correct autofixable ruff rules for Optional
also add a better docstring
…nup-mechanism Add `infrahubctl branch report` command
WalkthroughThis pull request performs a comprehensive modernization of the Python SDK and CLI tooling. Major changes include: (1) replacing Poetry with UV as the package manager across CI/CD workflows, configuration files, and documentation; (2) converting pyproject.toml from Poetry format to PEP 621 standard with Hatch as the build backend; (3) modernizing Python type hints to use PEP 604 union syntax ( Pre-merge checks❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Deploying infrahub-sdk-python with
|
| Latest commit: |
4952028
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://1c52bb3e.infrahub-sdk-python.pages.dev |
| Branch Preview URL: | https://wvd-20251201-release-1-16.infrahub-sdk-python.pages.dev |
Codecov Report❌ Patch coverage is @@ Coverage Diff @@
## stable #671 +/- ##
==========================================
+ Coverage 75.48% 75.80% +0.32%
==========================================
Files 113 113
Lines 9512 9660 +148
Branches 1893 1473 -420
==========================================
+ Hits 7180 7323 +143
- Misses 1832 1841 +9
+ Partials 500 496 -4
Flags with carried forward coverage won't be shown. Click here to find out more.
... and 5 files with indirect coverage changes 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (4)
infrahub_sdk/batch.py (1)
4-19: AlignBatchTask.tasktype signature withBatchTaskSyncand actual usage
BatchTask.taskis typed asCallable[[Any], Awaitable[Any]], but it's invoked astask.task(*task.args, **task.kwargs)whereargsistuple[Any, ...]. The sync counterpartBatchTaskSynccorrectly usesCallable[..., Any]. With mypy'sdisallow_untyped_defs = trueenabled for this module, the current annotation will fail type checking.Update
BatchTask.taskto:@dataclass class BatchTask: - task: Callable[[Any], Awaitable[Any]] + task: Callable[..., Awaitable[Any]] args: tuple[Any, ...] kwargs: dict[str, Any] node: Any | None = NoneThis aligns the async variant with its sync counterpart and correctly reflects how the callable is invoked.
infrahub_sdk/async_typer.py (1)
5-28: ParameterizeCallableinmaybe_run_asyncfor mypy strict compatibilityWith
disallow_untyped_defs = trueenabled, unparameterizedCallableon line 14 will trigger mypy errors.Update to:
- def maybe_run_async(decorator: Callable, func: Callable) -> Any: + def maybe_run_async(decorator: Callable[..., Any], func: Callable[..., Any]) -> Any:This preserves runtime behavior and satisfies mypy's type parameter requirements.
infrahub_sdk/ctl/check.py (1)
218-223: Malformed JSON string whenformat_json=Trueand no checks are foundThe line:
print('{"level": "WARNING", "message": "message", ""No check found"}')produces invalid JSON (there’s an extra
""No check found"fragment without a key/value pair), which will break consumers expecting parseable output.Consider correcting it to a single well‑formed message, e.g.:
- else: - print('{"level": "WARNING", "message": "message", ""No check found"}') + else: + print('{"level": "WARNING", "message": "No check found"}')This isn’t introduced by this PR but is worth fixing before relying on
--format-jsonin automation..github/workflows/ci.yml (1)
45-305: UV-based CI wiring is coherent; standardize checkout versionsThe dependency-groups (
lint,tests,dev) and extras (all,ctl) inpyproject.tomlalign with the uv commands in the workflow:
python-lintusesuv sync --group lint(ruff, mypy, yamllint)documentation,validate-generated-documentation,unit-tests, andintegration-tests-latest-infrahubuseuv sync --all-groups --all-extras(broader scope)Minor inconsistency:
python-lintusesactions/checkout@v5(line 79) while all other jobs use@v6. Standardize onv6for consistency.
🧹 Nitpick comments (16)
infrahub_sdk/transfer/importer/json.py (1)
65-65: Consider usingstrict=Truefor data integrity.Since both columns come from the same PyArrow table, they should have identical lengths. Using
strict=Truewould catch data corruption issues early rather than silently truncating to the shorter sequence.Apply this diff:
- for graphql_data, kind in zip(table.column("graphql_json"), table.column("kind"), strict=False): + for graphql_data, kind in zip(table.column("graphql_json"), table.column("kind"), strict=True):infrahub_sdk/spec/range_expansion.py (1)
59-59: Improve type hint specificity for mypy strict mode.The
re.Patterntype parameter should be specified asre.Pattern[str]for strict type checking compatibility.-def _extract_constants(pattern: str, re_compiled: re.Pattern) -> tuple[list[int], list[list[str]]]: +def _extract_constants(pattern: str, re_compiled: re.Pattern[str]) -> tuple[list[int], list[list[str]]]:tests/fixtures/integration/test_infrahubctl/tags_transform/tags_transform.py (1)
8-8: Good addition of return type annotation.The
dict[str, str]return type correctly reflects the function's output. For complete type coverage, consider also annotating thedataparameter.Apply this diff to add the parameter annotation:
- async def transform(self, data) -> dict[str, str]: + async def transform(self, data: dict) -> dict[str, str]:Note: The exact type of
datadepends on the base class contract. If a more specific type is available fromInfrahubTransform, use that instead of the genericdict.infrahub_sdk/ctl/task.py (1)
70-83: Limit/offset union hints look good; consider aligningstateannotation with its defaultThe switch to
int | Noneforlimitandoffsetis correct and matches Typer’sNonedefault and theclient.task.filtersignature, so no behavioral change here.One small consistency tweak you might want to do while you’re here:
stateis annotated aslist[str]but has aNonedefault and is passed into_parse_states(states: list[str] | None). With strict mypy this can be noisy; aligning the annotation would be cleaner:- state: list[str] = typer.Option( + state: list[str] | None = typer.Option( None, "--state", "-s", help="Filter by task state. Can be provided multiple times." ),infrahub_sdk/config.py (1)
161-204: Config typing tweaks look good; config guidelines appear satisfied
- Narrowing the type ignore on
loggerto# type: ignore[return-value]is a nice improvement: it keeps the documented intent (“we letself.logbe treated asInfrahubLoggersdespite structlog quirks”) while not masking other potential issues on that property.- Changing
for field in Config.model_fields:to iterate the mapping directly is equivalent to iterating.keys()and keeps theclone()behavior intact.Also, for this module specifically:
ConfigBase.model_configusesenv_prefix="INFRAHUB_", andvalidate_proxy_config()enforces thatproxyandproxy_mounts(backed byINFRAHUB_PROXY_MOUNTS_HTTP/HTTPS) are mutually exclusive,which aligns with the provided configuration guidelines.
If you ever want to guarantee that
loggeris neverNoneat runtime, you might consider either:
- making
lognon-optional and defaulting it to a concrete logger, or- having
loggerraise ifself.logis unset, rather than returningNone.For now, the current behavior is consistent with the existing comments and use case.
infrahub_sdk/template/__init__.py (1)
4-34: Callable import switch is fine; consider parameterizing filter callablesSwitching
Callableto come fromcollections.abcis consistent with modern typing style and doesn’t affect runtime behavior.If you’re running mypy in strict mode, you may want to be explicit about the callable shape for filters:
-from collections.abc import Callable +from collections.abc import Callable @@ - filters: dict[str, Callable] | None = None, + filters: dict[str, Callable[..., Any]] | None = None,This keeps the current flexibility (any callable is allowed) while avoiding potential “missing type parameters for generic type
Callable” warnings.If you adopt this, please re-run mypy to ensure there are no remaining unsubscripted-
Callableinstances that strict mode complains about.infrahub_sdk/spec/object.py (1)
233-233: Avoid creating an unnecessary list inany().The
any([...])call creates a list unnecessarily. Use a generator expression or direct boolean operators instead.Apply this diff:
- if not any([element in data, element in context]): + if element not in data and element not in context:Alternatively, if you prefer the
any()approach, use a generator:- if not any([element in data, element in context]): + if not any((element in data, element in context)):infrahub_sdk/query_groups.py (1)
171-171: Consider using a set forunused_member_idsfor better performance.The code converts a set difference to a list, but
unused_member_idsis only used for membership checks (if member.id in self.unused_member_idson lines 111 and 205). Sets are more efficient for membership tests.Consider updating the type hint on line 22 and removing the
list()conversion:- self.unused_member_ids: list[str] | None = None + self.unused_member_ids: set[str] | None = NoneAnd on lines 171 and 265:
- self.unused_member_ids = list(set(existing_group.members.peer_ids) - set(members)) + self.unused_member_ids = set(existing_group.members.peer_ids) - set(members)Also applies to: 265-265
CLAUDE.md (1)
167-177: Update pyproject.toml description to remove Poetry referenceThe code quality and CI bullets correctly reflect Ruff 0.14.5 and Python 3.10–3.13, but the
pyproject.tomlentry still refers to “Poetry dependencies,” which is now misleading with the uv/Hatch setup.Consider neutral wording like:
-- **pyproject.toml**: Poetry dependencies, tool configurations (ruff, mypy, pytest) +- **pyproject.toml**: Project dependencies and tool configurations (ruff, mypy, pytest)Also applies to: 183-187
infrahub_sdk/ctl/cli_commands.py (1)
9-12: PEP 604 type hints and Callable import are consistent with CLI utilitiesSwitching
branch/variables/concurrenttostr | None/list[str] | Noneand importingCallablefromcollections.abcaligns these commands withparse_cli_varsand the project-wide typing style; no functional changes and this should play well with strict mypy.If you want to finish the cleanup while you’re here, you could also make
run’sbranchannotationstr | Noneto match the other commands and its defaultNone.Also applies to: 77-102, 107-126, 131-146, 250-262, 300-312
tests/unit/sdk/test_repository.py (1)
2-3: temp_dir fixture typing clarified; optionally tighten Generator typeAnnotating
temp_diras returning aGenerator[str]makes its intent clearer and is sufficient for most tooling.If you want to be maximally explicit for strict type checkers, you could refine it to:
-from collections.abc import Generator +from collections.abc import Generator ... -@pytest.fixture -def temp_dir() -> Generator[str]: +@pytest.fixture +def temp_dir() -> Generator[str, None, None]:Also applies to: 13-17
infrahub_sdk/diff.py (1)
144-204: LGTM - Query builder for GetDiffTree.The
get_diff_tree_query()function properly constructs the GraphQL query using theQueryclass. The node structure mirrors the existing raw string inget_diff_summary_query()but is now programmatically built, enabling better maintainability and type-safe variable handling.Consider consolidating
get_diff_summary_query()(lines 52-88) to also use theQueryclass pattern for consistency, since both queries share the samenode_structure. This would reduce duplication and improve maintainability.# Example: Extract shared node structure _NODE_STRUCTURE = { "uuid": None, "kind": None, # ... rest of structure } def get_diff_summary_query() -> Query: return Query( name="GetDiffSummary", query={"DiffTree": {"@filters": {...}, "nodes": _NODE_STRUCTURE}}, variables={"branch_name": str, "name": str | None, ...}, )infrahub_sdk/ctl/graphql.py (1)
77-182: UTF‑8 write for schema looks good; consider aligning result‑type writes
- Explicit
encoding="utf-8"inexport_schemais a solid improvement, and thequery: Path | Nonedefaulting toPath.cwd()is clean and matches the help text.- Iterating
for file_name in package_generator._result_types_filesis equivalent to.keys()and fine.You might also want to make
generate_result_typesconsistent by writing the generated modules with an explicit encoding as well:- file_path.write_text(code) + file_path.write_text(code, encoding="utf-8")tests/conftest.py (1)
3-42: Fixture Generator annotations are fine; you can tighten generics if desiredThe new
Generatorannotations improve typing without changing behavior. If you want fully precise types (and to help static checkers), you could spell out all three generic parameters:-from collections.abc import Generator +from collections.abc import Generator -@pytest.fixture(scope="session") -def event_loop() -> Generator[asyncio.AbstractEventLoop]: +@pytest.fixture(scope="session") +def event_loop() -> Generator[asyncio.AbstractEventLoop, None, None]: @@ -@pytest.fixture(scope="session", autouse=True) -def clean_env_vars() -> Generator: +@pytest.fixture(scope="session", autouse=True) +def clean_env_vars() -> Generator[None, None, None]:This is optional and not required for correctness.
tests/unit/sdk/test_node.py (1)
2416-2625: Deep-nesting_process_relationshipstest exercises both async and sync paths wellThe new
test_process_relationships_recursive_deep_nestingcorrectly:
- Sets up a 3-level graph (Device → Interfaces → IP Addresses) and a matching schema cache for both clients.
- Verifies that
recursive=Falseonly yields the two interfaces, whilerecursive=Trueyields the interfaces plus all three IP address nodes, for bothInfrahubNodeandInfrahubNodeSync.If you ever find this pattern useful elsewhere, you could factor the nested data/schema construction into a fixture to reduce duplication, but as-is the test is clear and targeted.
infrahub_sdk/ctl/branch.py (1)
163-163: Consider handling the case where no default branch exists.Using
next()is more Pythonic than list indexing, but if no default branch is found, it will raiseStopIterationwhich may be confusing. Consider providing a sentinel or explicit error:- default_branch = next(branch for branch in branches.values() if branch.is_default) + default_branch = next((branch for branch in branches.values() if branch.is_default), None) + if default_branch is None: + console.print("[red]No default branch found!") + returnAlternatively, if a default branch is always guaranteed to exist, this is acceptable as-is.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (2)
poetry.lockis excluded by!**/*.lockuv.lockis excluded by!**/*.lock
📒 Files selected for processing (76)
.github/file-filters.yml(2 hunks).github/workflows/ci.yml(8 hunks).github/workflows/define-versions.yml(1 hunks).github/workflows/publish-pypi.yml(1 hunks).github/workflows/release.yml(2 hunks).gitignore(1 hunks)CHANGELOG.md(1 hunks)CLAUDE.md(4 hunks)README.md(1 hunks)docs/docs/infrahubctl/infrahubctl-branch.mdx(2 hunks)docs/docs/python-sdk/guides/client.mdx(1 hunks)infrahub_sdk/async_typer.py(1 hunks)infrahub_sdk/batch.py(1 hunks)infrahub_sdk/client.py(11 hunks)infrahub_sdk/config.py(2 hunks)infrahub_sdk/ctl/branch.py(4 hunks)infrahub_sdk/ctl/check.py(2 hunks)infrahub_sdk/ctl/cli.py(1 hunks)infrahub_sdk/ctl/cli_commands.py(6 hunks)infrahub_sdk/ctl/generator.py(2 hunks)infrahub_sdk/ctl/graphql.py(2 hunks)infrahub_sdk/ctl/importer.py(2 hunks)infrahub_sdk/ctl/repository.py(3 hunks)infrahub_sdk/ctl/task.py(1 hunks)infrahub_sdk/ctl/utils.py(3 hunks)infrahub_sdk/ctl/validate.py(1 hunks)infrahub_sdk/diff.py(3 hunks)infrahub_sdk/graphql/constants.py(1 hunks)infrahub_sdk/graphql/renderers.py(2 hunks)infrahub_sdk/node/attribute.py(4 hunks)infrahub_sdk/node/constants.py(1 hunks)infrahub_sdk/node/node.py(8 hunks)infrahub_sdk/node/related_node.py(1 hunks)infrahub_sdk/node/relationship.py(1 hunks)infrahub_sdk/object_store.py(4 hunks)infrahub_sdk/operation.py(1 hunks)infrahub_sdk/protocols_base.py(0 hunks)infrahub_sdk/protocols_generator/generator.py(1 hunks)infrahub_sdk/pytest_plugin/items/jinja2_transform.py(1 hunks)infrahub_sdk/pytest_plugin/models.py(1 hunks)infrahub_sdk/pytest_plugin/plugin.py(1 hunks)infrahub_sdk/query_groups.py(2 hunks)infrahub_sdk/schema/__init__.py(5 hunks)infrahub_sdk/schema/main.py(1 hunks)infrahub_sdk/schema/repository.py(2 hunks)infrahub_sdk/spec/object.py(2 hunks)infrahub_sdk/spec/range_expansion.py(1 hunks)infrahub_sdk/template/__init__.py(1 hunks)infrahub_sdk/transfer/importer/json.py(3 hunks)infrahub_sdk/types.py(2 hunks)infrahub_sdk/utils.py(2 hunks)pyproject.toml(4 hunks)tasks.py(1 hunks)tests/__init__.py(1 hunks)tests/conftest.py(3 hunks)tests/fixtures/integration/test_infrahubctl/tags_transform/tags_transform.py(1 hunks)tests/helpers/fixtures.py(1 hunks)tests/integration/conftest.py(1 hunks)tests/integration/test_infrahub_client.py(4 hunks)tests/unit/__init__.py(1 hunks)tests/unit/ctl/conftest.py(2 hunks)tests/unit/ctl/test_branch_report.py(1 hunks)tests/unit/ctl/test_render_app.py(1 hunks)tests/unit/ctl/test_repository_app.py(1 hunks)tests/unit/ctl/test_transform_app.py(2 hunks)tests/unit/sdk/checks/test_checks.py(3 hunks)tests/unit/sdk/conftest.py(48 hunks)tests/unit/sdk/graphql/conftest.py(6 hunks)tests/unit/sdk/graphql/test_plugin.py(2 hunks)tests/unit/sdk/test_batch.py(1 hunks)tests/unit/sdk/test_diff_summary.py(2 hunks)tests/unit/sdk/test_node.py(36 hunks)tests/unit/sdk/test_repository.py(2 hunks)tests/unit/sdk/test_schema.py(1 hunks)tests/unit/sdk/test_template.py(1 hunks)tests/unit/sdk/test_yaml.py(1 hunks)
💤 Files with no reviewable changes (1)
- infrahub_sdk/protocols_base.py
🧰 Additional context used
📓 Path-based instructions (11)
**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.py: All async operations must have corresponding sync implementations following the dual implementation pattern
Use mypy with strict configuration for type checking in Python files
Files:
tests/helpers/fixtures.pytests/unit/ctl/test_transform_app.pytests/integration/conftest.pyinfrahub_sdk/node/relationship.pyinfrahub_sdk/pytest_plugin/models.pyinfrahub_sdk/ctl/cli.pyinfrahub_sdk/query_groups.pytests/unit/ctl/test_render_app.pyinfrahub_sdk/object_store.pyinfrahub_sdk/utils.pytasks.pyinfrahub_sdk/ctl/check.pyinfrahub_sdk/schema/repository.pytests/unit/sdk/test_schema.pyinfrahub_sdk/node/constants.pytests/unit/ctl/test_branch_report.pytests/unit/__init__.pytests/unit/ctl/test_repository_app.pyinfrahub_sdk/batch.pytests/unit/sdk/checks/test_checks.pytests/__init__.pyinfrahub_sdk/ctl/utils.pytests/unit/sdk/test_diff_summary.pytests/unit/sdk/test_yaml.pytests/unit/sdk/test_template.pyinfrahub_sdk/ctl/generator.pyinfrahub_sdk/node/attribute.pyinfrahub_sdk/ctl/importer.pyinfrahub_sdk/template/__init__.pyinfrahub_sdk/spec/range_expansion.pyinfrahub_sdk/diff.pytests/unit/sdk/test_node.pytests/unit/sdk/test_batch.pyinfrahub_sdk/node/node.pyinfrahub_sdk/ctl/graphql.pyinfrahub_sdk/async_typer.pyinfrahub_sdk/operation.pytests/integration/test_infrahub_client.pyinfrahub_sdk/ctl/cli_commands.pytests/conftest.pyinfrahub_sdk/ctl/branch.pyinfrahub_sdk/protocols_generator/generator.pyinfrahub_sdk/client.pytests/unit/sdk/test_repository.pyinfrahub_sdk/ctl/task.pyinfrahub_sdk/graphql/constants.pytests/unit/ctl/conftest.pytests/fixtures/integration/test_infrahubctl/tags_transform/tags_transform.pyinfrahub_sdk/types.pyinfrahub_sdk/graphql/renderers.pyinfrahub_sdk/schema/main.pyinfrahub_sdk/node/related_node.pyinfrahub_sdk/pytest_plugin/items/jinja2_transform.pyinfrahub_sdk/config.pyinfrahub_sdk/schema/__init__.pyinfrahub_sdk/spec/object.pytests/unit/sdk/graphql/test_plugin.pyinfrahub_sdk/ctl/validate.pyinfrahub_sdk/pytest_plugin/plugin.pyinfrahub_sdk/transfer/importer/json.pytests/unit/sdk/conftest.pyinfrahub_sdk/ctl/repository.pytests/unit/sdk/graphql/conftest.py
tests/unit/**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
Place unit tests in
tests/unit/directory for testing individual components in isolation
Files:
tests/unit/ctl/test_transform_app.pytests/unit/ctl/test_render_app.pytests/unit/sdk/test_schema.pytests/unit/ctl/test_branch_report.pytests/unit/__init__.pytests/unit/ctl/test_repository_app.pytests/unit/sdk/checks/test_checks.pytests/unit/sdk/test_diff_summary.pytests/unit/sdk/test_yaml.pytests/unit/sdk/test_template.pytests/unit/sdk/test_node.pytests/unit/sdk/test_batch.pytests/unit/sdk/test_repository.pytests/unit/ctl/conftest.pytests/unit/sdk/graphql/test_plugin.pytests/unit/sdk/conftest.pytests/unit/sdk/graphql/conftest.py
**/ctl/**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
Use Typer framework for building CLI commands in the infrahubctl CLI
Files:
tests/unit/ctl/test_transform_app.pyinfrahub_sdk/ctl/cli.pytests/unit/ctl/test_render_app.pyinfrahub_sdk/ctl/check.pytests/unit/ctl/test_branch_report.pytests/unit/ctl/test_repository_app.pyinfrahub_sdk/ctl/utils.pyinfrahub_sdk/ctl/generator.pyinfrahub_sdk/ctl/importer.pyinfrahub_sdk/ctl/graphql.pyinfrahub_sdk/ctl/cli_commands.pyinfrahub_sdk/ctl/branch.pyinfrahub_sdk/ctl/task.pytests/unit/ctl/conftest.pyinfrahub_sdk/ctl/validate.pyinfrahub_sdk/ctl/repository.py
**/*.md
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.md: Use markdownlint for documentation consistency
Use Vale for documentation style checking
Follow markdown style as defined in.markdownlint.yamlconfiguration
Files:
README.mdCHANGELOG.mdCLAUDE.md
docs/**/*.{md,mdx}
📄 CodeRabbit inference engine (CLAUDE.md)
docs/**/*.{md,mdx}: Follow Diataxis framework for documentation structure: Tutorials (learning-oriented), How-to guides (task-oriented), Explanation (understanding-oriented), and Reference (information-oriented)
Use professional but approachable tone with plain language and technical precision in documentation
Use concise and direct documentation with short, active sentences and minimal fluff
Maintain informative documentation focused on explaining how and why rather than marketing
Follow consistent documentation structure patterns across documents
Define new terms when first introduced in documentation
Use domain-relevant terminology from the user perspective (playbooks, branches, schemas, commits) in documentation
Maintain consistency with Infrahub's data model and UI naming conventions in documentation
Use proper language tags for all code blocks in documentation
Include both async and sync code examples using Tabs component where applicable
Provide realistic code examples that reflect real-world complexity in documentation
Use callouts for warnings, tips, and important notes in documentation
Files:
docs/docs/infrahubctl/infrahubctl-branch.mdxdocs/docs/python-sdk/guides/client.mdx
tests/integration/**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
Place integration tests in
tests/integration/directory for testing against real Infrahub instances
Files:
tests/integration/conftest.pytests/integration/test_infrahub_client.py
**/node/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
**/node/*.py: Implement lazy loading for node attributes and relationships to load on demand
Support batch operations for bulk create/update/delete operations on nodes
Include built-in data validation with GraphQL query generation for nodes
Files:
infrahub_sdk/node/relationship.pyinfrahub_sdk/node/constants.pyinfrahub_sdk/node/attribute.pyinfrahub_sdk/node/node.pyinfrahub_sdk/node/related_node.py
**/node/relationship.py
📄 CodeRabbit inference engine (CLAUDE.md)
Implement automatic handling of node relationships with add/remove/replace operations
Files:
infrahub_sdk/node/relationship.py
**/check*.py
📄 CodeRabbit inference engine (CLAUDE.md)
In Checks implementation, use the
validate()method, NOTcheck()when implementing InfrahubCheck
Files:
infrahub_sdk/ctl/check.py
**/client.py
📄 CodeRabbit inference engine (CLAUDE.md)
**/client.py: UseInfrahubClient(async) andInfrahubClientSync(sync) with identical interfaces following the Dual Client Pattern
Use HTTPX-based transport with proxy support (single proxy or HTTP/HTTPS mounts) and API token/JWT authentication with automatic refresh
Files:
infrahub_sdk/client.py
**/config.py
📄 CodeRabbit inference engine (CLAUDE.md)
**/config.py: Use Pydantic-basedConfigclass with environment variable support for configuration management
Use environment variables prefixed withINFRAHUB_for configuration
Ensure mutual exclusivity validation between proxy configuration methods (INFRAHUB_PROXYvsINFRAHUB_PROXY_MOUNTS_HTTP/INFRAHUB_PROXY_MOUNTS_HTTPS)
Files:
infrahub_sdk/config.py
🧠 Learnings (20)
📚 Learning: 2025-11-25T07:18:58.155Z
Learnt from: CR
Repo: opsmill/infrahub-sdk-python PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T07:18:58.155Z
Learning: Use `poetry install --with dev --all-extras` to install dependencies in development environment
Applied to files:
README.mdCLAUDE.md
📚 Learning: 2025-11-25T13:29:23.062Z
Learnt from: wvandeun
Repo: opsmill/infrahub-sdk-python PR: 637
File: infrahub_sdk/ctl/branch.py:290-290
Timestamp: 2025-11-25T13:29:23.062Z
Learning: In infrahub_sdk/ctl/branch.py, the report command uses pc.created_by.updated_at to display "Created at" for proposed changes as a workaround because the SDK doesn't have easy access to the creation time of the proposed change. This will be replaced with proper object-level metadata implementation in version 1.7 of Infrahub.
Applied to files:
docs/docs/infrahubctl/infrahubctl-branch.mdxCHANGELOG.mdtests/unit/ctl/test_branch_report.pyinfrahub_sdk/ctl/branch.pyinfrahub_sdk/node/related_node.py
📚 Learning: 2025-11-25T07:18:58.155Z
Learnt from: CR
Repo: opsmill/infrahub-sdk-python PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T07:18:58.155Z
Learning: Applies to **/node/relationship.py : Implement automatic handling of node relationships with add/remove/replace operations
Applied to files:
infrahub_sdk/node/relationship.pytests/unit/sdk/test_node.pyinfrahub_sdk/node/node.pyinfrahub_sdk/operation.pyinfrahub_sdk/node/related_node.pyinfrahub_sdk/transfer/importer/json.py
📚 Learning: 2025-11-25T13:23:15.190Z
Learnt from: wvandeun
Repo: opsmill/infrahub-sdk-python PR: 637
File: infrahub_sdk/operation.py:74-76
Timestamp: 2025-11-25T13:23:15.190Z
Learning: In infrahub_sdk/operation.py, the recursive=True parameter in _process_relationships is a temporary workaround to access Proposed Changes data. This will be replaced with proper object-level metadata implementation in version 1.7.
Applied to files:
infrahub_sdk/node/relationship.pytests/unit/sdk/test_node.pyinfrahub_sdk/node/node.pyinfrahub_sdk/operation.py
📚 Learning: 2025-11-25T07:18:58.155Z
Learnt from: CR
Repo: opsmill/infrahub-sdk-python PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T07:18:58.155Z
Learning: Applies to **/ctl/**/*.py : Use Typer framework for building CLI commands in the infrahubctl CLI
Applied to files:
infrahub_sdk/ctl/cli.pytasks.pyinfrahub_sdk/ctl/cli_commands.pyinfrahub_sdk/ctl/branch.py
📚 Learning: 2025-11-25T07:18:58.155Z
Learnt from: CR
Repo: opsmill/infrahub-sdk-python PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T07:18:58.155Z
Learning: Validate documentation accuracy against the latest Infrahub version
Applied to files:
CHANGELOG.md
📚 Learning: 2025-11-25T07:18:58.155Z
Learnt from: CR
Repo: opsmill/infrahub-sdk-python PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T07:18:58.155Z
Learning: Applies to **/client.py : Use `InfrahubClient` (async) and `InfrahubClientSync` (sync) with identical interfaces following the Dual Client Pattern
Applied to files:
docs/docs/python-sdk/guides/client.mdxinfrahub_sdk/schema/repository.pytests/unit/ctl/test_repository_app.pytests/unit/sdk/checks/test_checks.pytests/unit/sdk/test_diff_summary.pyinfrahub_sdk/ctl/branch.pyinfrahub_sdk/client.pyinfrahub_sdk/schema/__init__.pytests/unit/sdk/conftest.py
📚 Learning: 2025-11-25T07:18:58.155Z
Learnt from: CR
Repo: opsmill/infrahub-sdk-python PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T07:18:58.155Z
Learning: Applies to **/config.py : Use environment variables prefixed with `INFRAHUB_` for configuration
Applied to files:
docs/docs/python-sdk/guides/client.mdx
📚 Learning: 2025-11-25T07:18:58.155Z
Learnt from: CR
Repo: opsmill/infrahub-sdk-python PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T07:18:58.155Z
Learning: Generate documentation with `poetry run invoke docs`
Applied to files:
tasks.py.github/workflows/ci.ymlCLAUDE.md
📚 Learning: 2025-11-25T07:18:58.155Z
Learnt from: CR
Repo: opsmill/infrahub-sdk-python PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T07:18:58.155Z
Learning: Run linting with `poetry run invoke lint` (ruff + mypy + yamllint + markdownlint) to ensure code quality
Applied to files:
.github/workflows/ci.ymlCLAUDE.md
📚 Learning: 2025-11-25T07:18:58.155Z
Learnt from: CR
Repo: opsmill/infrahub-sdk-python PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T07:18:58.155Z
Learning: Use Ruff (0.11.0) for comprehensive linting and formatting
Applied to files:
.github/workflows/ci.ymlpyproject.tomlCLAUDE.md
📚 Learning: 2025-11-25T07:18:58.155Z
Learnt from: CR
Repo: opsmill/infrahub-sdk-python PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T07:18:58.155Z
Learning: Validate documentation with `poetry run invoke docs-validate`
Applied to files:
.github/workflows/ci.ymlCLAUDE.md
📚 Learning: 2025-11-25T07:18:58.155Z
Learnt from: CR
Repo: opsmill/infrahub-sdk-python PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T07:18:58.155Z
Learning: Run `poetry run invoke format` to format code before committing
Applied to files:
.github/workflows/ci.ymlCLAUDE.md
📚 Learning: 2025-11-25T07:18:58.155Z
Learnt from: CR
Repo: opsmill/infrahub-sdk-python PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T07:18:58.155Z
Learning: Run unit tests with `poetry run pytest --cov infrahub_sdk tests/unit/` to ensure code coverage
Applied to files:
.github/workflows/ci.ymlpyproject.tomltests/unit/sdk/checks/test_checks.pyCLAUDE.md
📚 Learning: 2025-11-25T07:18:58.155Z
Learnt from: CR
Repo: opsmill/infrahub-sdk-python PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T07:18:58.155Z
Learning: Maintain code coverage through codecov integration in testing
Applied to files:
.github/workflows/ci.yml
📚 Learning: 2025-11-25T07:18:58.155Z
Learnt from: CR
Repo: opsmill/infrahub-sdk-python PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T07:18:58.155Z
Learning: Applies to tests/integration/**/*.py : Place integration tests in `tests/integration/` directory for testing against real Infrahub instances
Applied to files:
tests/unit/sdk/checks/test_checks.pyCLAUDE.md
📚 Learning: 2025-11-25T07:18:58.155Z
Learnt from: CR
Repo: opsmill/infrahub-sdk-python PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T07:18:58.155Z
Learning: Applies to **/node/*.py : Include built-in data validation with GraphQL query generation for nodes
Applied to files:
infrahub_sdk/diff.pyinfrahub_sdk/ctl/graphql.pyinfrahub_sdk/ctl/validate.py
📚 Learning: 2025-11-25T07:18:58.155Z
Learnt from: CR
Repo: opsmill/infrahub-sdk-python PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T07:18:58.155Z
Learning: Run integration tests with `poetry run pytest tests/integration/`
Applied to files:
CLAUDE.md
📚 Learning: 2025-11-25T07:18:58.155Z
Learnt from: CR
Repo: opsmill/infrahub-sdk-python PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T07:18:58.155Z
Learning: Use Docusaurus-based documentation system with auto-generation for CLI docs and config reference
Applied to files:
CLAUDE.md
📚 Learning: 2025-11-25T07:18:58.155Z
Learnt from: CR
Repo: opsmill/infrahub-sdk-python PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T07:18:58.155Z
Learning: Applies to **/*.md : Use markdownlint for documentation consistency
Applied to files:
CLAUDE.md
🧬 Code graph analysis (16)
infrahub_sdk/query_groups.py (1)
infrahub_sdk/node/relationship.py (1)
peer_ids(44-45)
tasks.py (1)
infrahub_sdk/ctl/cli_commands.py (1)
run(131-181)
tests/unit/ctl/test_repository_app.py (1)
infrahub_sdk/client.py (1)
InfrahubClient(318-1744)
tests/unit/sdk/checks/test_checks.py (1)
infrahub_sdk/ctl/cli_commands.py (1)
check(79-102)
tests/unit/sdk/test_diff_summary.py (3)
infrahub_sdk/client.py (3)
InfrahubClient(318-1744)get_diff_tree(1285-1339)get_diff_tree(2579-2633)infrahub_sdk/diff.py (1)
get_diff_tree_query(144-204)tests/unit/sdk/conftest.py (2)
clients(42-46)BothClients(25-28)
tests/unit/sdk/test_yaml.py (1)
infrahub_sdk/yaml.py (1)
load_content(43-58)
infrahub_sdk/diff.py (1)
infrahub_sdk/graphql/query.py (1)
Query(31-43)
tests/unit/sdk/test_node.py (3)
tests/unit/sdk/conftest.py (3)
BothClients(25-28)client(32-33)clients(42-46)infrahub_sdk/node/node.py (5)
InfrahubNode(458-1108)from_graphql(486-500)from_graphql(1139-1153)_process_relationships(892-945)_process_relationships(1539-1592)infrahub_sdk/node/related_node.py (1)
id(83-86)
infrahub_sdk/operation.py (1)
infrahub_sdk/node/node.py (4)
from_graphql(486-500)from_graphql(1139-1153)_process_relationships(892-945)_process_relationships(1539-1592)
tests/integration/test_infrahub_client.py (1)
tests/unit/sdk/conftest.py (1)
client(32-33)
infrahub_sdk/ctl/cli_commands.py (3)
infrahub_sdk/testing/repository.py (1)
path(57-58)infrahub_sdk/types.py (1)
debug(49-50)infrahub_sdk/analyzer.py (1)
variables(72-99)
infrahub_sdk/ctl/branch.py (4)
infrahub_sdk/branch.py (3)
BranchData(25-35)get(205-215)get(245-255)infrahub_sdk/diff.py (1)
DiffTreeData(39-49)infrahub_sdk/protocols.py (1)
CoreProposedChange(491-505)infrahub_sdk/utils.py (1)
decode_json(94-98)
infrahub_sdk/client.py (1)
infrahub_sdk/diff.py (5)
DiffTreeData(39-49)NodeDiff(11-17)diff_tree_node_to_node_diff(91-141)get_diff_summary_query(52-88)get_diff_tree_query(144-204)
tests/fixtures/integration/test_infrahubctl/tags_transform/tags_transform.py (2)
infrahub_sdk/ctl/cli_commands.py (1)
transform(302-360)infrahub_sdk/yaml.py (1)
data(147-150)
infrahub_sdk/ctl/validate.py (1)
infrahub_sdk/analyzer.py (1)
variables(72-99)
infrahub_sdk/transfer/importer/json.py (3)
infrahub_sdk/node/related_node.py (1)
kind(123-126)infrahub_sdk/schema/main.py (1)
kind(279-280)infrahub_sdk/yaml.py (1)
kind(157-158)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: unit-tests (3.12)
- GitHub Check: unit-tests (3.13)
- GitHub Check: unit-tests (3.10)
- GitHub Check: unit-tests (3.11)
|
|
||
| ## Prerequisites | ||
|
|
||
| - Python 3.9 or higher |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Update Python version requirement to reflect PR changes.
Line 19 states "Python 3.9 or higher," but according to the PR objectives, Python 3.9 support is being removed and the SDK now requires Python 3.10+. This prerequisite needs to be updated to match the modernization goals of this release.
- Python 3.9 or higher
+ Python 3.10 or higher📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| - Python 3.9 or higher | |
| - Python 3.10 or higher |
🤖 Prompt for AI Agents
In docs/docs/python-sdk/guides/client.mdx around line 19, the prerequisite
currently reads "Python 3.9 or higher" but the PR removes 3.9 support; update
this line to require "Python 3.10 or higher" (or equivalent phrasing used across
the docs) and run a quick grep to ensure all other occurrences of "3.9" are
updated to "3.10" for consistency.
| def format_timestamp(timestamp: str) -> str: | ||
| """Format ISO timestamp to 'YYYY-MM-DD HH:MM:SS'. | ||
| Args: | ||
| timestamp (str): ISO fromatted timestamp | ||
| Returns: | ||
| (str): the datetime as string formatted as 'YYYY-MM-DD HH:MM:SS' | ||
| Raises: | ||
| Any execptions returned from formatting the timestamp are propogated to the caller | ||
| """ | ||
| dt = datetime.fromisoformat(timestamp.replace("Z", "+00:00")) | ||
| return dt.strftime("%Y-%m-%d %H:%M:%S") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor typos in docstring.
The docstring contains a few typos:
- Line 33: "fromatted" → "formatted"
- Line 39: "execptions" → "exceptions", "propogated" → "propagated"
def format_timestamp(timestamp: str) -> str:
- """Format ISO timestamp to 'YYYY-MM-DD HH:MM:SS'.
+ """Format ISO timestamp to 'YYYY-MM-DD HH:MM:SS'.
Args:
- timestamp (str): ISO fromatted timestamp
+ timestamp (str): ISO formatted timestamp
Returns:
(str): the datetime as string formatted as 'YYYY-MM-DD HH:MM:SS'
Raises:
- Any execptions returned from formatting the timestamp are propogated to the caller
+ Any exceptions returned from formatting the timestamp are propagated to the caller
"""🤖 Prompt for AI Agents
In infrahub_sdk/ctl/branch.py around lines 30 to 42, the function docstring has
a few typos: change "fromatted" to "formatted" in the Args description, change
"execptions" to "exceptions" and "propogated" to "propagated" in the Raises
section; update the wording if needed to keep grammar consistent (e.g., "ISO
formatted timestamp" and "Any exceptions returned from formatting the timestamp
are propagated to the caller").
| async def test_check_git_files_changed_empty_response(httpx_mock: HTTPXMock) -> None: | ||
| response = {} | ||
|
|
||
| httpx_mock.add_response( | ||
| method="GET", | ||
| url="http://mock/api/diff/files?branch=test-branch", | ||
| json=response, | ||
| ) | ||
|
|
||
| """Test check_git_files_changed returns False when branch not in response.""" | ||
| client = InfrahubClient(config=Config(address="http://mock")) | ||
| result = await check_git_files_changed(client, branch="test-branch") | ||
| assert result is False |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Move docstring to the beginning of the function.
The docstring on line 87 is incorrectly placed after code execution has started. Docstrings should be the first statement in a function.
Apply this diff to fix the docstring placement:
async def test_check_git_files_changed_empty_response(httpx_mock: HTTPXMock) -> None:
+ """Test check_git_files_changed returns False when branch not in response."""
response = {}
httpx_mock.add_response(
method="GET",
url="http://mock/api/diff/files?branch=test-branch",
json=response,
)
- """Test check_git_files_changed returns False when branch not in response."""
client = InfrahubClient(config=Config(address="http://mock"))📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| async def test_check_git_files_changed_empty_response(httpx_mock: HTTPXMock) -> None: | |
| response = {} | |
| httpx_mock.add_response( | |
| method="GET", | |
| url="http://mock/api/diff/files?branch=test-branch", | |
| json=response, | |
| ) | |
| """Test check_git_files_changed returns False when branch not in response.""" | |
| client = InfrahubClient(config=Config(address="http://mock")) | |
| result = await check_git_files_changed(client, branch="test-branch") | |
| assert result is False | |
| async def test_check_git_files_changed_empty_response(httpx_mock: HTTPXMock) -> None: | |
| """Test check_git_files_changed returns False when branch not in response.""" | |
| response = {} | |
| httpx_mock.add_response( | |
| method="GET", | |
| url="http://mock/api/diff/files?branch=test-branch", | |
| json=response, | |
| ) | |
| client = InfrahubClient(config=Config(address="http://mock")) | |
| result = await check_git_files_changed(client, branch="test-branch") | |
| assert result is False |
🤖 Prompt for AI Agents
tests/unit/ctl/test_branch_report.py around lines 78 to 90: the function has a
docstring placed after test setup and execution; move the docstring to be the
first statement inside the async test function (i.e., immediately after the def
line) so it documents the test properly and does not execute after code,
ensuring the test setup (httpx_mock, response, client creation, call and
assertion) follows the docstring.
Summary by CodeRabbit
New Features
infrahubctl branch reportcommand for detailed branch cleanup status reportingget_diff_tree()methods to SDK clients for retrieving complete diff trees with metadataChanged
is_visibleproperty from node attributesDocumentation
✏️ Tip: You can customize this high-level summary in your review settings.