Make PyCollector an implementation detail - don't use in hook type annotation

The `pytest_pycollector_makeitem` argument `collector` is currently
annotated with type `PyCollector`. As part of #7469, that would have
required us to expose it in the public API. But really it's an
implementation detail, not something we want to expose. So replace the
annotation with the concrete python collector types that are passed.

Strictly speaking, `pytest_pycollector_makeitem` is called from
`PyCollector.collect()`, so the new type annotation is incorrect if
another type subclasses `PyCollector`. But the set of python collectors
is closed (mapping to language constructs), and the type is private, so
there shouldn't be any other deriving classes, and we can consider it
effectively sealed (unfortunately Python does not provide a way to
express this - yet?).
This commit is contained in:
Ran Benita
2021-11-04 00:21:35 +02:00
parent 7ae23ff8ae
commit e05e696fda
3 changed files with 14 additions and 9 deletions

View File

@@ -224,11 +224,15 @@ def pytest_pycollect_makemodule(module_path: Path, parent) -> "Module":
@hookimpl(trylast=True)
def pytest_pycollect_makeitem(collector: "PyCollector", name: str, obj: object):
def pytest_pycollect_makeitem(
collector: Union["Module", "Class"], name: str, obj: object
) -> Union[None, nodes.Item, nodes.Collector, List[Union[nodes.Item, nodes.Collector]]]:
assert isinstance(collector, (Class, Module)), type(collector)
# Nothing was collected elsewhere, let's do it here.
if safe_isclass(obj):
if collector.istestclass(obj, name):
return Class.from_parent(collector, name=name, obj=obj)
klass: Class = Class.from_parent(collector, name=name, obj=obj)
return klass
elif collector.istestfunction(obj, name):
# mock seems to store unbound methods (issue473), normalize it.
obj = getattr(obj, "__func__", obj)
@@ -247,15 +251,16 @@ def pytest_pycollect_makeitem(collector: "PyCollector", name: str, obj: object):
)
elif getattr(obj, "__test__", True):
if is_generator(obj):
res = Function.from_parent(collector, name=name)
res: Function = Function.from_parent(collector, name=name)
reason = "yield tests were removed in pytest 4.0 - {name} will be ignored".format(
name=name
)
res.add_marker(MARK_GEN.xfail(run=False, reason=reason))
res.warn(PytestCollectionWarning(reason))
return res
else:
res = list(collector._genfunctions(name, obj))
return res
return list(collector._genfunctions(name, obj))
return None
class PyobjMixin(nodes.Node):