Skip to content
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

Improve Type Hints #455

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
3 changes: 3 additions & 0 deletions src/ahbicht/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,6 @@ class StrEnum(str, Enum): # type:ignore[no-redef]
"""

# We'll live with this class for Python <v3.11. The unit test for python 3.9-3.11 ensure that this works.


__all__ = ["StrEnum"]
2 changes: 1 addition & 1 deletion src/ahbicht/content_evaluation/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ async def is_valid_expression(
# create (but do not await) the evaluation tasks for all possible content evaluation results
# the idea is, that if _any_ evaluation task raises an uncatched exception this can be interpreted as:
# "the expression is invalid"
async def evaluate_with_cer(cer: ContentEvaluationResult):
async def evaluate_with_cer(cer: ContentEvaluationResult) -> None:
content_evaluation_result_setter(cer)
try:
await evaluate_ahb_expression_tree(tree)
Expand Down
2 changes: 1 addition & 1 deletion src/ahbicht/content_evaluation/evaluator_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
3 changes: 2 additions & 1 deletion src/ahbicht/content_evaluation/evaluators.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import inject
from maus.edifact import EdifactFormat, EdifactFormatVersion


# pylint: disable=too-few-public-methods


Expand All @@ -33,7 +34,7 @@ class Evaluator(ABC):
)
_evaluation_method_name_pattern = re.compile(r"^evaluate_(?P<condition_key>\d+)$")

def __init__(self):
def __init__(self) -> None:
"""
initializes a cache with all evaluation methods defined in the (child) class
"""
Expand Down
2 changes: 1 addition & 1 deletion src/ahbicht/content_evaluation/fc_evaluators.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()

Expand Down
2 changes: 1 addition & 1 deletion src/ahbicht/content_evaluation/rc_evaluators.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()

Expand Down
6 changes: 3 additions & 3 deletions src/ahbicht/evaluation_results.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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
"""
Expand Down
2 changes: 1 addition & 1 deletion src/ahbicht/expressions/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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}"
12 changes: 6 additions & 6 deletions src/ahbicht/expressions/ahb_expression_evaluation.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,23 +31,23 @@

# 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.
It returns a list of the seperated requirement indicators with
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.
"""
super().__init__()

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."""
Expand All @@ -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
Expand All @@ -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`
Expand Down Expand Up @@ -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.
Expand Down
4 changes: 3 additions & 1 deletion src/ahbicht/expressions/base_transformer.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
8 changes: 4 additions & 4 deletions src/ahbicht/expressions/condition_expression_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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]
)
Expand Down
10 changes: 5 additions & 5 deletions src/ahbicht/expressions/condition_nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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:
Expand All @@ -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:
Expand Down Expand Up @@ -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:
Expand Down
6 changes: 3 additions & 3 deletions src/ahbicht/expressions/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,20 +93,20 @@ 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"])
except ValueError:
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
"""
Expand Down
14 changes: 7 additions & 7 deletions src/ahbicht/expressions/expression_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -192,23 +192,23 @@ 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)}"
else:
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)}"
else:
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)})"
Expand All @@ -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.
Expand All @@ -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:
Expand Down
Loading
Loading