-
Notifications
You must be signed in to change notification settings - Fork 2.4k
model.SuiteVisitor
should take a TypeVar
to specify the TestSuite
and TestCase
types
#4940
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
Comments
This is fine if it's possible to specify only the package, but if you needed to specify all types separately like class Example(SuiteVisitor[TestSuite, TestCase, Keyword, If, IfBranch, Try, TryBranch, For, While, Break, Continue, Return, Var, Error]):
... this isn't a good idea. In addition to the usage being horrible, there's a problem that on the result side we have Currently the recommended way to use typing with visitors is to import appropriate type hints: from robot.result import TestSuite, TestCase
class Example(SuiteVisitor):
def start_suite(self, suite: TestSuite):
...
def visit_test(self, test: TestCase):
... I consider the above pretty convenient, which means this enhancement doesn't have too high priority. |
unfortunately mypy doesn't allow that:
it's not typesafe because you could theoretically do something like this: from robot.api import SuiteVisitor
from robot import model, result
class ResultVisitor(SuiteVisitor):
def start_suite(self, suite: result.TestSuite):
print(suite.passed) # a model.TestSuite can be passed to this method which would cause this to crash
foo: SuiteVisitor = ResultVisitor()
foo.start_suite(model.TestSuite()) # crashes because `start_suite` was expecting a `running.TestSuite` but received a `model.TestSuite` |
on a related note, mypy doesn't even allow you to type-check code from robot without adding a |
Do you have ideas how to implement this without making the visitor implementation horribly complicated? Mypy compatibility isn't a goal for us for various reasons, one of them Mypy being annoyingly buggy, and the main reason we are adding type hints is easing IDE usage. The current approach already works well in that regard, so I'm not interested to make the code much more complex just to make Mypy happy. |
the idea i suggested in the original post doesn't seem too complicated to me. the only issue i can see is the redundancy of having to specify both the from typing import TypeAlias
_TS = TypeVar("_TS", bound=model.TestSuite)
_TC = TypeVar("_TS", bound=model.TestCase)
class _SuiteVisitor(Generic[_TS, _TC]):
def start_suite(self, suite: _TS) -> bool | None:
...
def visit_test(self, test: _TC) -> None:
...
RunningSuiteVisitor: TypeAlias = _SuiteVisitor[running.TestSuite, running.TestCase]
ResultSuiteVisitor: TypeAlias = _SuiteVisitor[result.TestSuite, result.TestCase] that way, users can easily subtype whichever one they want depending on what their suite visitor is used for: class ResultVisitor(ResultSuiteVisitor):
...
i agree, mypy seems to be very unreliable and in my experience many of the errors it gives me turn out to be false positives. no idea why it ended up being the most popular type checker. but if you push past those issues, its definitely better than not using a type checker at all and saves lots of time in the long run since it prevents runtime errors that could have easily been caught by a type checker.
assuming the IDE you're targeting is vscode, i would recommend checking out the pyright type checker as an alternative to mypy. in my experience it's probably the most capable of competing with mypy, and seems far less buggy. it's also what vscode uses for autocomplete, so if you want to validate that vscode's autocomplete works, it wouldn't hurt to add it to the CI imo |
Having separate visitors for the running and result model would certainly be easier for users than needing to list all possible item types with from robot.model import SuiteVisitor
from robot.running import TestSuite, TestCase
class Example(SuiteVisitor):
def start_suite(suite: TestSuite):
...
def start_test(test: TestCase):
... If there was a separate from robot.running import RunningSuiteVisitor
class Example(RunningSuiteVisitor):
def start_suite(suite):
...
def start_test(test):
... I personally don't consider adding separate One problem with |
thanks. i'll give that a go and open a PR |
It's not enough for to make just If the main need is having running and result specific visitors, I believe it's easiest to do that my directly extending the current |
Hmm...I don't think Mypy is that buggy. Sure, there might be some corner cases. Have you thought about introducing Ruff (and Ruff formatted)? # mypy src/robot
Found 1472 errors in 83 files (checked 239 source files)
# ruff check src/robot
Found 2184 errors.
[*] 759 fixable with the `--fix` option (373 hidden fixes can be enabled with the `--unsafe-fixes` option). Note: Ruff is configured to use the most obvious rules. Some gradual approach is required to introduce and fix these. |
model.SuiteVisitor
can apply to arunning.TestSuite
orresult.TestSuite
depending on whether it's used as a prerunmodifier or prerebotmodifier, etc. but currently it's typed as only visitingmodel.TestSuite
maybe something like this (similar to
model.TestSuite
's typevars):ideally it should only need one generic to specify either
model
,running
orresult
since i don't think something likeSuiteVisitor[model.TestSuite, running.TestCase]
is possible, but that would probably require some refactoringThe text was updated successfully, but these errors were encountered: