Skip to content

Commit

Permalink
downgrade code to work with 3.8
Browse files Browse the repository at this point in the history
  • Loading branch information
DetachHead committed Sep 13, 2023
1 parent d884d54 commit 09209d5
Show file tree
Hide file tree
Showing 13 changed files with 83 additions and 73 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/check and publish.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ jobs:
- run: poetry lock --check
- run: poetry install
- run: poetry run mypy -p pytest_robotframework --python-version ${{ matrix.python_version }}
- run: poetry run mypy tests --python-version 3.11
- run: poetry run mypy tests --python-version ${{ matrix.python_version }}
- run: poetry run black --check --diff .
- run: poetry run ruff .
- run: poetry run pylint pytest_robotframework tests
Expand Down
2 changes: 1 addition & 1 deletion poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ pytest = "^7"
robotframework = "^6.1.1"
deepmerge = "^1.1.0"
basedtyping = ">=0.0.3 <0.2"
exceptiongroup = "^1.1.3"

[tool.poetry.group.dev.dependencies]
black = ">=23"
Expand Down
50 changes: 27 additions & 23 deletions pytest_robotframework/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,17 @@
from __future__ import annotations

import inspect
from collections import defaultdict
from contextlib import AbstractContextManager, nullcontext
from functools import wraps
from pathlib import Path

# yes lets put the Callable type in the collection module.... because THAT makes sense!!!
# said no one ever
from typing import ( # noqa: UP035
from typing import (
TYPE_CHECKING,
Callable,
ParamSpec,
DefaultDict,
Dict,
Type,
TypeVar,
Union,
cast,
overload,
)
Expand All @@ -27,7 +26,7 @@
from robot.running.librarykeywordrunner import LibraryKeywordRunner
from robot.running.statusreporter import StatusReporter
from robot.utils import getshortdoc
from typing_extensions import override
from typing_extensions import ParamSpec, override

from pytest_robotframework._internal.errors import UserError
from pytest_robotframework._internal.robot_utils import execution_context
Expand All @@ -39,12 +38,12 @@
from robot.running.context import _ExecutionContext


RobotVariables = dict[str, object]
RobotVariables = Dict[str, object]

Listener = ListenerV2 | ListenerV3
Listener = Union[ListenerV2, ListenerV3]


_suite_variables = defaultdict[Path, RobotVariables](dict)
_suite_variables = DefaultDict[Path, RobotVariables](dict)


def set_variables(variables: RobotVariables):
Expand All @@ -56,7 +55,7 @@ def set_variables(variables: RobotVariables):
_suite_variables[suite_path] = variables


_resources = list[Path]()
_resources: list[Path] = []


def import_resource(path: Path | str):
Expand Down Expand Up @@ -163,21 +162,24 @@ def exit_status_reporter(
else:
status_reporter.__exit__(type(error), error, error.__traceback__)

class WrappedContextManager(AbstractContextManager[T]):
# https://github.com/python/mypy/issues/16097
class WrappedContextManager(AbstractContextManager): # type:ignore[type-arg]
"""defers exiting the status reporter until after the wrapped context
manager is finished"""

def __init__(
self,
wrapped: AbstractContextManager[T],
status_reporter: AbstractContextManager[None],
wrapped: AbstractContextManager, # type:ignore[type-arg]
status_reporter: AbstractContextManager, # type:ignore[type-arg]
) -> None:
self.wrapped = wrapped
self.status_reporter = status_reporter
self.wrapped = wrapped # type:ignore[no-any-expr]
self.status_reporter = status_reporter # type:ignore[no-any-expr]

@override
def __enter__(self) -> T:
return self.wrapped.__enter__()
return ( # type:ignore[no-any-return]
self.wrapped.__enter__() # type:ignore[no-any-expr,no-untyped-call]
)

@override
def __exit__(
Expand All @@ -187,8 +189,10 @@ def __exit__(
traceback: TracebackType | None,
/,
) -> bool | None:
suppress = self.wrapped.__exit__(exc_type, exc_value, traceback)
exit_status_reporter(self.status_reporter)
suppress = self.wrapped.__exit__( # type:ignore[no-any-expr]
exc_type, exc_value, traceback
)
exit_status_reporter(self.status_reporter) # type:ignore[no-any-expr]
return suppress

@wraps(fn)
Expand Down Expand Up @@ -290,10 +294,10 @@ def keywordify(
)


_errors = list[Exception]()
_errors: list[Exception] = []

_T_ListenerOrSuiteVisitor = TypeVar(
"_T_ListenerOrSuiteVisitor", bound=type[Listener | SuiteVisitor]
"_T_ListenerOrSuiteVisitor", bound=Type[Union[Listener, SuiteVisitor]]
)


Expand Down Expand Up @@ -336,13 +340,13 @@ def inner(*args: _P.args, **kwargs: _P.kwargs) -> T:

class _ListenerRegistry:
def __init__(self):
self.instances = list[Listener]()
self.instances: list[Listener] = []
self.too_late = False


_listeners = _ListenerRegistry()

_T_Listener = TypeVar("_T_Listener", bound=type[Listener])
_T_Listener = TypeVar("_T_Listener", bound=Type[Listener])


def listener(cls: _T_Listener) -> _T_Listener:
Expand Down
39 changes: 25 additions & 14 deletions pytest_robotframework/_internal/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@

from __future__ import annotations

from typing import TYPE_CHECKING, cast
from typing import TYPE_CHECKING, Dict, cast

import pytest
from deepmerge import always_merger
from exceptiongroup import ExceptionGroup
from pytest import TestReport
from robot.api import logger
from robot.libraries.BuiltIn import BuiltIn
Expand Down Expand Up @@ -49,12 +50,12 @@ def _collect_slash_run(session: Session, *, collect_only: bool):
if _listeners.too_late:
raise InternalError("somehow ran collect/run twice???")
robot = RobotFramework() # type:ignore[no-untyped-call]
robot_arg_list = list[str]()
robot_arg_list: list[str] = []
session.config.hook.pytest_robot_modify_args(
args=robot_arg_list, session=session, collect_only=collect_only
)
robot_args = cast(
dict[str, object],
Dict[str, object],
always_merger.merge( # type:ignore[no-untyped-call]
robot.parse_arguments( # type:ignore[no-untyped-call]
[ # type:ignore[no-any-expr]
Expand All @@ -63,27 +64,37 @@ def _collect_slash_run(session: Session, *, collect_only: bool):
session.path,
]
)[0],
dict[str, object](
extension="py:robot",
runemptysuite=True,
parser=[PythonParser(session)],
prerunmodifier=[PytestCollector(session, collect_only=collect_only)],
),
{ # type:ignore[no-any-expr]
"extension": "py:robot",
"runemptysuite": True,
"parser": [PythonParser(session)], # type:ignore[no-any-expr]
"prerunmodifier": [ # type:ignore[no-any-expr]
PytestCollector(session, collect_only=collect_only)
],
},
),
)
if collect_only:
robot_args |= {"report": None, "output": None, "log": None, "exitonerror": True}
robot_args = {
**robot_args,
"report": None,
"output": None,
"log": None,
"exitonerror": True,
}
else:
robot_args = always_merger.merge( # type:ignore[no-untyped-call]
robot_args,
dict[str, object](
prerunmodifier=[PytestRuntestProtocolInjector(session)],
listener=[
{ # type:ignore[no-any-expr]
"prerunmodifier": [ # type:ignore[no-any-expr]
PytestRuntestProtocolInjector(session)
],
"listener": [ # type:ignore[no-any-expr]
PytestRuntestProtocolHooks(session),
ErrorDetector(session),
*_listeners.instances,
],
),
},
)
_listeners.too_late = True
# needed for log_file listener methods to prevent logger from deactivating after the test is
Expand Down
25 changes: 9 additions & 16 deletions pytest_robotframework/_internal/robot_classes.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,7 @@

from contextlib import suppress
from types import ModuleType

# callable is not a collection
from typing import ( # noqa: UP035
TYPE_CHECKING,
Callable,
Generator,
Literal,
ParamSpec,
cast,
)
from typing import TYPE_CHECKING, Callable, Generator, List, Literal, cast

from _pytest import runner
from pluggy import HookCaller, HookImpl
Expand All @@ -23,7 +14,7 @@
from robot.api import SuiteVisitor
from robot.api.interfaces import ListenerV3, Parser, TestDefaults
from robot.running.model import Body
from typing_extensions import override
from typing_extensions import ParamSpec, override

from pytest_robotframework import catch_errors
from pytest_robotframework._internal import robot_library
Expand Down Expand Up @@ -275,10 +266,10 @@ class PytestRuntestProtocolHooks(ListenerV3):
def __init__(self, session: Session):
self.session = session
self.stop_running_hooks = False
self.hookwrappers = dict[HookImpl, _HookWrapper]()
self.hookwrappers: dict[HookImpl, _HookWrapper] = {}
"""hookwrappers that are in the middle of running"""
self.start_test_hooks = list[HookImpl]()
self.end_test_hooks = list[HookImpl]()
self.start_test_hooks: list[HookImpl] = []
self.end_test_hooks: list[HookImpl] = []

def _get_item(self, data: running.TestCase) -> Item:
item = _get_item_from_robot_test(self.session, data)
Expand Down Expand Up @@ -416,7 +407,7 @@ def end_test(
self._call_hooks(item, self.end_test_hooks)


robot_errors_key = StashKey[list[model.Message]]()
robot_errors_key = StashKey[List[model.Message]]()


@catch_errors
Expand Down Expand Up @@ -463,5 +454,7 @@ def log_message(self, message: model.Message):
f" {self.current_test})"
)
if not item.stash.get(robot_errors_key, None):
item.stash[robot_errors_key] = list[model.Message]()
# TODO: why can't mypy infer the type here?
# https://github.com/DetachHead/pytest-robotframework/issues/36
item.stash[robot_errors_key] = [] # type:ignore[misc]
item.stash[robot_errors_key].append(message)
7 changes: 4 additions & 3 deletions pytest_robotframework/_internal/robot_library.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

from __future__ import annotations

from typing import TYPE_CHECKING, Literal, cast
from typing import TYPE_CHECKING, List, Literal, cast

from _pytest._code.code import ExceptionInfo, ExceptionRepr
from _pytest.runner import call_and_report, show_test_item
Expand All @@ -16,18 +16,19 @@
if TYPE_CHECKING:
from pytest_robotframework._internal.robot_utils import Cloaked

_report_key = StashKey[list[TestReport]]()
_report_key = StashKey[List[TestReport]]()


def _call_and_report_robot_edition(
item: Item, when: Literal["setup", "call", "teardown"], **kwargs: object
):
"""wrapper for the `call_and_report` function used by `_pytest.runner.runtestprotocol`
with additional logic to show the result in the robot log"""
reports: list[TestReport]
if _report_key in item.stash:
reports = item.stash[_report_key]
else:
reports = list[TestReport]()
reports = []
item.stash[_report_key] = reports
report = call_and_report( # type:ignore[no-untyped-call]
item, when, log=True, **kwargs
Expand Down
4 changes: 2 additions & 2 deletions pytest_robotframework/_internal/robot_utils.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from __future__ import annotations

from typing import Generic, cast
from typing import Generic, Union, cast

from basedtyping import T
from robot.running.context import _ExecutionContext
Expand All @@ -22,4 +22,4 @@ def execution_context() -> _ExecutionContext | None:
# need to import it every time because it changes
from robot.running import EXECUTION_CONTEXTS

return cast(_ExecutionContext | None, EXECUTION_CONTEXTS.current)
return cast(Union[_ExecutionContext, None], EXECUTION_CONTEXTS.current)
3 changes: 2 additions & 1 deletion pytest_robotframework/_internal/utils.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
from __future__ import annotations

from functools import wraps
from typing import Callable, Concatenate, ParamSpec, cast # noqa: UP035
from typing import Callable, cast

from basedtyping import T
from typing_extensions import Concatenate, ParamSpec

P = ParamSpec("P")

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
from __future__ import annotations

from contextlib import AbstractContextManager, contextmanager

# callable isnt a collection
from typing import TYPE_CHECKING, Callable, assert_type # noqa: UP035
from typing import TYPE_CHECKING, Callable

from robot.api import logger

Expand All @@ -12,6 +10,8 @@
if TYPE_CHECKING:
from collections.abc import Iterator

from typing_extensions import assert_type


@keyword
@contextmanager
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
from __future__ import annotations

from contextlib import AbstractContextManager, contextmanager

# Callable isnt a collection
from typing import TYPE_CHECKING, Callable, assert_type # noqa: UP035
from typing import TYPE_CHECKING, Callable

from pytest_robotframework import keyword

if TYPE_CHECKING:
from collections.abc import Iterator

from typing_extensions import assert_type


@keyword(name="foo bar", tags=("a", "b"))
def foo(): ...
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,10 @@
from __future__ import annotations

from functools import wraps

# callable isnt a collection
from typing import TYPE_CHECKING, Callable, ParamSpec # noqa: UP035
from typing import TYPE_CHECKING, Callable

from robot.api import logger
from typing_extensions import ParamSpec

from pytest_robotframework import keyword

Expand Down
Loading

0 comments on commit 09209d5

Please sign in to comment.