Conversation
d75d7ee to
a107d0c
Compare
e76f9ef to
5df8a6c
Compare
5df8a6c to
34120f6
Compare
JukkaL
left a comment
There was a problem hiding this comment.
Negative lines of code is great -- thanks! This removes some pretty pointless boilerplate. I have just a bunch of style/documentation related comments.
mypy/myunit/__init__.py
Outdated
| def __init__(self, name: str, suite: 'Optional[Suite]' = None, | ||
| func: Optional[Callable[[], None]] = None) -> None: | ||
| self.func = func | ||
| class ProtoTestCase: |
There was a problem hiding this comment.
I'd suggest renaming this to BaseTestCase, since Proto sounds like a protocol but this is a regular class. Also add a docstring. At least describe how these are run, since this class doesn't seem to have a hint about that.
mypy/myunit/__init__.py
Outdated
| self.tmpdir = None | ||
|
|
||
|
|
||
| class TestCase(ProtoTestCase): |
There was a problem hiding this comment.
Add docstring. In particular, how is this different from the base class?
mypy/test/data.py
Outdated
|
|
||
|
|
||
| class DataDrivenTestCase(TestCase): | ||
| class DataDrivenTestCase(ProtoTestCase): |
There was a problem hiding this comment.
This is kind of confusing, since there seems to be no longer anything in this class about how an individual test case is run. This at least needs a docstring.
mypy/test/data.py
Outdated
| def pytest_pycollect_makeitem(collector: Any, name: str, obj: Any) -> Any: | ||
| if not isinstance(obj, type) or not issubclass(obj, DataSuite): | ||
| return None | ||
| if obj is DataSuite: |
There was a problem hiding this comment.
Add comment here -- something like this perhaps: only classes derived from DataSuite contain test cases, not the DataSuite class.
mypy/test/data.py
Outdated
| def collect(self) -> Iterator['MypyDataCase']: | ||
| for case in self.obj.cases(): | ||
| yield MypyDataCase(case.name, self, case) | ||
| cls = self.obj |
There was a problem hiding this comment.
Add comment -- what is self.obj here and where does it come from? This apparently requires understanding some pytest magic, which many readers likely won't be too familiar with, including me.
| return MypyDataSuite(name, parent=collector) | ||
|
|
||
|
|
||
| class MypyDataSuite(pytest.Class): # type: ignore # inheriting from Any |
There was a problem hiding this comment.
Could you add docstring here as well while you are at it and probably have more context on this than I have?
mypy/test/data.py
Outdated
|
|
||
|
|
||
| class DataSuite: | ||
| files = None # type: typing.ClassVar[List[str]] |
There was a problem hiding this comment.
I'd rather not have the ClassVar annotations here and elsewhere -- they add noise and distract from the main intent of the code. It would be okay to just add a comment here mentioning that all of these should be treated as class variables.
mypy/test/data.py
Outdated
| optional_out = False # type: typing.ClassVar[bool] | ||
| native_sep = False # type: typing.ClassVar[bool] | ||
| require_stable = False # type: typing.ClassVar[bool] | ||
| require_incremental = False # type: typing.ClassVar[bool] |
There was a problem hiding this comment.
require_stable and require_incremental are too specialized to be included here as configuration attributes. It's okay to have is_incremental and has_stable_flags as utility functions in this module (I don't think that they need to be associated with any class), but I'd prefer if these would be explicitly handled using asserts in run_case methods, similar to how these were implemented previously.
There was a problem hiding this comment.
These are also used as filters in the test selection, and the asserts only validate it. I will add a filter method then.
mypy/test/testpythoneval.py
Outdated
| test_python_evaluation, test_temp_dir, True) | ||
| return c | ||
| files = ['pythoneval.test', 'python2eval.test'] # type: typing.ClassVar[List[str]] | ||
| if sys.version_info.major == 3 and sys.version_info.minor >= 4: |
There was a problem hiding this comment.
3.3 is no longer supported for running mypy so this test can be dropped.
|
I think I've addressed the comments except the parts about configuration options. I hope to address the rest tomorrow. |
|
@JukkaL I believe this is ready. |
JukkaL
left a comment
There was a problem hiding this comment.
Thanks for the updates! Looks mostly good now, just a few minor things left.
mypy/myunit/__init__.py
Outdated
| class BaseTestCase: | ||
| """Common base class for _MyUnitTestCase and DataDrivenTestCase. | ||
|
|
||
| Handles temporary folder creation and deletion""" |
There was a problem hiding this comment.
Style nit: In multi-line docstrings add the trailing """ on a separate line like this:
class BaseTestCase:
"""Common base class for _MyUnitTestCase and DataDrivenTestCase.
Handles temporary folder creation and deletion.
"""
...
mypy/myunit/__init__.py
Outdated
|
|
||
| def setup(self) -> None: | ||
| super().setup() | ||
| self.suite.set_up() |
There was a problem hiding this comment.
Inconsistent naming: setup vs set_up?
mypy/test/data.py
Outdated
| obj: object) -> 'Optional[Any]': | ||
| """Called by pytest on each object in modules configured in conftest.py files. | ||
|
|
||
| collector is pytest.Collector, returns Optional[pytest.Class]""" |
There was a problem hiding this comment.
Style nit: """ should be on a separate line in multi-line docstrings.
mypy/test/data.py
Outdated
| # Only classes derived from DataSuite contain test cases, not the DataSuite class itself | ||
| if issubclass(obj, DataSuite) and obj is not DataSuite: | ||
| # Non-None result means this obj is a test case | ||
| # result.collect will be called, with self.obj being obj |
There was a problem hiding this comment.
Here it's a little unclear what result.collect refers to. Maybe rephrase as "The collect method of the returned MypyDataSuite instance will be called later, with self.obj being obj."
mypy/test/testcheck.py
Outdated
| c += parse_test_cases(os.path.join(test_data_prefix, f), | ||
| None, test_temp_dir, True) | ||
| return c | ||
| files = typecheck_files # type: List[str] |
There was a problem hiding this comment.
All of the variable type annotations for in DataSuite subclasses now seem redundant. Can you remove them?
mypy/test/testdmypy.py
Outdated
| def run_case(self, testcase: DataDrivenTestCase) -> None: | ||
| assert self.is_incremental(testcase), "Testcase is not incremental" | ||
| assert self.has_stable_flags(testcase), "Testcase has varying flags" | ||
| assert has_stable_flags(testcase), "Testcase is not incremental" |
There was a problem hiding this comment.
The message should be "Testcase has varying flags" (the messages seem to have been switched on these two lines).
mypy/test/testdmypy.py
Outdated
| assert self.is_incremental(testcase), "Testcase is not incremental" | ||
| assert self.has_stable_flags(testcase), "Testcase has varying flags" | ||
| assert has_stable_flags(testcase), "Testcase is not incremental" | ||
| assert is_incremental(testcase), "Testcase has varying flags" |
There was a problem hiding this comment.
Here's the other switched message.
|
Thanks! Fixed. |
Test discovery logic is duplicated over all the different test suites. This PR refactors this logic to the plugin method
collect(), leaving only the choice of configuration in the classes. This refactoring should enable further optimizations in the discovery of specific tests.The argument
performtoparse_test_cases()is (already) unused, so it is removed. Same goes forinclude_path.The core of the changes can be tested by diffing the result of
py.test --collect-only -n0with the main branch. The only differences should be the execution time and the name of the suitePythonCmdlineSuitewhich is calledPythonEvaluationSuiteon master.TestCaseis split intoBaseTestCaseto avoid sharing of fields and methods that's not really shared with myunit tests, such asrun(). I believe this change need not last long.