Skip to content

Commit

Permalink
Fixes for Python 3.9 and mypy warnings
Browse files Browse the repository at this point in the history
Add fallback of import of `ParamSpec` for Python 3.9
Also rename `R` to `R_co` since it is covariant and that is the standard
naming convention
  • Loading branch information
sphuber committed Sep 13, 2023
1 parent 9f2596c commit b32d07e
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 11 deletions.
24 changes: 15 additions & 9 deletions aiida/engine/processes/functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@
# This type is not available for Python 3.9 and older
UnionType = None # type: ignore[assignment,misc] # pylint: disable=invalid-name

try:
from typing import ParamSpec
except ImportError:
# Fallback for Python 3.9 and older
from typing_extensions import ParamSpec # type: ignore[assignment]

try:
get_annotations = inspect.get_annotations
except AttributeError:
Expand Down Expand Up @@ -88,18 +94,18 @@ def get_stack_size(size: int = 2) -> int: # type: ignore[return]
return size - 1


P = t.ParamSpec('P')
R = t.TypeVar('R', covariant=True)
P = ParamSpec('P')
R_co = t.TypeVar('R_co', covariant=True)
N = t.TypeVar('N', bound=ProcessNode)


class ProcessFunctionType(t.Protocol, t.Generic[P, R, N]):
class ProcessFunctionType(t.Protocol, t.Generic[P, R_co, N]):
"""Protocol for a decorated process function."""

def __call__(self, *args: P.args, **kwargs: P.kwargs) -> R:
def __call__(self, *args: P.args, **kwargs: P.kwargs) -> R_co:
...

def run(self, *args: P.args, **kwargs: P.kwargs) -> R:
def run(self, *args: P.args, **kwargs: P.kwargs) -> R_co:
...

def run_get_pk(self, *args: P.args, **kwargs: P.kwargs) -> tuple[dict[str, t.Any] | None, int]:
Expand All @@ -119,7 +125,7 @@ def run_get_node(self, *args: P.args, **kwargs: P.kwargs) -> tuple[dict[str, t.A
spec: t.Callable[[], ProcessSpec]


def calcfunction(function: t.Callable[P, R]) -> ProcessFunctionType[P, R, CalcFunctionNode]:
def calcfunction(function: t.Callable[P, R_co]) -> ProcessFunctionType[P, R_co, CalcFunctionNode]:
"""
A decorator to turn a standard python function into a calcfunction.
Example usage:
Expand All @@ -143,10 +149,10 @@ def calcfunction(function: t.Callable[P, R]) -> ProcessFunctionType[P, R, CalcFu
:param function: The function to decorate.
:return: The decorated function.
"""
return process_function(node_class=CalcFunctionNode)(function)
return process_function(node_class=CalcFunctionNode)(function) # type: ignore[arg-type]


def workfunction(function: t.Callable[P, R]) -> ProcessFunctionType[P, R, WorkFunctionNode]:
def workfunction(function: t.Callable[P, R_co]) -> ProcessFunctionType[P, R_co, WorkFunctionNode]:
"""
A decorator to turn a standard python function into a workfunction.
Example usage:
Expand All @@ -170,7 +176,7 @@ def workfunction(function: t.Callable[P, R]) -> ProcessFunctionType[P, R, WorkFu
:param function: The function to decorate.
:return: The decorated function.
"""
return process_function(node_class=WorkFunctionNode)(function)
return process_function(node_class=WorkFunctionNode)(function) # type: ignore[arg-type]


def process_function(node_class: t.Type['ProcessNode']) -> t.Callable[[FunctionType], FunctionType]:
Expand Down
2 changes: 1 addition & 1 deletion aiida/parsers/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ def parse_calcfunction(**kwargs):
inputs = {'metadata': {'store_provenance': store_provenance}}
inputs.update(parser.get_outputs_for_parsing())

return parse_calcfunction.run_get_node(**inputs) # type: ignore[attr-defined]
return parse_calcfunction.run_get_node(**inputs)

@abstractmethod
def parse(self, **kwargs) -> Optional[ExitCode]:
Expand Down
11 changes: 10 additions & 1 deletion docs/source/nitpick-exceptions
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,15 @@ py:class aiida.storage.sqlite_zip.models.DbGroupNode
py:class aiida.engine.processes.workchains.context.ToContext
py:func aiida.orm.implementation.BackendQueryBuilder

### Typing aliases
py:obj aiida.engine.processes.functions.P
py:obj aiida.engine.processes.functions.N
py:obj aiida.engine.processes.functions.R_co
py:class P
py:class N
py:class aiida.engine.processes.functions.N
py:class aiida.engine.processes.functions.R_co

### third-party packages
# Note: These exceptions are needed if
# * the objects are referenced e.g. as param/return types types in method docstrings (without intersphinx mapping)
Expand All @@ -117,7 +126,7 @@ py:class click.types.Path
py:class click.types.File
py:class click.types.StringParamType
py:func click.shell_completion._start_of_option
py:meth click.Option.get_default
py:meth click.Option.get_default
py:meth fail

py:class requests.models.Response
Expand Down

0 comments on commit b32d07e

Please sign in to comment.