Skip to content

Conversation

@bluetech
Copy link
Member

@bluetech bluetech commented Feb 14, 2020

Extracted from #6717.

Depends/based on #6737.

# we arrive here because of a dynamic call to
# getfixturevalue(argname) usage which was naturally
# not known at parsing/collection time
assert self._pyfuncitem.parent is not None
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is immediately dereferenced below so should be fine.

"""
return self._get_active_fixturedef(argname).cached_result[0]
fixturedef = self._get_active_fixturedef(argname)
assert fixturedef.cached_result is not None
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Immediately dereferenced below.

values.reverse()
return values
values.append(fixturedef)
assert isinstance(current, SubRequest)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This attribute is only set on SubRequest.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would make a helpful in-code comment for future maintainers 😄

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know, once the assert is in, the implication is reversed -- the access is legal because of the assert, not the other way :)



scopes = "session package module class function".split()
scopes = ["session", "package", "module", "class", "function"] # type: List[_Scope]
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed to make the type annotation work (_Scope is a Literal).

"""Look up the index of ``scope`` and raise a descriptive value error
if not defined.
"""
strscopes = scopes # type: Sequence[str]
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a hack to expand the type of scopes to allow checking against an str rather than _Scope.

exceptions.append(sys.exc_info())
if exceptions:
_, val, tb = exceptions[0]
assert val is not None
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dereferenced just below.

# display it now and during the teardown (in .finish()).
if fixturedef.ids:
if callable(fixturedef.ids):
fixturedef.cached_param = fixturedef.ids(request.param)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed so I only need to ignore once.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe a helper method FixtureDef.set_cached_param would be appropriate? Though I can see an argument that it's not worth the trouble when we have to maintain the current option for backwards-compatibility.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I'm not sure it's worth it.

@bluetech bluetech changed the title Type annotate fixtures.py & related WIP: Type annotate fixtures.py & related Feb 14, 2020
@bluetech bluetech changed the title WIP: Type annotate fixtures.py & related Type annotate fixtures.py & related Feb 14, 2020
Copy link
Member

@Zac-HD Zac-HD left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @bluetech! A few questions and suggestions for further annotations below, but overall this looks great to me 😁

# display it now and during the teardown (in .finish()).
if fixturedef.ids:
if callable(fixturedef.ids):
fixturedef.cached_param = fixturedef.ids(request.param)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe a helper method FixtureDef.set_cached_param would be appropriate? Though I can see an argument that it's not worth the trouble when we have to maintain the current option for backwards-compatibility.


def add_funcarg_pseudo_fixture_def(collector, metafunc, fixturemanager):
def add_funcarg_pseudo_fixture_def(
collector, metafunc: "Metafunc", fixturemanager: "FixtureManager"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Worth annotating collector? AFAICT it's an Optional[Type[nodes.Node]].

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When I'm not sure of something, and too lazy to check/verify, I leave it unannotated. Usually some later PR adds it :)

values.reverse()
return values
values.append(fixturedef)
assert isinstance(current, SubRequest)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would make a helpful in-code comment for future maintainers 😄

self,
request: "FixtureRequest",
scope: "_Scope",
param,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

param: object, ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIRC, this one can also be NOTSET, and I'd like to distinguish it in the type annotation from just an object (although object subsumes everything) just for clarity.

I think there is another PR that does that although I sort of lost track myself already 👣



def _eval_scope_callable(scope_callable, fixture_name, config):
def _eval_scope_callable(scope_callable, fixture_name: str, config: Config) -> str:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

scope_callable: Callable[..., str] - speccing keyword arguments is pretty fiddly, but even without the arguments specified this could catch a fair few issues.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer to leave this one for for later.


def getfixtureclosure(self, fixturenames, parentnode, ignore_args=()):
def getfixtureclosure(
self, fixturenames: Tuple[str, ...], parentnode, ignore_args: Sequence[str] = ()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

parentnode: nodes.Node

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure, I prefer to leave this one.

Copy link
Member Author

@bluetech bluetech left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the review @Zac-HD. I applied (some) of your suggestions. Also rebased.


def add_funcarg_pseudo_fixture_def(collector, metafunc, fixturemanager):
def add_funcarg_pseudo_fixture_def(
collector, metafunc: "Metafunc", fixturemanager: "FixtureManager"
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When I'm not sure of something, and too lazy to check/verify, I leave it unannotated. Usually some later PR adds it :)

values.reverse()
return values
values.append(fixturedef)
assert isinstance(current, SubRequest)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know, once the assert is in, the implication is reversed -- the access is legal because of the assert, not the other way :)

self,
request: "FixtureRequest",
scope: "_Scope",
param,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIRC, this one can also be NOTSET, and I'd like to distinguish it in the type annotation from just an object (although object subsumes everything) just for clarity.

I think there is another PR that does that although I sort of lost track myself already 👣



def _eval_scope_callable(scope_callable, fixture_name, config):
def _eval_scope_callable(scope_callable, fixture_name: str, config: Config) -> str:
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer to leave this one for for later.


def getfixtureclosure(self, fixturenames, parentnode, ignore_args=()):
def getfixtureclosure(
self, fixturenames: Tuple[str, ...], parentnode, ignore_args: Sequence[str] = ()
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure, I prefer to leave this one.

# display it now and during the teardown (in .finish()).
if fixturedef.ids:
if callable(fixturedef.ids):
fixturedef.cached_param = fixturedef.ids(request.param)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I'm not sure it's worth it.

@bluetech bluetech closed this Feb 28, 2020
@bluetech bluetech deleted the fixtures-annotate branch February 28, 2020 12:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants