diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 914b361..7f2a655 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -62,35 +62,24 @@ repos: rev: v0.1.8 hooks: - id: ripsecrets - - repo: https://github.com/asottile/pyupgrade - rev: v3.19.0 + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.8.1 hooks: - - id: pyupgrade + - id: ruff-format args: - - --py39-plus - - repo: https://github.com/PyCQA/autoflake - rev: v2.3.1 - hooks: - - id: autoflake - - repo: https://github.com/PyCQA/isort - rev: 5.13.2 - hooks: - - id: isort - - repo: https://github.com/psf/black - rev: 24.10.0 - hooks: - - id: black + - --line-length=110 - repo: https://github.com/PyCQA/prospector rev: v1.13.3 hooks: - id: prospector args: - - --tool=pydocstyle + - --tool=ruff - --die-on-tool-error - --output-format=pylint additional_dependencies: - prospector-profile-duplicated==1.8.0 # pypi - prospector-profile-utils==1.12.2 # pypi + - ruff==0.8.1 # pypi - repo: https://github.com/sbrunner/jsonschema-validator rev: 0.3.2 hooks: diff --git a/.prospector.yaml b/.prospector.yaml index 33df1db..01822cb 100644 --- a/.prospector.yaml +++ b/.prospector.yaml @@ -1,8 +1,16 @@ inherits: - duplicated - utils:base + - utils:fix - utils:no-design-checks + - utils:unsafe pycodestyle: disable: - E704 # multiple statements on one line (def) (not compatible with protocol) + +ruff: + disable: + - D101 # Missing docstring in public class + - D102 # Missing docstring in public method + - D103 # Missing docstring in public function diff --git a/c2c/template/__init__.py b/c2c/template/__init__.py index fc60f99..9c8a22c 100644 --- a/c2c/template/__init__.py +++ b/c2c/template/__init__.py @@ -37,6 +37,7 @@ import sys import traceback from argparse import ArgumentParser, Namespace +from ast import literal_eval from string import Formatter from subprocess import CalledProcessError # nosec from typing import Any, Callable, Optional, Protocol, Union, cast @@ -80,7 +81,7 @@ def transform_path( "The key '%s' in '%s' is not present in: [%s]", key, current_path, - ", ".join([f"'{k}'" for k in value.keys()]), + ", ".join([f"'{k}'" for k in value]), ) else: if len(path) == 1: @@ -190,10 +191,7 @@ def __init__( self.all_environment_dict[env["name"]] = os.environ[env["name"]] def path_in(self, path_list: list[str], list_: list[str]) -> bool: - for path in path_list: - if path in list_: - return True - return False + return any(path in list_ for path in path_list) def format_walker( self, current_vars: dict[str, Any], path: Optional[str] = None, path_list: Optional[list[str]] = None @@ -231,7 +229,7 @@ def format_walker( elif isinstance(current_vars, dict): skip = [] - for key in current_vars.keys(): + for key in current_vars: if path is None: current_path = key current_path_list = [key] @@ -392,12 +390,16 @@ def set_path(item: tuple[dict[str, Any], str], value: str) -> None: def _proceed(files: list[tuple[str, str]], used_vars: dict[str, Any], options: Namespace) -> None: if options.engine == "jinja": - from bottle import jinja2_template as engine # type: ignore # pylint: disable=import-outside-toplevel + from bottle import ( + jinja2_template as engine, # type: ignore # pylint: disable=import-outside-toplevel + ) bottle_template(files, used_vars, engine) elif options.engine == "mako": - from bottle import mako_template as engine # pylint: disable=import-outside-toplevel + from bottle import ( + mako_template as engine, # pylint: disable=import-outside-toplevel + ) bottle_template(files, used_vars, engine) @@ -586,11 +588,9 @@ def __init__(self, interpreter: dict[str, Any]): def __call__(self, expression: str, current_path: str) -> Value: # type: ignore try: - return cast(Value, eval(expression, globs)) # nosec # pylint: disable=eval-used + return cast(Value, literal_eval(expression, globs)) # nosec # pylint: disable=eval-used except Exception: # pragma: nocover # pylint: disable=broad-except - error = "When evaluating {} expression '{}' in '{}' as Python:\n{}".format( - var_name, expression, current_path, traceback.format_exc() - ) + error = f"When evaluating {var_name} expression '{expression}' in '{current_path}' as Python:\n{traceback.format_exc()}" LOG.error(error) if interpreter.get("ignore_error", False): return "ERROR: " + error @@ -622,8 +622,8 @@ def __call__(self, value: str, current_path: str) -> Value: try: return cast(dict[str, Any], json.loads(value)) except ValueError as exception: # pragma: nocover - error = "When evaluating {} expression '{}' in '{}' as JSON: {}".format( - key, value, current_path, exception + error = ( + f"When evaluating {key} expression '{value}' in '{current_path}' as JSON: {exception}" ) LOG.error(error) if interpreter.get("ignore_error", False): @@ -639,8 +639,8 @@ def __call__(self, value: str, current_path: str) -> Value: try: return cast(dict[str, Any], yaml.safe_load(value)) except ParserError as exception: # pragma: nocover - error = "When evaluating {} expression '{}' in '{}' as YAML: {}".format( - key, value, current_path, exception + error = ( + f"When evaluating {key} expression '{value}' in '{current_path}' as YAML: {exception}" ) LOG.error(error) if self.interpreter.get("ignore_error", False): @@ -678,11 +678,9 @@ def __call__(self, value: str, current_path: str) -> Value: # type: ignore expression = self.postprocess["expression"] # [:] to clone expression = expression.format(repr(value)) try: - return cast(Value, eval(expression, globs)) # nosec # pylint: disable=eval-used + return cast(Value, literal_eval(expression, globs)) # nosec # pylint: disable=eval-used except ValueError as exception: # pragma: nocover - error = "When interpreting the expression '{}' in '{}': {}".format( - expression, current_path, exception - ) + error = f"When interpreting the expression '{expression}' in '{current_path}': {exception}" LOG.error(error) if ignore_error: return "ERROR: " + error diff --git a/poetry.lock b/poetry.lock index b439d56..ab966ca 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.4 and should not be changed by hand. [[package]] name = "astroid" @@ -736,6 +736,7 @@ pylint-flask = "0.6" pyroma = {version = ">=2.4", optional = true, markers = "extra == \"with-pyroma\" or extra == \"with_everything\""} PyYAML = "*" requirements-detector = ">=1.3.2" +ruff = {version = "*", optional = true, markers = "extra == \"with-ruff\" or extra == \"with_everything\""} setoptconf-tmp = ">=0.3.1,<0.4.0" toml = ">=0.10.2,<0.11.0" @@ -1107,6 +1108,33 @@ typing-extensions = {version = ">=4.0.0,<5.0", markers = "python_version < \"3.1 [package.extras] jupyter = ["ipywidgets (>=7.5.1,<9)"] +[[package]] +name = "ruff" +version = "0.8.1" +description = "An extremely fast Python linter and code formatter, written in Rust." +optional = false +python-versions = ">=3.7" +files = [ + {file = "ruff-0.8.1-py3-none-linux_armv6l.whl", hash = "sha256:fae0805bd514066f20309f6742f6ee7904a773eb9e6c17c45d6b1600ca65c9b5"}, + {file = "ruff-0.8.1-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:b8a4f7385c2285c30f34b200ca5511fcc865f17578383db154e098150ce0a087"}, + {file = "ruff-0.8.1-py3-none-macosx_11_0_arm64.whl", hash = "sha256:cd054486da0c53e41e0086e1730eb77d1f698154f910e0cd9e0d64274979a209"}, + {file = "ruff-0.8.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2029b8c22da147c50ae577e621a5bfbc5d1fed75d86af53643d7a7aee1d23871"}, + {file = "ruff-0.8.1-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2666520828dee7dfc7e47ee4ea0d928f40de72056d929a7c5292d95071d881d1"}, + {file = "ruff-0.8.1-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:333c57013ef8c97a53892aa56042831c372e0bb1785ab7026187b7abd0135ad5"}, + {file = "ruff-0.8.1-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:288326162804f34088ac007139488dcb43de590a5ccfec3166396530b58fb89d"}, + {file = "ruff-0.8.1-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b12c39b9448632284561cbf4191aa1b005882acbc81900ffa9f9f471c8ff7e26"}, + {file = "ruff-0.8.1-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:364e6674450cbac8e998f7b30639040c99d81dfb5bbc6dfad69bc7a8f916b3d1"}, + {file = "ruff-0.8.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b22346f845fec132aa39cd29acb94451d030c10874408dbf776af3aaeb53284c"}, + {file = "ruff-0.8.1-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:b2f2f7a7e7648a2bfe6ead4e0a16745db956da0e3a231ad443d2a66a105c04fa"}, + {file = "ruff-0.8.1-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:adf314fc458374c25c5c4a4a9270c3e8a6a807b1bec018cfa2813d6546215540"}, + {file = "ruff-0.8.1-py3-none-musllinux_1_2_i686.whl", hash = "sha256:a885d68342a231b5ba4d30b8c6e1b1ee3a65cf37e3d29b3c74069cdf1ee1e3c9"}, + {file = "ruff-0.8.1-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:d2c16e3508c8cc73e96aa5127d0df8913d2290098f776416a4b157657bee44c5"}, + {file = "ruff-0.8.1-py3-none-win32.whl", hash = "sha256:93335cd7c0eaedb44882d75a7acb7df4b77cd7cd0d2255c93b28791716e81790"}, + {file = "ruff-0.8.1-py3-none-win_amd64.whl", hash = "sha256:2954cdbe8dfd8ab359d4a30cd971b589d335a44d444b6ca2cb3d1da21b75e4b6"}, + {file = "ruff-0.8.1-py3-none-win_arm64.whl", hash = "sha256:55873cc1a473e5ac129d15eccb3c008c096b94809d693fc7053f588b67822737"}, + {file = "ruff-0.8.1.tar.gz", hash = "sha256:3583db9a6450364ed5ca3f3b4225958b24f78178908d5c4bc0f46251ccca898f"}, +] + [[package]] name = "semver" version = "3.0.2" @@ -1323,4 +1351,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.0" python-versions = ">=3.9,<4.0" -content-hash = "37c4e76adf8ad982e46ac9a8d27fff382f8669c0b5617302a8f31e7f550e4152" +content-hash = "902eb45a898112873222907659d825e21621c084f22da30afc00d557cf080250" diff --git a/pyproject.toml b/pyproject.toml index ef4cb66..66f677f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -45,7 +45,7 @@ PyYAML = "6.0.2" pyyaml-include = "2.2" [tool.poetry.group.dev.dependencies] -prospector = { version = "1.13.3", extras = ["with_bandit", "with_mypy", "with_pyroma"] } +prospector = { version = "1.13.3", extras = ["with_bandit", "with_mypy", "with_pyroma", "with_ruff"] } prospector-profile-duplicated = "1.8.0" prospector-profile-utils = "1.13.0" pytest = "8.3.4"