Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 6 additions & 8 deletions infrahub_sdk/batch.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,16 +71,14 @@ def add(self, *args: Any, task: Callable, node: Any | None = None, **kwargs: Any
self._tasks.append(BatchTask(task=task, node=node, args=args, kwargs=kwargs))

async def execute(self) -> AsyncGenerator:
tasks = []

for batch_task in self._tasks:
tasks.append(
asyncio.create_task(
execute_batch_task_in_pool(
task=batch_task, semaphore=self.semaphore, return_exceptions=self.return_exceptions
)
tasks = [
asyncio.create_task(
execute_batch_task_in_pool(
task=batch_task, semaphore=self.semaphore, return_exceptions=self.return_exceptions
)
)
for batch_task in self._tasks
]

for completed_task in asyncio.as_completed(tasks):
node, result = await completed_task
Expand Down
10 changes: 4 additions & 6 deletions infrahub_sdk/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -1200,12 +1200,11 @@ async def query_gql_query(
url_params["update_group"] = str(update_group).lower()

if url_params:
url_params_str = []
url_params_str: list[tuple[str, str]] = []
url_params_dict = {}
for key, value in url_params.items():
if isinstance(value, (list)):
for item in value:
url_params_str.append((key, item))
url_params_str.extend((key, item) for item in value)
else:
url_params_dict[key] = value

Expand Down Expand Up @@ -2512,12 +2511,11 @@ def query_gql_query(
url_params["update_group"] = str(update_group).lower()

if url_params:
url_params_str = []
url_params_str: list[tuple[str, str]] = []
url_params_dict = {}
for key, value in url_params.items():
if isinstance(value, (list)):
for item in value:
url_params_str.append((key, item))
url_params_str.extend((key, item) for item in value)
else:
url_params_dict[key] = value

Expand Down
2 changes: 1 addition & 1 deletion infrahub_sdk/ctl/cli_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ async def _run_transform(
elif isinstance(error, str) and "Branch:" in error:
console.print(f"[yellow] - {error}")
console.print("[yellow] you can specify a different branch with --branch")
raise typer.Abort()
raise typer.Abort

if inspect.iscoroutinefunction(transform_func):
output = await transform_func(response)
Expand Down
4 changes: 2 additions & 2 deletions infrahub_sdk/ctl/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ def active(self) -> Settings:
return self._settings

print("Configuration not properly loaded")
raise typer.Abort()
raise typer.Abort

def load(self, config_file: str | Path = "infrahubctl.toml", config_data: dict | None = None) -> None:
"""Load configuration.
Expand Down Expand Up @@ -90,7 +90,7 @@ def load_and_exit(self, config_file: str | Path = "infrahubctl.toml", config_dat
for error in exc.errors():
loc_str = [str(item) for item in error["loc"]]
print(f" {'/'.join(loc_str)} | {error['msg']} ({error['type']})")
raise typer.Abort()
raise typer.Abort


SETTINGS = ConfiguredSettings()
4 changes: 2 additions & 2 deletions infrahub_sdk/ctl/repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,8 +150,8 @@ async def add(
await client.execute_graphql(query=query.render(), tracker="mutation-repository-create")


@app.command()
async def list(
@app.command(name="list")
async def list_repositories(
branch: str | None = typer.Option(None, help="Branch on which to list repositories."),
debug: bool = False,
_: str = CONFIG_PARAM,
Expand Down
21 changes: 10 additions & 11 deletions infrahub_sdk/diff.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,18 +117,17 @@ def diff_tree_node_to_node_diff(node_dict: dict[str, Any], branch_name: str) ->
},
)
if not is_cardinality_one and "elements" in relationship_dict:
peer_diffs = []
for element_dict in relationship_dict["elements"]:
peer_diffs.append(
NodeDiffPeer(
action=str(element_dict.get("status")),
summary={
"added": int(element_dict.get("num_added") or 0),
"removed": int(element_dict.get("num_removed") or 0),
"updated": int(element_dict.get("num_updated") or 0),
},
)
peer_diffs = [
NodeDiffPeer(
action=str(element_dict.get("status")),
summary={
"added": int(element_dict.get("num_added") or 0),
"removed": int(element_dict.get("num_removed") or 0),
"updated": int(element_dict.get("num_updated") or 0),
},
)
for element_dict in relationship_dict["elements"]
]
relationship_diff["peers"] = peer_diffs
element_diffs.append(relationship_diff)
return NodeDiff(
Expand Down
7 changes: 6 additions & 1 deletion infrahub_sdk/protocols_generator/generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,12 @@ def __init__(self, schema: dict[str, MainSchemaTypesAll]) -> None:
)

def render(self, sync: bool = True) -> str:
jinja2_env = jinja2.Environment(loader=jinja2.BaseLoader(), trim_blocks=True, lstrip_blocks=True)
jinja2_env = jinja2.Environment(
loader=jinja2.BaseLoader(),
trim_blocks=True,
lstrip_blocks=True,
autoescape=False, # noqa: S701
)
jinja2_env.filters["render_attribute"] = self._jinja2_filter_render_attribute
jinja2_env.filters["render_relationship"] = self._jinja2_filter_render_relationship
jinja2_env.filters["syncify"] = self._jinja2_filter_syncify
Expand Down
3 changes: 3 additions & 0 deletions infrahub_sdk/recorder.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ def default(cls) -> NoRecorder:
def __eq__(self, other: object) -> bool:
return isinstance(other, NoRecorder)

def __hash__(self) -> int:
return hash(self.__class__)


class JSONRecorder(BaseSettings):
model_config = SettingsConfigDict(env_prefix="INFRAHUB_JSON_RECORDER_")
Expand Down
8 changes: 5 additions & 3 deletions infrahub_sdk/spec/object.py
Original file line number Diff line number Diff line change
Expand Up @@ -264,9 +264,11 @@ async def validate_object(
context = context.copy() if context else {}

# First validate if all mandatory fields are present
for element in schema.mandatory_input_names:
if not any([element in data, element in context]):
errors.append(ObjectValidationError(position=position + [element], message=f"{element} is mandatory"))
errors.extend(
ObjectValidationError(position=position + [element], message=f"{element} is mandatory")
for element in schema.mandatory_input_names
if not any([element in data, element in context])
)

# Validate if all attributes are valid
for key, value in data.items():
Expand Down
5 changes: 2 additions & 3 deletions infrahub_sdk/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -338,13 +338,12 @@ def get_user_permissions(data: list[dict]) -> dict:
groups = {}
for group in data:
group_name = group["node"]["display_label"]
permissions = []
permissions: list[str] = []

roles = group["node"].get("roles", {}).get("edges", [])
for role in roles:
role_permissions = role["node"].get("permissions", {}).get("edges", [])
for permission in role_permissions:
permissions.append(permission["node"]["identifier"]["value"])
permissions.extend(permission["node"]["identifier"]["value"] for permission in role_permissions)

groups[group_name] = permissions

Expand Down
8 changes: 4 additions & 4 deletions infrahub_sdk/yaml.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,10 +92,10 @@ def load_file_from_disk(cls, path: Path) -> list[Self]:
has_multiple_document = bool(file_content.count("---") > 1)

if has_multiple_document:
for content in yaml.safe_load_all(file_content):
yaml_files.append(
cls.init(location=path, multiple_documents=has_multiple_document, content=content)
)
yaml_files.extend(
cls.init(location=path, multiple_documents=has_multiple_document, content=content)
for content in yaml.safe_load_all(file_content)
)

else:
yaml_files.append(
Expand Down
49 changes: 40 additions & 9 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,6 @@ ignore = [
##################################################################################################
# Rules below needs to be Investigated #
##################################################################################################
"PT", # flake8-pytest-style
"ERA", # eradicate commented-out code
"SLF001", # flake8-self
"EM", # flake8-errmsg
Expand All @@ -229,7 +228,6 @@ ignore = [
"TID", # flake8-tidy-imports
"FBT", # flake8-boolean-trap
"G", # flake8-logging-format
"RSE", # flake8-raise
"BLE", # flake8-blind-except (BLE)

##################################################################################################
Expand All @@ -239,21 +237,15 @@ ignore = [
##################################################################################################
"B008", # Do not perform function call `typer.Option` in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable
"B904", # Within an `except` clause, raise exceptions with `raise ... from err` or `raise ... from None` to distinguish them from errors in exception handling
"INP001", # File declares a package, but is nested under an implicit namespace package.
"N802", # Function name should be lowercase
"PERF203", # `try`-`except` within a loop incurs performance overhead
"PERF401", # Use a list comprehension to create a transformed list
"PLR0912", # Too many branches
"PLR0913", # Too many arguments in function definition
"PLR0917", # Too many positional arguments
"PLR2004", # Magic value used in comparison
"PLR6301", # Method could be a function, class method, or static method
"PLW0603", # Using the global statement to update `SETTINGS` is discouraged
"PLW1641", # Object does not implement `__hash__` method
"RUF005", # Consider `[*path, str(key)]` instead of concatenation
"RUF029", # Function is declared `async`, but doesn't `await` or use `async` features.
"S311", # Standard pseudo-random generators are not suitable for cryptographic purposes
"S701", # By default, jinja2 sets `autoescape` to `False`. Consider using `autoescape=True`
"SIM108", # Use ternary operator `key_str = f"{value[ALIAS_KEY]}: {key}" if ALIAS_KEY in value and value[ALIAS_KEY] else key` instead of `if`-`else`-block
"TC003", # Move standard library import `collections.abc.Iterable` into a type-checking block
"UP031", # Use format specifiers instead of percent format
Expand All @@ -274,7 +266,6 @@ ignorelist = [
# Review and update builtin shadowing below this line
"filter",
"format",
"list",
"property",
]

Expand All @@ -298,6 +289,7 @@ max-complexity = 17
"ANN202", # Missing return type annotation for private function
"ANN401", # Dynamically typed expressions (typing.Any) are disallowed
"ASYNC240", # Async functions should not use pathlib.Path methods, use trio.Path or anyio.path
"PT013", # Incorrect import of `pytest`; use `import pytest` instead
]

"infrahub_sdk/client.py" = [
Expand All @@ -307,17 +299,56 @@ max-complexity = 17
"PLR0904", # Too many public methods
]

"infrahub_sdk/node/node.py" = [
##################################################################################################
# Review and change the below later #
##################################################################################################
"PLR0912", # Too many branches
]

"infrahub_sdk/node/related_node.py" = [
##################################################################################################
# Review and change the below later #
##################################################################################################
"PLR0912", # Too many branches
]

"infrahub_sdk/pytest_plugin/models.py" = [
"S105", # 'PASS' is not a password but a state
]

"infrahub_sdk/template/__init__.py" = [
##################################################################################################
# Review and change the below later #
##################################################################################################
"S701", # By default, jinja2 sets `autoescape` to `False`. Consider using `autoescape=True` or the `select_autoescape` function to mitigate XSS vulnerabilities.
]

"infrahub_sdk/spec/object.py" = [
##################################################################################################
# Review and change the below later #
##################################################################################################
"PLR0912", # Too many branches
]

"infrahub_sdk/transfer/importer/json.py" = [
##################################################################################################
# Review and change the below later #
##################################################################################################
"PLR0912", # Too many branches
]

"tests/**/*.py" = [
"PLR2004", # Magic value used in comparison
"S101", # Use of assert detected
"S105", # Possible hardcoded password assigned to variable
"S106", # Possible hardcoded password assigned to argument
"ARG001", # Unused function argument
"ARG002", # Unused method argument
"PT006", # Wrong type passed to first argument of `pytest.mark.parametrize`; expected `tuple`
"PT011", # `pytest.raises(ValueError)` is too broad, set the `match` parameter or use a more specific exception
"PT012", # `pytest.raises()` block should contain a single simple statement
"PT013", # Incorrect import of `pytest`; use `import pytest` instead
]

# tests/integration/
Expand Down
2 changes: 1 addition & 1 deletion tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ def _generate_infrahub_sdk_configuration_documentation() -> None:

template_text = template_file.read_text(encoding="utf-8")

environment = jinja2.Environment(trim_blocks=True)
environment = jinja2.Environment(trim_blocks=True, autoescape=jinja2.select_autoescape(default_for_string=False))
template = environment.from_string(template_text)
rendered_file = template.render(properties=properties)

Expand Down
Empty file added tests/fixtures/__init__.py
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
18 changes: 9 additions & 9 deletions uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.