From 37a269cfde2566f9c8fdf24912ed38ce524e994b Mon Sep 17 00:00:00 2001 From: Stefan Tatschner Date: Thu, 28 Nov 2024 13:41:33 +0100 Subject: [PATCH] chore: Enable ruff for pydantic_argparse --- pyproject.toml | 1 - src/gallia/pydantic_argparse/__init__.py | 6 +- .../pydantic_argparse/argparse/actions.py | 37 +++---- .../pydantic_argparse/argparse/parser.py | 19 ++-- .../pydantic_argparse/parsers/__init__.py | 5 +- .../pydantic_argparse/parsers/command.py | 4 +- src/gallia/pydantic_argparse/parsers/enum.py | 6 +- .../pydantic_argparse/parsers/literal.py | 9 +- .../pydantic_argparse/parsers/standard.py | 6 +- src/gallia/pydantic_argparse/parsers/utils.py | 8 +- src/gallia/pydantic_argparse/py.typed | 0 .../pydantic_argparse/utils/__init__.py | 2 - .../pydantic_argparse/utils/namespaces.py | 4 +- src/gallia/pydantic_argparse/utils/nesting.py | 10 +- .../pydantic_argparse/utils/pydantic.py | 40 ++++--- src/gallia/pydantic_argparse/utils/types.py | 7 +- vendor/pydantic-argparse/LICENSE.md | 21 ---- vendor/pydantic-argparse/README.md | 0 vendor/pydantic-argparse/pyproject.toml | 102 ------------------ 19 files changed, 80 insertions(+), 207 deletions(-) delete mode 100644 src/gallia/pydantic_argparse/py.typed delete mode 100644 vendor/pydantic-argparse/LICENSE.md delete mode 100644 vendor/pydantic-argparse/README.md delete mode 100644 vendor/pydantic-argparse/pyproject.toml diff --git a/pyproject.toml b/pyproject.toml index 9adcfb001..29b8b3675 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -98,7 +98,6 @@ no_implicit_optional = true [tool.ruff] target-version = "py311" line-length = 100 -extend-exclude = ["src/gallia/pydantic_argparse"] [tool.ruff.lint] select = [ diff --git a/src/gallia/pydantic_argparse/__init__.py b/src/gallia/pydantic_argparse/__init__.py index 4b279b4c2..fb3f3f7ed 100644 --- a/src/gallia/pydantic_argparse/__init__.py +++ b/src/gallia/pydantic_argparse/__init__.py @@ -17,13 +17,11 @@ from gallia.pydantic_argparse.argparse import ArgumentParser -from . import argparse, parsers, utils - class BaseArgument(BaseModel): """Base pydantic model for argument groups.""" - model_config = ConfigDict(json_schema_extra=dict(subcommand=False)) + model_config = ConfigDict(json_schema_extra={"subcommand": False}) class BaseCommand(BaseModel): @@ -34,7 +32,7 @@ class BaseCommand(BaseModel): have `subcommand=True`. """ - model_config = ConfigDict(json_schema_extra=dict(subcommand=True), defer_build=True) + model_config = ConfigDict(json_schema_extra={"subcommand": True}, defer_build=True) # Public Re-Exports diff --git a/src/gallia/pydantic_argparse/argparse/actions.py b/src/gallia/pydantic_argparse/argparse/actions.py index 7eb3a5c96..62934ea60 100644 --- a/src/gallia/pydantic_argparse/argparse/actions.py +++ b/src/gallia/pydantic_argparse/argparse/actions.py @@ -11,16 +11,10 @@ """ import argparse +from collections.abc import Callable, Iterable, Sequence from typing import ( Any, - Callable, - Iterable, - List, - Optional, - Sequence, - Tuple, TypeVar, - Union, cast, ) @@ -79,8 +73,8 @@ def __call__( self, parser: argparse.ArgumentParser, namespace: argparse.Namespace, - values: Union[str, Sequence[Any], None], - option_string: Optional[str] = None, + values: str | Sequence[Any] | None, + option_string: str | None = None, ) -> None: """Parses arguments into a namespace with the specified subparser. @@ -102,7 +96,7 @@ def __call__( # such, this function signature also accepts 'str' and 'None' types for # the values argument. However, in reality, this should only ever be a # list of strings here, so we just do a type cast. - values = cast(List[str], values) + values = cast(list[str], values) # Get Parser Name and Remaining Argument Strings parser_name, *arg_strings = values @@ -151,14 +145,12 @@ def __init__( self, option_strings: Sequence[str], dest: str, - default: Optional[Union[T, str]] = None, - type: Optional[ # noqa: A002] - Union[Callable[[str], T], argparse.FileType] - ] = None, - choices: Optional[Iterable[T]] = None, + default: T | str | None = None, + type_: Callable[[str], T] | argparse.FileType | None = None, + choices: Iterable[T] | None = None, required: bool = False, - help: Optional[str] = None, # noqa: A002 - metavar: Optional[Union[str, Tuple[str, ...]]] = None, + help: str | None = None, # noqa: A002 + metavar: str | tuple[str, ...] | None = None, ) -> None: """Instantiates the Boolean Optional Action. @@ -189,10 +181,7 @@ def __init__( # Check if this option string is a "--" option string if option_string.startswith("--"): # Create a "--no-" negated option string - option_string = "--no-" + option_string[2:] - - # Append the negated option string to the new list as well - _option_strings.append(option_string) + _option_strings.append(f"--no-{option_string[2:]}") # Initialise Super Class super().__init__( @@ -200,7 +189,7 @@ def __init__( dest=dest, nargs=0, default=default, - type=type, + type=type_, choices=choices, required=required, help=help, @@ -211,8 +200,8 @@ def __call__( self, parser: argparse.ArgumentParser, namespace: argparse.Namespace, - values: Optional[Union[str, Sequence[Any]]], - option_string: Optional[str] = None, + values: str | Sequence[Any] | None, + option_string: str | None = None, ) -> None: """Parses the provided boolean arguments into a namespace. diff --git a/src/gallia/pydantic_argparse/argparse/parser.py b/src/gallia/pydantic_argparse/argparse/parser.py index e930c405f..e75bdba72 100644 --- a/src/gallia/pydantic_argparse/argparse/parser.py +++ b/src/gallia/pydantic_argparse/argparse/parser.py @@ -20,12 +20,13 @@ import argparse import sys -from typing import Generic, NoReturn, Optional, Type, Any, Never +from typing import Any, Generic, Never, NoReturn from pydantic import BaseModel, ValidationError from gallia.pydantic_argparse import parsers from gallia.pydantic_argparse.argparse import actions +from gallia.pydantic_argparse.parsers import command from gallia.pydantic_argparse.utils.field import ArgFieldInfo from gallia.pydantic_argparse.utils.nesting import _NestedArgumentParser from gallia.pydantic_argparse.utils.pydantic import PydanticField, PydanticModelT @@ -97,10 +98,10 @@ def __init__( self.extra_defaults = extra_defaults # Add Arguments Groups - self._subcommands: Optional[argparse._SubParsersAction] = None + self._subcommands: argparse._SubParsersAction | None = None # Add Arguments from Model - self._submodels: dict[str, Type[BaseModel]] = dict() + self._submodels: dict[str, type[BaseModel]] = {} self.model = model self._add_model(model) @@ -170,7 +171,9 @@ def _validation_error(self, error: ValidationError, parser: _NestedArgumentParse and argument in self.extra_defaults[model] and self.extra_defaults[model][argument][1] == e["input"] ): - source = f"default of {argument} from {self.extra_defaults[model][argument][0]}: " + source = ( + f"default of {argument} from {self.extra_defaults[model][argument][0]}: " + ) else: # Use the same method, that was used for the CLI generation argument_name = PydanticField(argument, fields[argument]).arg_names() @@ -256,7 +259,7 @@ def _add_version_flag(self) -> None: def _add_model( self, - model: Type[BaseModel], + model: type[BaseModel], arg_group: argparse._ArgumentGroup | None = None, ) -> None: """Adds the `pydantic` model to the argument parser. @@ -278,7 +281,7 @@ def _add_model( for field in PydanticField.parse_model(model): if field.is_a(BaseModel): if field.is_subcommand(): - parsers.command.parse_field(self._commands(), field, self.extra_defaults) + command.parse_field(self._commands(), field, self.extra_defaults) else: # for any nested pydantic models, set default factory to model_construct # method. This allows pydantic to handle if no arguments from a nested @@ -309,7 +312,9 @@ def _add_model( if isinstance(field.info, ArgFieldInfo) and field.info.group is not None: if field.info.group not in explicit_groups: - explicit_groups[field.info.group] = self.add_argument_group(field.info.group) + explicit_groups[field.info.group] = self.add_argument_group( + field.info.group + ) parsers.add_field(explicit_groups[field.info.group], field) added = True diff --git a/src/gallia/pydantic_argparse/parsers/__init__.py b/src/gallia/pydantic_argparse/parsers/__init__.py index 34600474f..c2aa1eb08 100644 --- a/src/gallia/pydantic_argparse/parsers/__init__.py +++ b/src/gallia/pydantic_argparse/parsers/__init__.py @@ -11,13 +11,10 @@ each contain the `should_parse()` and `parse_field()` functions. """ -from typing import Optional - -from gallia.pydantic_argparse.utils.pydantic import PydanticField, PydanticValidator +from gallia.pydantic_argparse.utils.pydantic import PydanticField from . import ( boolean, - command, container, enum, literal, diff --git a/src/gallia/pydantic_argparse/parsers/command.py b/src/gallia/pydantic_argparse/parsers/command.py index 04f700e71..276f161d8 100644 --- a/src/gallia/pydantic_argparse/parsers/command.py +++ b/src/gallia/pydantic_argparse/parsers/command.py @@ -11,7 +11,7 @@ """ import argparse -from typing import Type, Any +from typing import Any from gallia.pydantic_argparse.utils.pydantic import ( PydanticField, @@ -21,7 +21,7 @@ def parse_field( subparser: argparse._SubParsersAction, field: PydanticField, - extra_defaults: dict[Type, dict[str, Any]] | None = None, + extra_defaults: dict[type, dict[str, Any]] | None = None, ) -> None: """Adds command pydantic field to argument parser. diff --git a/src/gallia/pydantic_argparse/parsers/enum.py b/src/gallia/pydantic_argparse/parsers/enum.py index 6eee2dbf3..9c01806ff 100644 --- a/src/gallia/pydantic_argparse/parsers/enum.py +++ b/src/gallia/pydantic_argparse/parsers/enum.py @@ -14,10 +14,10 @@ import enum from typing import Any +from gallia.pydantic_argparse.utils.field import ArgFieldInfo from gallia.pydantic_argparse.utils.pydantic import PydanticField from .utils import SupportsAddArgument -from ..utils.field import ArgFieldInfo def should_parse(field: PydanticField) -> bool: @@ -68,4 +68,6 @@ def parse_field( args.update(field.arg_dest()) # Add Enum Field - parser.add_argument(*field.arg_names(), action=action, help=field.description(), metavar=metavar, **args) + parser.add_argument( + *field.arg_names(), action=action, help=field.description(), metavar=metavar, **args + ) diff --git a/src/gallia/pydantic_argparse/parsers/literal.py b/src/gallia/pydantic_argparse/parsers/literal.py index 96827c805..6a7bfae3f 100644 --- a/src/gallia/pydantic_argparse/parsers/literal.py +++ b/src/gallia/pydantic_argparse/parsers/literal.py @@ -11,13 +11,12 @@ """ import argparse +from typing import Any, Literal, get_args +from gallia.pydantic_argparse.utils.field import ArgFieldInfo from gallia.pydantic_argparse.utils.pydantic import PydanticField from .utils import SupportsAddArgument -from ..utils.field import ArgFieldInfo - -from typing import Literal, get_args, Any def should_parse(field: PydanticField) -> bool: @@ -60,4 +59,6 @@ def parse_field( args.update(field.arg_dest()) # Add Literal Field - parser.add_argument(*field.arg_names(), action=action, help=field.description(), metavar=metavar, **args) + parser.add_argument( + *field.arg_names(), action=action, help=field.description(), metavar=metavar, **args + ) diff --git a/src/gallia/pydantic_argparse/parsers/standard.py b/src/gallia/pydantic_argparse/parsers/standard.py index 6aaf40c3a..c66c0ca01 100644 --- a/src/gallia/pydantic_argparse/parsers/standard.py +++ b/src/gallia/pydantic_argparse/parsers/standard.py @@ -38,5 +38,9 @@ def parse_field( # Add Standard Field parser.add_argument( - *field.arg_names(), action=argparse._StoreAction, help=field.description(), metavar=field.metavar(), **args + *field.arg_names(), + action=argparse._StoreAction, + help=field.description(), + metavar=field.metavar(), + **args, ) diff --git a/src/gallia/pydantic_argparse/parsers/utils.py b/src/gallia/pydantic_argparse/parsers/utils.py index 0a5de700d..5231bbb3f 100644 --- a/src/gallia/pydantic_argparse/parsers/utils.py +++ b/src/gallia/pydantic_argparse/parsers/utils.py @@ -6,7 +6,7 @@ from argparse import Action, FileType from collections.abc import Callable, Iterable -from typing import Any, Protocol, TypeVar, Union +from typing import Any, Protocol, TypeVar _T = TypeVar("_T") @@ -17,11 +17,11 @@ class SupportsAddArgument(Protocol): def add_argument( # noqa: D102 self, *name_or_flags: str, - action: Union[str, type[Action]] = ..., - nargs: Union[int, str] = ..., + action: str | type[Action] = ..., + nargs: int | str = ..., const: Any = ..., default: Any = ..., - type: Union[Callable[[str], _T], FileType] = ..., # noqa: A002 + type: Callable[[str], _T] | FileType = ..., # noqa: A002 choices: Iterable[_T] | None = ..., required: bool = ..., help: str | None = ..., # noqa: A002 diff --git a/src/gallia/pydantic_argparse/py.typed b/src/gallia/pydantic_argparse/py.typed deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/gallia/pydantic_argparse/utils/__init__.py b/src/gallia/pydantic_argparse/utils/__init__.py index a66511e21..f3bd36f74 100644 --- a/src/gallia/pydantic_argparse/utils/__init__.py +++ b/src/gallia/pydantic_argparse/utils/__init__.py @@ -13,5 +13,3 @@ The public interface exposed by this package is the various described utility modules each containing helper functions. """ - -from . import namespaces, pydantic, types diff --git a/src/gallia/pydantic_argparse/utils/namespaces.py b/src/gallia/pydantic_argparse/utils/namespaces.py index e0f720593..3408ecd11 100644 --- a/src/gallia/pydantic_argparse/utils/namespaces.py +++ b/src/gallia/pydantic_argparse/utils/namespaces.py @@ -9,10 +9,10 @@ """ import argparse -from typing import Any, Dict +from typing import Any -def to_dict(namespace: argparse.Namespace) -> Dict[str, Any]: +def to_dict(namespace: argparse.Namespace) -> dict[str, Any]: """Converts a nested namespace to a dictionary recursively. Args: diff --git a/src/gallia/pydantic_argparse/utils/nesting.py b/src/gallia/pydantic_argparse/utils/nesting.py index f7b2bc0da..1f2dec4fd 100644 --- a/src/gallia/pydantic_argparse/utils/nesting.py +++ b/src/gallia/pydantic_argparse/utils/nesting.py @@ -5,7 +5,7 @@ """Utilities to help with parsing arbitrarily nested `pydantic` models.""" from argparse import Namespace -from typing import Any, Generic, Type, TypeAlias +from typing import Any, Generic, TypeAlias from boltons.iterutils import get_path, remap from pydantic import BaseModel @@ -13,7 +13,7 @@ from .namespaces import to_dict from .pydantic import PydanticField, PydanticModelT -ModelT: TypeAlias = PydanticModelT | Type[PydanticModelT] | BaseModel | Type[BaseModel] +ModelT: TypeAlias = PydanticModelT | type[PydanticModelT] | BaseModel | type[BaseModel] class _NestedArgumentParser(Generic[PydanticModelT]): @@ -21,12 +21,12 @@ class _NestedArgumentParser(Generic[PydanticModelT]): def __init__( self, - model: PydanticModelT | Type[PydanticModelT], + model: PydanticModelT | type[PydanticModelT], namespace: Namespace, ) -> None: self.model = model self.args = to_dict(namespace) - self.subcommand_path: tuple[str, ...] = tuple() + self.subcommand_path: tuple[str, ...] = () self.schema: dict[str, Any] = self._get_nested_model_fields(self.model, namespace) self.schema = self._remove_null_leaves(self.schema) @@ -42,7 +42,7 @@ def contains_subcommand(ns: Namespace, subcommand_path: tuple[str, ...]) -> bool return True - model_fields: dict[str, Any] = dict() + model_fields: dict[str, Any] = {} for field in PydanticField.parse_model(model): key = field.name diff --git a/src/gallia/pydantic_argparse/utils/pydantic.py b/src/gallia/pydantic_argparse/utils/pydantic.py index 0cc92c6b5..e04da5073 100644 --- a/src/gallia/pydantic_argparse/utils/pydantic.py +++ b/src/gallia/pydantic_argparse/utils/pydantic.py @@ -10,21 +10,19 @@ dynamically generated validators and environment variable parsers. """ -from collections.abc import Container +from collections.abc import Container, Iterator from dataclasses import dataclass from enum import Enum from types import UnionType from typing import ( + Annotated, Any, - Iterator, Literal, - Type, TypeVar, Union, cast, get_args, get_origin, - Annotated, ) from pydantic import BaseModel @@ -57,7 +55,7 @@ class PydanticField: extra_default: tuple[str, Any] | None = None @classmethod - def parse_model(cls, model: BaseModel | Type[BaseModel]) -> Iterator["PydanticField"]: + def parse_model(cls, model: BaseModel | type[BaseModel]) -> Iterator["PydanticField"]: """Iterator over the pydantic model fields, yielding this wrapper class. Yields: @@ -73,13 +71,15 @@ def _get_type(self, annotation: type | None) -> type | tuple[type | None, ...] | return origin elif origin is Union or origin is UnionType: args = get_args(annotation) - types = list(arg for arg in args if arg is not NoneType) + types = [arg for arg in args if arg is not NoneType] elif origin is None: types = [annotation] else: - raise AssertionError(f"Unsupported origin {origin} for field {self.name} with annotation {annotation}") + raise AssertionError( + f"Unsupported origin {origin} for field {self.name} with annotation {annotation}" + ) - base_types: list[Type | None] = [] + base_types: list[type | None] = [] for t in types: origin = get_origin(t) @@ -143,13 +143,16 @@ def is_a(self, types: Any | tuple[Any, ...]) -> bool: is_type = False for t in field_type: is_type = ( - is_type or t in types or (is_valid and isinstance(t, types)) or (is_valid and issubclass(t, types)) # type: ignore + is_type + or t in types + or (is_valid and isinstance(t, types)) + or (is_valid and issubclass(t, types)) # type: ignore ) return is_type @property - def model_type(self) -> Type[BaseModel]: + def model_type(self) -> type[BaseModel]: """Try to return the `pydantic.BaseModel` type. Raises: @@ -160,13 +163,12 @@ def model_type(self) -> Type[BaseModel]: types = self.get_type() if not isinstance(types, tuple): - return cast(Type[BaseModel], types) + return cast(type[BaseModel], types) for t in types: if isinstance(t, type) and issubclass(t, BaseModel): return t - else: - raise TypeError("No `pydantic.BaseModel`s were found associated with this field.") + raise TypeError("No `pydantic.BaseModel`s were found associated with this field.") def is_subcommand(self) -> bool: """Check whether the input pydantic Model is a subcommand. @@ -283,7 +285,9 @@ def arg_required(self) -> dict[str, bool]: def arg_default(self) -> dict[str, Any]: return ( {} - if self.extra_default is None or isinstance(self.info, ArgFieldInfo) and self.info.positional + if self.extra_default is None + or isinstance(self.info, ArgFieldInfo) + and self.info.positional else {"default": self.extra_default[1]} ) @@ -295,10 +299,14 @@ def arg_const(self) -> dict[str, Any]: ) def arg_dest(self) -> dict[str, str]: - return {} if isinstance(self.info, ArgFieldInfo) and self.info.positional else {"dest": self.name} + return ( + {} + if isinstance(self.info, ArgFieldInfo) and self.info.positional + else {"dest": self.name} + ) -def is_subcommand(model: BaseModel | Type[BaseModel]) -> bool: +def is_subcommand(model: BaseModel | type[BaseModel]) -> bool: """Check whether the input pydantic Model is a subcommand. The default is that all pydantic Models are not subcommands, so this diff --git a/src/gallia/pydantic_argparse/utils/types.py b/src/gallia/pydantic_argparse/utils/types.py index d056d70ef..6e3a4e24d 100644 --- a/src/gallia/pydantic_argparse/utils/types.py +++ b/src/gallia/pydantic_argparse/utils/types.py @@ -8,14 +8,9 @@ comparing the types of `pydantic fields. """ -import sys -from typing import Iterable +from collections.abc import Iterable # Version-Guarded -if sys.version_info < (3, 8): # pragma: <3.8 cover - pass -else: # pragma: >=3.8 cover - pass def all_types(types: Iterable) -> bool: diff --git a/vendor/pydantic-argparse/LICENSE.md b/vendor/pydantic-argparse/LICENSE.md deleted file mode 100644 index ff06aaae1..000000000 --- a/vendor/pydantic-argparse/LICENSE.md +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2021 Hayden Richards - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file diff --git a/vendor/pydantic-argparse/README.md b/vendor/pydantic-argparse/README.md deleted file mode 100644 index e69de29bb..000000000 diff --git a/vendor/pydantic-argparse/pyproject.toml b/vendor/pydantic-argparse/pyproject.toml deleted file mode 100644 index 5db03e1c3..000000000 --- a/vendor/pydantic-argparse/pyproject.toml +++ /dev/null @@ -1,102 +0,0 @@ -# SPDX-FileCopyrightText: Hayden Richards -# -# SPDX-License-Identifier: MIT - -[tool.poetry] -name = "pydantic-argparse" -version = "1.0.0" -description = "Typed Argument Parsing with Pydantic" -authors = ["Hayden Richards "] -readme = "README.md" -license = "MIT" -homepage = "https://pydantic-argparse.supimdos.com" -repository = "https://github.com/SupImDos/pydantic-argparse" -keywords = ["python", "pydantic", "argparse", "typed", "validation"] -include = ["LICENSE.md"] - -[tool.poetry.dependencies] -python = "^3.7" -pydantic = "^2" -boltons = "^23" -importlib_metadata = { version = ">=4", python = "<3.8" } -typing_extensions = { version = ">=4", python = "<3.8" } - -[tool.poetry.group.dev.dependencies] -poethepoet = "^0.18.1" -mypy = "^1.0.0" -ruff = "^0.0.247" -pytest = "^7.2.1" -pytest-cov = "^4.0.0" -pytest-mock = "^3.10.0" -covdefaults = "^2.2.2" -mkdocs-material = "^9.0.13" -mkdocstrings = { extras = ["python-legacy"], version = "^0.20.0" } -mkdocs-gen-files = "^0.4.0" -mkdocs-literate-nav = "^0.6.0" -mkdocs-autorefs = "^0.4.1" - -[tool.poe.tasks] -test = "pytest tests --cov=pydantic_argparse" -type = "mypy tests docs pydantic_argparse" -lint = "ruff tests docs pydantic_argparse" -clean = "rm -rf **/.coverage **/.mypy_cache **/.pytest_cache **/.ruff_cache **/__pycache__" -build = "poetry build" -publish = "poetry publish" -docs-serve = "mkdocs serve" -docs-publish = "mkdocs gh-deploy --force" - -[tool.ruff] -line-length = 120 -select = [ - "F", # flake8 - "E", # pycodestyle errors - "W", # pycodestyle warnings - "S", # flake8-bandit - "B", # flake8-bugbear - "A", # flake8-builtins - "D", # flake8-docstrings - "PT", # flake8-pytest-style - "Q", # flake8-quotes - "RUF", # ruff -] -ignore = [ - "D401", # imperative mood - overly restrictive -] - -[tool.ruff.per-file-ignores] -"__init__.py" = ["F401"] # allow unused imports in `__init__.py` -"tests/*.py" = ["S101"] # allow asserts in unit tests - -[tool.ruff.pydocstyle] -convention = "google" - -[tool.pytest.ini_options] -addopts = "--verbose" -log_cli_level = "DEBUG" -log_cli_format = "%(asctime)s.%(msecs)03d [%(levelname)-8s] (%(name)-11s): %(message)s" -log_cli_date_format = "%Y%m%dT%H%M%S" - -[tool.coverage.run] -plugins = ["covdefaults"] - -[tool.mypy] -check_untyped_defs = true -disallow_untyped_defs = true -disallow_incomplete_defs = true -disallow_untyped_decorators = true -disallow_any_unimported = true -warn_return_any = true -warn_unused_ignores = true -no_implicit_optional = true -show_error_codes = true -plugins = ["pydantic.mypy"] - -[tool.pydantic-mypy] -init_forbid_extra = true -init_typed = true -warn_required_dynamic_aliases = true -warn_untyped_fields = true - -[build-system] -requires = ["poetry-core"] -build-backend = "poetry.core.masonry.api"