From 76764cbce4716ed70c73535a86e8bd18074f7bd2 Mon Sep 17 00:00:00 2001 From: konstantin Date: Thu, 1 Aug 2024 18:10:12 +0200 Subject: [PATCH] Improve Type Hints on the way to mypy --strict --- src/ahbicht/__init__.py | 3 +++ src/ahbicht/content_evaluation/__init__.py | 2 +- .../content_evaluation/evaluator_factory.py | 2 +- src/ahbicht/content_evaluation/evaluators.py | 3 ++- .../content_evaluation/fc_evaluators.py | 2 +- .../content_evaluation/rc_evaluators.py | 2 +- src/ahbicht/evaluation_results.py | 6 ++--- src/ahbicht/expressions/__init__.py | 2 +- .../expressions/ahb_expression_evaluation.py | 12 +++++----- src/ahbicht/expressions/base_transformer.py | 4 +++- .../condition_expression_parser.py | 8 +++---- src/ahbicht/expressions/condition_nodes.py | 10 ++++---- src/ahbicht/expressions/enums.py | 6 ++--- src/ahbicht/expressions/expression_builder.py | 14 +++++------ .../expressions/expression_resolver.py | 24 +++++++++---------- ...format_constraint_expression_evaluation.py | 8 +++---- src/ahbicht/expressions/hints_provider.py | 4 ++-- src/ahbicht/expressions/package_expansion.py | 4 ++-- ...rement_constraint_expression_evaluation.py | 12 ++++------ src/ahbicht/json_serialization/tree_schema.py | 14 +++++------ src/ahbicht/mapping_results.py | 9 +++---- src/ahbicht/utility_functions.py | 6 ++--- src/ahbicht/validation/validation.py | 10 ++++---- src/ahbicht/validation/validation_results.py | 14 +++++------ src/ahbicht/validation/validation_values.py | 2 +- tox.ini | 1 + 26 files changed, 95 insertions(+), 89 deletions(-) diff --git a/src/ahbicht/__init__.py b/src/ahbicht/__init__.py index 52305203..9dbc34d7 100644 --- a/src/ahbicht/__init__.py +++ b/src/ahbicht/__init__.py @@ -21,3 +21,6 @@ class StrEnum(str, Enum): # type:ignore[no-redef] """ # We'll live with this class for Python None: content_evaluation_result_setter(cer) try: await evaluate_ahb_expression_tree(tree) diff --git a/src/ahbicht/content_evaluation/evaluator_factory.py b/src/ahbicht/content_evaluation/evaluator_factory.py index 0c1e3343..312b3e1d 100644 --- a/src/ahbicht/content_evaluation/evaluator_factory.py +++ b/src/ahbicht/content_evaluation/evaluator_factory.py @@ -111,7 +111,7 @@ def create_and_inject_hardcoded_evaluators( content_evaluation_result, edifact_format=edifact_format, edifact_format_version=edifact_format_version ) - def configure(binder): + def configure(binder): # type:ignore[no-untyped-def] binder.bind(TokenLogicProvider, SingletonTokenLogicProvider([*evaluators])) if evaluatable_data_provider is not None: binder.bind_to_provider(EvaluatableDataProvider, evaluatable_data_provider) diff --git a/src/ahbicht/content_evaluation/evaluators.py b/src/ahbicht/content_evaluation/evaluators.py index f4a9e628..d4780be3 100644 --- a/src/ahbicht/content_evaluation/evaluators.py +++ b/src/ahbicht/content_evaluation/evaluators.py @@ -12,6 +12,7 @@ import inject from maus.edifact import EdifactFormat, EdifactFormatVersion + # pylint: disable=too-few-public-methods @@ -33,7 +34,7 @@ class Evaluator(ABC): ) _evaluation_method_name_pattern = re.compile(r"^evaluate_(?P\d+)$") - def __init__(self): + def __init__(self) -> None: """ initializes a cache with all evaluation methods defined in the (child) class """ diff --git a/src/ahbicht/content_evaluation/fc_evaluators.py b/src/ahbicht/content_evaluation/fc_evaluators.py index b6932e19..83229b1b 100644 --- a/src/ahbicht/content_evaluation/fc_evaluators.py +++ b/src/ahbicht/content_evaluation/fc_evaluators.py @@ -186,7 +186,7 @@ class ContentEvaluationResultBasedFcEvaluator(FcEvaluator): Other than the DictBasedFcEvaluator the outcome is not dependent on the initialization but on the evaluatable data. """ - def __init__(self): + def __init__(self) -> None: super().__init__() self._schema = ContentEvaluationResultSchema() diff --git a/src/ahbicht/content_evaluation/rc_evaluators.py b/src/ahbicht/content_evaluation/rc_evaluators.py index a46aa4f4..18219c26 100644 --- a/src/ahbicht/content_evaluation/rc_evaluators.py +++ b/src/ahbicht/content_evaluation/rc_evaluators.py @@ -119,7 +119,7 @@ class ContentEvaluationResultBasedRcEvaluator(RcEvaluator): Other than the DictBasedRcEvaluator the outcome is not dependent on the initialization but on the evaluatable data. """ - def __init__(self): + def __init__(self) -> None: super().__init__() self._schema: ContentEvaluationResultSchema = ContentEvaluationResultSchema() diff --git a/src/ahbicht/evaluation_results.py b/src/ahbicht/evaluation_results.py index e94106a6..005a8c51 100644 --- a/src/ahbicht/evaluation_results.py +++ b/src/ahbicht/evaluation_results.py @@ -48,7 +48,7 @@ class RequirementConstraintEvaluationResultSchema(Schema): hints = fields.String(load_default=None) @post_load - def deserialize(self, data, **kwargs) -> RequirementConstraintEvaluationResult: + def deserialize(self, data, **kwargs) -> RequirementConstraintEvaluationResult: # type:ignore[no-untyped-def] """ Converts the barely typed data dictionary into an actual RequirementConstraintEvaluationResult :param data: @@ -82,7 +82,7 @@ class FormatConstraintEvaluationResultSchema(Schema): error_message = fields.String(allow_none=True, load_default=None) @post_load - def deserialize(self, data, **kwargs) -> FormatConstraintEvaluationResult: + def deserialize(self, data, **kwargs) -> FormatConstraintEvaluationResult: # type:ignore[no-untyped-def] """ Converts the barely typed data dictionary into an actual FormatConstraintEvaluationResult :param data: @@ -113,7 +113,7 @@ class AhbExpressionEvaluationResultSchema(Schema): format_constraint_evaluation_result = fields.Nested(FormatConstraintEvaluationResultSchema()) @post_load - def deserialize(self, data, **kwargs) -> AhbExpressionEvaluationResult: + def deserialize(self, data, **kwargs) -> AhbExpressionEvaluationResult: # type:ignore[no-untyped-def] """ Converts the barely typed data dictionary into an actual AhbExpressionEvaluationResult """ diff --git a/src/ahbicht/expressions/__init__.py b/src/ahbicht/expressions/__init__.py index 976b605a..df1ddaf0 100644 --- a/src/ahbicht/expressions/__init__.py +++ b/src/ahbicht/expressions/__init__.py @@ -24,7 +24,7 @@ def __init__(self, error_message: str, invalid_expression: Optional[str] = None) self.invalid_expression = invalid_expression self.error_message = error_message - def __str__(self): + def __str__(self) -> str: if self.invalid_expression is None: return f"{self.__class__}: Invalid expression because: {self.error_message}" return f"{self.__class__}: The expression '{self.invalid_expression}' in invalid because: {self.error_message}" diff --git a/src/ahbicht/expressions/ahb_expression_evaluation.py b/src/ahbicht/expressions/ahb_expression_evaluation.py index ff7af132..47862770 100644 --- a/src/ahbicht/expressions/ahb_expression_evaluation.py +++ b/src/ahbicht/expressions/ahb_expression_evaluation.py @@ -31,7 +31,7 @@ # pylint: disable=invalid-name # invalid-name: That's also the reason why they seemingly violate the naming conventions. -class AhbExpressionTransformer(Transformer): +class AhbExpressionTransformer(Transformer[Token, Union[str, PrefixOperator, ModalMark]]): """ Transformer, that evaluates the trees built from the ahb expressions. The input are the conditions as defined in the AHBs in the form of ConditionNodes. @@ -39,7 +39,7 @@ class AhbExpressionTransformer(Transformer): their respective condition expressions already evaluated to booleans. """ - def __init__(self): + def __init__(self) -> None: """ The input are the evaluated format constraint conditions in the form of ConditionNodes. """ @@ -47,7 +47,7 @@ def __init__(self): def CONDITION_EXPRESSION(self, condition_expression: Token) -> str: """Returns the condition expression.""" - return condition_expression.value + return condition_expression.value # type:ignore[no-any-return] def PREFIX_OPERATOR(self, prefix_operator: Token) -> PrefixOperator: """Returns the prefix operator.""" @@ -59,7 +59,7 @@ def MODAL_MARK(self, modal_mark: Token) -> ModalMark: @v_args(inline=True) # Children are provided as *args instead of a list argument def single_requirement_indicator_expression( - self, requirement_indicator: RequirementIndicator, condition_expression + self, requirement_indicator: RequirementIndicator, condition_expression: Union[str, Tree[Token]] ) -> Awaitable[AhbExpressionEvaluationResult]: """ Evaluates the condition expression of the respective requirement indicator expression and returns a list of the @@ -68,7 +68,7 @@ def single_requirement_indicator_expression( return self._single_requirement_indicator_expression_async(requirement_indicator, condition_expression) async def _single_requirement_indicator_expression_async( - self, requirement_indicator: RequirementIndicator, condition_expression + self, requirement_indicator: RequirementIndicator, condition_expression: Union[str, Tree[Token]] ) -> AhbExpressionEvaluationResult: """ See :meth:`single_requirement_indicator_expression_async` @@ -146,7 +146,7 @@ async def _ahb_expression_async( async def evaluate_ahb_expression_tree( - parsed_tree: Tree, + parsed_tree: Tree[Token], ) -> AhbExpressionEvaluationResult: """ Evaluates the tree built from the ahb expressions with the help of the AhbExpressionTransformer. diff --git a/src/ahbicht/expressions/base_transformer.py b/src/ahbicht/expressions/base_transformer.py index 53cc66df..34d90c7c 100644 --- a/src/ahbicht/expressions/base_transformer.py +++ b/src/ahbicht/expressions/base_transformer.py @@ -20,7 +20,9 @@ @v_args(inline=True) # Children are provided as *args instead of a list argument -class BaseTransformer(Transformer, ABC, Generic[SupportedArgumentNode, SupportedReturn]): +class BaseTransformer( + Transformer[SupportedArgumentNode, SupportedReturn], ABC, Generic[SupportedArgumentNode, SupportedReturn] +): """ Transformer that evaluates the trees built from the format constraint expressions. The input are the evaluated format constraint conditions in the form of ConditionNodes. diff --git a/src/ahbicht/expressions/condition_expression_parser.py b/src/ahbicht/expressions/condition_expression_parser.py index af0dd2ce..98c4d014 100644 --- a/src/ahbicht/expressions/condition_expression_parser.py +++ b/src/ahbicht/expressions/condition_expression_parser.py @@ -78,7 +78,7 @@ def parse_condition_expression_to_tree(condition_expression: str) -> Tree[Token] def extract_categorized_keys_from_tree( - tree_or_list: Union[Tree, List[str]], sanitize: bool = False + tree_or_list: Union[Tree[Token], List[str]], sanitize: bool = False ) -> CategorizedKeyExtract: """ find different types of condition nodes inside the given tree or list of keys. @@ -93,19 +93,19 @@ def extract_categorized_keys_from_tree( condition_keys = tree_or_list elif isinstance(tree_or_list, Tree): condition_keys = [ - x.value # type:ignore[attr-defined] + x.value for x in tree_or_list.scan_values( lambda token: token.type == "CONDITION_KEY" # type:ignore[union-attr] ) ] result.package_keys = [ - x.value # type:ignore[attr-defined] + x.value for x in tree_or_list.scan_values( lambda token: token.type == "PACKAGE_KEY" # type:ignore[union-attr] ) ] result.time_condition_keys = [ - x.value # type:ignore[attr-defined] + x.value for x in tree_or_list.scan_values( lambda token: token.type == "TIME_CONDITION_KEY" # type:ignore[union-attr] ) diff --git a/src/ahbicht/expressions/condition_nodes.py b/src/ahbicht/expressions/condition_nodes.py index fc99227e..f3b56727 100644 --- a/src/ahbicht/expressions/condition_nodes.py +++ b/src/ahbicht/expressions/condition_nodes.py @@ -32,10 +32,10 @@ class ConditionFulfilledValue(str, Enum): #: a hint or unevaluated format constraint which does not have a status of being fulfilled or not NEUTRAL = "NEUTRAL" - def __str__(self): + def __str__(self) -> str: return self.value - def __or__(self, other): + def __or__(self, other: "ConditionFulfilledValue") -> "ConditionFulfilledValue": if other == ConditionFulfilledValue.NEUTRAL: # todo: the next 8 lines are nearly identical with __and__ return self if self == ConditionFulfilledValue.NEUTRAL: @@ -49,7 +49,7 @@ def __or__(self, other): return ConditionFulfilledValue.UNKNOWN return ConditionFulfilledValue.UNFULFILLED - def __and__(self, other): + def __and__(self, other: "ConditionFulfilledValue") -> "ConditionFulfilledValue": if other == ConditionFulfilledValue.NEUTRAL: # todo: the next 8 lines are nearly identical with __or__ return self if self == ConditionFulfilledValue.NEUTRAL: @@ -64,7 +64,7 @@ def __and__(self, other): return ConditionFulfilledValue.FULFILLED return ConditionFulfilledValue.UNFULFILLED - def __xor__(self, other): + def __xor__(self, other: "ConditionFulfilledValue") -> "ConditionFulfilledValue": if other == ConditionFulfilledValue.NEUTRAL: return self if self == ConditionFulfilledValue.NEUTRAL: @@ -163,7 +163,7 @@ class EvaluatedFormatConstraintSchema(Schema): # pylint: disable=unused-argument @post_load - def deserialize(self, data, **kwargs) -> EvaluatedFormatConstraint: + def deserialize(self, data, **kwargs) -> EvaluatedFormatConstraint: # type:ignore[no-untyped-def] """ converts the barely typed data dictionary into an actual EvaluatedFormatConstraint :param data: diff --git a/src/ahbicht/expressions/enums.py b/src/ahbicht/expressions/enums.py index 99d4146c..2daec87e 100644 --- a/src/ahbicht/expressions/enums.py +++ b/src/ahbicht/expressions/enums.py @@ -93,12 +93,12 @@ class RequirementIndicatorSchema(Schema): value = fields.String() @pre_load - def pre_load(self, data, **kwargs) -> Dict[Literal["value"], str]: + def pre_load(self, data, **kwargs) -> Dict[Literal["value"], str]: # type:ignore[no-untyped-def] """puts the value in an artificial dictionary""" return {"value": data} @post_load - def post_load(self, data, **kwargs) -> RequirementIndicator: + def post_load(self, data, **kwargs) -> RequirementIndicator: # type:ignore[no-untyped-def] """tries to parse the data as either PrefixOperator or ModalMark""" try: return ModalMark(data["value"]) @@ -106,7 +106,7 @@ def post_load(self, data, **kwargs) -> RequirementIndicator: return PrefixOperator(data["value"]) @post_dump - def post_dump(self, data, **kwargs): + def post_dump(self, data, **kwargs): # type:ignore[no-untyped-def] """ returns the enum value as upper case """ diff --git a/src/ahbicht/expressions/expression_builder.py b/src/ahbicht/expressions/expression_builder.py index cb9adf37..cac53133 100644 --- a/src/ahbicht/expressions/expression_builder.py +++ b/src/ahbicht/expressions/expression_builder.py @@ -3,7 +3,7 @@ """ import re from abc import ABC, abstractmethod -from typing import Generic, Optional, Protocol, Type, TypeVar, Union +from typing import Generic, Optional, Protocol, Type, TypeVar, Union, Self from ahbicht.expressions.condition_nodes import ( ConditionNode, @@ -192,7 +192,7 @@ def __init__(self, init_condition: Optional[_ClassesWithHintAttribute]): def get_expression(self) -> Optional[str]: return self._expression - def land(self, other: Optional[_ClassesWithHintAttribute]) -> ExpressionBuilder: + def land(self, other: Optional[_ClassesWithHintAttribute]) ->Self: if other is not None: if self._expression: self._expression += f" und {HintExpressionBuilder.get_hint_text(other)}" @@ -200,7 +200,7 @@ def land(self, other: Optional[_ClassesWithHintAttribute]) -> ExpressionBuilder: self._expression = HintExpressionBuilder.get_hint_text(other) return self - def lor(self, other: Optional[_ClassesWithHintAttribute]) -> ExpressionBuilder: + def lor(self, other: Optional[_ClassesWithHintAttribute]) ->Self: if other is not None: if self._expression: self._expression += f" oder {HintExpressionBuilder.get_hint_text(other)}" @@ -208,7 +208,7 @@ def lor(self, other: Optional[_ClassesWithHintAttribute]) -> ExpressionBuilder: self._expression = HintExpressionBuilder.get_hint_text(other) return self - def xor(self, other: Optional[_ClassesWithHintAttribute]) -> ExpressionBuilder: + def xor(self, other: Optional[_ClassesWithHintAttribute]) -> Self: if other is not None: if self._expression: self._expression = f"Entweder ({self._expression}) oder ({HintExpressionBuilder.get_hint_text(other)})" @@ -231,7 +231,7 @@ def __init__(self, init_condition: EvaluatedFormatConstraint): def get_expression(self) -> Optional[str]: return self._expression - def land(self, other: EvaluatedFormatConstraint) -> ExpressionBuilder: + def land(self, other: EvaluatedFormatConstraint) -> Self: if other.format_constraint_fulfilled is True: # If a format constraint is connected with "logical and" to another format constraint which is fulfilled, # then the remaining expression/error message stays the same. @@ -243,14 +243,14 @@ def land(self, other: EvaluatedFormatConstraint) -> ExpressionBuilder: self._expression = f"'{self._expression}' und '{other.error_message}'" return self - def lor(self, other: EvaluatedFormatConstraint) -> ExpressionBuilder: + def lor(self, other: EvaluatedFormatConstraint) -> Self: if self.format_constraint_fulfilled is False and other.format_constraint_fulfilled is False: self._expression = f"'{self._expression}' oder '{other.error_message}'" else: self._expression = None return self - def xor(self, other: EvaluatedFormatConstraint) -> ExpressionBuilder: + def xor(self, other: EvaluatedFormatConstraint) -> Self: if self.format_constraint_fulfilled is False and other.format_constraint_fulfilled is False: self._expression = f"Entweder '{self._expression}' oder '{other.error_message}'" elif self.format_constraint_fulfilled is True and other.format_constraint_fulfilled is True: diff --git a/src/ahbicht/expressions/expression_resolver.py b/src/ahbicht/expressions/expression_resolver.py index 181a831c..dac46403 100644 --- a/src/ahbicht/expressions/expression_resolver.py +++ b/src/ahbicht/expressions/expression_resolver.py @@ -46,7 +46,7 @@ async def parse_expression_including_unresolved_subexpressions( return expression_tree -async def expand_packages(parsed_tree: Tree) -> Tree[Token]: +async def expand_packages(parsed_tree: Tree[Token]) -> Tree[Token]: """ Replaces all the "short" packages in parser_tree with the respective "long" condition expressions """ @@ -58,7 +58,7 @@ async def expand_packages(parsed_tree: Tree) -> Tree[Token]: return result -def expand_time_conditions(parsed_tree: Tree) -> Tree[Token]: +def expand_time_conditions(parsed_tree: Tree[Token]) -> Tree[Token]: """ Replaces all the time conditions "UBx" with format constraints (and requirements constraints for UB3) """ @@ -66,19 +66,19 @@ def expand_time_conditions(parsed_tree: Tree) -> Tree[Token]: return result -async def _replace_sub_coroutines_with_awaited_results(tree: Union[Tree, Awaitable[Tree]]) -> Tree[Token]: +async def _replace_sub_coroutines_with_awaited_results(tree: Union[Tree[Token], Awaitable[Tree[Token]]]) -> Tree[Token]: """ awaits all coroutines inside the tree and replaces the coroutines with their respective awaited result. returns an updated tree """ - result: Tree + result: Tree[Token] if inspect.isawaitable(tree): result = await tree else: # if the tree type hint is correct this is always a tree if it's not awaitable - result = tree # type:ignore[assignment] + result = tree # todo: check why lark type hints state the return value of scan_values is always Iterator[str] - sub_results = await asyncio.gather(*result.scan_values(asyncio.iscoroutine)) # type:ignore[call-overload] + sub_results = await asyncio.gather(*result.scan_values(asyncio.iscoroutine)) for coro, sub_result in zip(result.scan_values(asyncio.iscoroutine), sub_results): for sub_tree in result.iter_subtrees(): for child_index, child in enumerate(sub_tree.children): @@ -89,12 +89,12 @@ async def _replace_sub_coroutines_with_awaited_results(tree: Union[Tree, Awaitab # pylint: disable=invalid-name # invalid-name: That's also the reason why it seemingly violates the naming conventions. -class AhbExpressionResolverTransformer(Transformer): +class AhbExpressionResolverTransformer(Transformer[Token, Tree[Token]]): """ Resolves the condition_expressions inside an ahb_expression. """ - def CONDITION_EXPRESSION(self, expression): + def CONDITION_EXPRESSION(self, expression: Token) -> Tree[Token]: """ Replacing the expression_condition with its parsed tree. """ @@ -108,11 +108,11 @@ class PackageExpansionTransformer(Transformer): The PackageExpansionTransformer expands packages inside a tree to condition expressions by using a PackageResolver. """ - def __init__(self): + def __init__(self) -> None: super().__init__() self.token_logic_provider: TokenLogicProvider = inject.instance(TokenLogicProvider) - def package(self, tokens: List[Token]) -> Awaitable[Tree]: + def package(self, tokens: List[Token]) -> Awaitable[Tree[Token]]: """ try to resolve the package using the injected PackageResolver """ @@ -140,7 +140,7 @@ async def _package_async(self, package_key_token: Token, evaluatable_data: Evalu if not resolved_package.has_been_resolved_successfully(): raise NotImplementedError(f"The package '{package_key_token.value}' could not be resolved by {resolver}") # the package_expression is not None because that's the definition of "has been resolved successfully" - tree_result = parse_condition_expression_to_tree(resolved_package.package_expression) # type:ignore[arg-type] + tree_result = parse_condition_expression_to_tree(resolved_package.package_expression) return tree_result @@ -188,7 +188,7 @@ class TimeConditionTransformer(Transformer): constraint for the respective division. """ - def time_condition(self, tokens: List[Token]) -> Tree: + def time_condition(self, tokens: List[Token]) -> Tree[Token]: """ try to resolve the package using the injected PackageResolver """ diff --git a/src/ahbicht/expressions/format_constraint_expression_evaluation.py b/src/ahbicht/expressions/format_constraint_expression_evaluation.py index 665319d5..d743941d 100644 --- a/src/ahbicht/expressions/format_constraint_expression_evaluation.py +++ b/src/ahbicht/expressions/format_constraint_expression_evaluation.py @@ -70,7 +70,7 @@ def xor_composition( def evaluate_format_constraint_tree( - parsed_tree: Tree, input_values: Mapping[str, EvaluatedFormatConstraint] + parsed_tree: Tree[Token], input_values: Mapping[str, EvaluatedFormatConstraint] ) -> EvaluatedFormatConstraint: """ Evaluates the tree built from the format constraint expressions with the help of the FormatConstraintTransformer. @@ -86,7 +86,7 @@ def evaluate_format_constraint_tree( except VisitError as visit_err: raise visit_err.orig_exc - return result + return result # type:ignore[no-any-return] async def format_constraint_evaluation( @@ -100,9 +100,9 @@ async def format_constraint_evaluation( if not format_constraints_expression: format_constraints_fulfilled = True else: - parsed_tree_fc: Tree = parse_condition_expression_to_tree(format_constraints_expression) + parsed_tree_fc: Tree[Token] = parse_condition_expression_to_tree(format_constraints_expression) all_evaluatable_format_constraint_keys: List[str] = [ - t.value for t in parsed_tree_fc.scan_values(lambda v: isinstance(v, Token)) # type:ignore[attr-defined] + t.value for t in parsed_tree_fc.scan_values(lambda v: isinstance(v, Token)) ] input_values: Dict[ str, EvaluatedFormatConstraint diff --git a/src/ahbicht/expressions/hints_provider.py b/src/ahbicht/expressions/hints_provider.py index 405b80aa..232c6be4 100644 --- a/src/ahbicht/expressions/hints_provider.py +++ b/src/ahbicht/expressions/hints_provider.py @@ -35,7 +35,7 @@ class HintsProvider(ABC): "The inheriting class needs to define a format version." ) - def __init__(self): + def __init__(self) -> None: self.logger = logging.getLogger(self.__module__) self.logger.setLevel(logging.DEBUG) self.logger.info("Instantiated %s", self.__class__.__name__) @@ -117,7 +117,7 @@ class ContentEvaluationResultBasedHintsProvider(HintsProvider): data. """ - def __init__(self): + def __init__(self)->None: super().__init__() self._schema = ContentEvaluationResultSchema() diff --git a/src/ahbicht/expressions/package_expansion.py b/src/ahbicht/expressions/package_expansion.py index f426a195..21a6fcbc 100644 --- a/src/ahbicht/expressions/package_expansion.py +++ b/src/ahbicht/expressions/package_expansion.py @@ -30,7 +30,7 @@ class PackageResolver(ABC): "The inheriting package resolver needs to define a format version." ) #: the format version for which the resolver may be used - def __init__(self): + def __init__(self) -> None: self.logger = logging.getLogger(self.__module__) self.logger.setLevel(logging.DEBUG) self.logger.info("Instantiated %s", self.__class__.__name__) @@ -120,7 +120,7 @@ class ContentEvaluationResultBasedPackageResolver(PackageResolver): evaluatable data. """ - def __init__(self): + def __init__(self) -> None: super().__init__() self._schema = ContentEvaluationResultSchema() diff --git a/src/ahbicht/expressions/requirement_constraint_expression_evaluation.py b/src/ahbicht/expressions/requirement_constraint_expression_evaluation.py index bc2331ce..dbed8379 100644 --- a/src/ahbicht/expressions/requirement_constraint_expression_evaluation.py +++ b/src/ahbicht/expressions/requirement_constraint_expression_evaluation.py @@ -64,7 +64,7 @@ def and_composition(self, left: TRCTransformerArgument, right: TRCTransformerArg def _or_xor_composition( self, left: ConditionNode, right: ConditionNode, composition: Literal["or_composition", "xor_composition"] - ): + ) -> EvaluatedComposition: """ Determine the condition_fulfilled attribute for or_/xor_compostions. """ @@ -215,7 +215,7 @@ def then_also_composition(self, left: Type[ConditionNode], right: Type[Condition def evaluate_requirement_constraint_tree( - parsed_tree: Tree, input_values: Mapping[str, TRCTransformerArgument] + parsed_tree: Tree[Token], input_values: Mapping[str, TRCTransformerArgument] ) -> EvaluatedComposition: """ Evaluates the tree built from the expressions with the help of the ConditionsTransformer. @@ -243,7 +243,7 @@ def evaluate_requirement_constraint_tree( async def requirement_constraint_evaluation( - condition_expression: Union[str, Tree] + condition_expression: Union[str, Tree[Token]] ) -> RequirementConstraintEvaluationResult: """ Evaluation of the condition expression in regard to the requirement conditions (rc). @@ -251,14 +251,12 @@ async def requirement_constraint_evaluation( that has already been parsed. """ if isinstance(condition_expression, str): - parsed_tree_rc: Tree = parse_condition_expression_to_tree(condition_expression) + parsed_tree_rc: Tree[Token] = parse_condition_expression_to_tree(condition_expression) else: parsed_tree_rc = condition_expression # get all condition keys from tree - all_condition_keys: List[str] = [ - t.value for t in parsed_tree_rc.scan_values(lambda v: isinstance(v, Token)) # type: ignore[attr-defined] - ] + all_condition_keys: List[str] = [t.value for t in parsed_tree_rc.scan_values(lambda v: isinstance(v, Token))] condition_node_builder = ConditionNodeBuilder(all_condition_keys) input_nodes = await condition_node_builder.requirement_content_evaluation_for_all_condition_keys() diff --git a/src/ahbicht/json_serialization/tree_schema.py b/src/ahbicht/json_serialization/tree_schema.py index 15dd0a89..f900b0d3 100644 --- a/src/ahbicht/json_serialization/tree_schema.py +++ b/src/ahbicht/json_serialization/tree_schema.py @@ -2,7 +2,7 @@ Schemata for the JSON serialization of expressions. """ -from typing import Optional, Union +from typing import Optional, Union, Literal, Dict,Any from lark import Token, Tree from marshmallow import Schema, fields, post_load, pre_dump @@ -17,12 +17,12 @@ class _TokenOrTree: A class that is easily serializable as dictionary and allows us to _not_ use the marshmallow-union package. """ - def __init__(self, token: Optional[Token] = None, tree: Optional[Tree] = None): + def __init__(self, token: Optional[Token] = None, tree: Optional[Tree[Token]] = None): self.token = token self.tree = tree token: Optional[Token] - tree: Optional[Tree] + tree: Optional[Tree[Token]] class _TokenOrTreeSchema(Schema): @@ -41,7 +41,7 @@ class _TokenOrTreeSchema(Schema): ) @post_load - def deserialize(self, data, **kwargs) -> Union[str, Tree, Token]: + def deserialize(self, data:Dict[Literal["tree", "token"], Any], **kwargs) -> Union[str, Tree[Token], Token]: # type:ignore[no-untyped-def] """ convert a dictionary back to a string, Tree or Token :param data: @@ -57,7 +57,7 @@ def deserialize(self, data, **kwargs) -> Union[str, Tree, Token]: return data @pre_dump - def prepare_tree_for_serialization(self, data, **kwargs) -> _TokenOrTree: + def prepare_tree_for_serialization(self, data, **kwargs) -> _TokenOrTree: # type:ignore[no-untyped-def] """ Create a string of tree object :param data: @@ -80,7 +80,7 @@ class TokenSchema(Schema): type = fields.String(dump_default=False, data_key="type") @post_load - def deserialize(self, data, **kwargs) -> Token: + def deserialize(self, data, **kwargs) -> Token: # type:ignore[no-untyped-def] """ converts the barely typed data dictionary into an actual Tree :param data: @@ -100,7 +100,7 @@ class TreeSchema(Schema): children = fields.List(fields.Nested(lambda: _TokenOrTreeSchema())) # pylint: disable=unnecessary-lambda @post_load - def deserialize(self, data, **kwargs) -> Tree: + def deserialize(self, data, **kwargs) -> Tree[Token]: """ converts the barely typed data dictionary into an actual Tree :param data: diff --git a/src/ahbicht/mapping_results.py b/src/ahbicht/mapping_results.py index 527bab91..2c75be9d 100644 --- a/src/ahbicht/mapping_results.py +++ b/src/ahbicht/mapping_results.py @@ -6,7 +6,7 @@ import attrs from marshmallow import Schema, fields, post_load -from marshmallow_enum import EnumField # type:ignore[import] +from marshmallow_enum import EnumField # type:ignore[import-untyped] from maus.edifact import EdifactFormat @@ -40,8 +40,9 @@ class ConditionKeyConditionTextMappingSchema(Schema): condition_text = fields.String(load_default=None) # pylint:disable=unused-argument + @post_load - def deserialize(self, data, **kwargs) -> ConditionKeyConditionTextMapping: + def deserialize(self, data, **kwargs) -> ConditionKeyConditionTextMapping: # type:ignore[no-untyped-def] """ Converts the barely typed data dictionary into an actual :class:`.ConditionKeyConditionTextMapping` """ @@ -84,7 +85,7 @@ class PackageKeyConditionExpressionMappingSchema(Schema): # pylint:disable=unused-argument @post_load - def deserialize(self, data, **kwargs) -> PackageKeyConditionExpressionMapping: + def deserialize(self, data, **kwargs) -> PackageKeyConditionExpressionMapping: # type:ignore[no-untyped-def] """ Converts the barely typed data dictionary into an actual :class:`.PackageKeyConditionExpressionMapping` """ @@ -92,7 +93,7 @@ def deserialize(self, data, **kwargs) -> PackageKeyConditionExpressionMapping: # pylint:disable=unused-argument -def check_max_greater_or_equal_than_min(instance: "Repeatability", attribute, value): +def check_max_greater_or_equal_than_min(instance: "Repeatability", attribute, value): # type:ignore[no-untyped-def] """ assert that 0<=min ValidationResultInContext: """ Validates data elements by handing them over to specialized functions for freetext or value pool data elements. @@ -248,7 +248,7 @@ async def validate_data_element( async def validate_data_element_freetext( data_element: DataElementFreeText, segment_requirement: Optional[RequirementValidationValue] = None, - soll_is_required=True, + soll_is_required: bool = True, ) -> ValidationResultInContext: """ Validates a freetext data element, e.g. 'Dokumentennummer'. @@ -278,7 +278,7 @@ async def validate_data_element_freetext( hints=invalid_expr_error.error_message, data_element_data_type=DataElementDataType.TEXT, ), - discriminator=data_element.discriminator, # type:ignore[arg-type] + discriminator=data_element.discriminator, ) # requirement constraints @@ -311,7 +311,7 @@ async def validate_data_element_freetext( str(result), ) return ValidationResultInContext( - discriminator=data_element.discriminator, # type:ignore[arg-type] + discriminator=data_element.discriminator, validation_result=result, ) @@ -401,7 +401,7 @@ async def validate_data_element_valuepool( str(result), ) return ValidationResultInContext( - discriminator=data_element.discriminator, # type:ignore[arg-type] + discriminator=data_element.discriminator, validation_result=result, ) diff --git a/src/ahbicht/validation/validation_results.py b/src/ahbicht/validation/validation_results.py index f6c6fed3..b6e73a89 100644 --- a/src/ahbicht/validation/validation_results.py +++ b/src/ahbicht/validation/validation_results.py @@ -6,7 +6,7 @@ import attrs import maus.models.edifact_components from marshmallow import Schema, fields, post_load -from marshmallow_enum import EnumField # type:ignore[import] +from marshmallow_enum import EnumField # type:ignore[import-untyped] from ahbicht.validation.validation_values import RequirementValidationValue @@ -42,7 +42,7 @@ class ValidationResultSchema(ValidationResultAttributesSchema): """ @post_load - def deserialize(self, data, **kwargs) -> ValidationResult: + def deserialize(self, data, **kwargs) -> ValidationResult: # type:ignore[no-untyped-def] """ Converts the barely typed data dictionary into an actual ValidationResult :param data: @@ -51,7 +51,7 @@ def deserialize(self, data, **kwargs) -> ValidationResult: """ return ValidationResult(**data) - def dump(self, obj, **kwargs) -> Union[Any, list]: + def dump(self, obj, **kwargs) -> Union[Any, Dict[str,Any] ]: # type:ignore[no-untyped-def] """ A way to dump the subclasses DataElementValidationResult and SegmentLevelValidationResult of ValidationResult @@ -77,7 +77,7 @@ class SegmentLevelValidationResultSchema(ValidationResultAttributesSchema): """ @post_load - def deserialize(self, data, **kwargs) -> SegmentLevelValidationResult: + def deserialize(self, data, **kwargs) -> SegmentLevelValidationResult: # type:ignore[no-untyped-def] """ Converts the barely typed data dictionary into an actual ValidationResult :param data: @@ -132,7 +132,7 @@ class DataElementValidationResultSchema(ValidationResultAttributesSchema): ) @post_load - def deserialize(self, data, **kwargs) -> DataElementValidationResult: + def deserialize(self, data, **kwargs) -> DataElementValidationResult: # type:ignore[no-untyped-def] """ Converts the barely typed data dictionary into an actual DataElementValidationResult :param data: @@ -162,7 +162,7 @@ class ValidationResultInContextSchema(Schema): # pylint:disable=unused-argument @post_load - def deserialize(self, data, **kwargs) -> ValidationResultInContext: + def deserialize(self, data, **kwargs) -> ValidationResultInContext: # type:ignore[no-untyped-def] """ Serializes a ValidationResultDiscriminator so that the discriminator is the key and the validation_result the value. @@ -249,7 +249,7 @@ class ListOfValidationResultInContextSchema(Schema): # pylint:disable=unused-argument @post_load - def deserialize(self, data, **kwargs) -> ListOfValidationResultInContext: + def deserialize(self, data, **kwargs) -> ListOfValidationResultInContext: # type:ignore[no-untyped-def] """ Deserializes a ValidationResultDiscriminator """ diff --git a/src/ahbicht/validation/validation_values.py b/src/ahbicht/validation/validation_values.py index 9b7cb177..21be836d 100644 --- a/src/ahbicht/validation/validation_values.py +++ b/src/ahbicht/validation/validation_values.py @@ -21,5 +21,5 @@ class RequirementValidationValue(StrEnum): IS_OPTIONAL_AND_EMPTY = "IS_OPTIONAL_AND_EMPTY" #: field is optional and empty IS_OPTIONAL_AND_FILLED = "IS_OPTIONAL_AND_FILLED" #: field is optional and filled - def __str__(self): + def __str__(self) -> str: return self.value diff --git a/tox.ini b/tox.ini index 7b62befd..fd1e0131 100644 --- a/tox.ini +++ b/tox.ini @@ -42,6 +42,7 @@ deps = -r dev_requirements/requirements-type_check.txt commands = mypy --show-error-codes src/ahbicht + # mypy --show-error-codes src/ahbicht --strict mypy --show-error-codes unittests mypy --show-error-codes json_schemas/generate_json_schemas.py # add single files (ending with .py) or packages here