-
-
Notifications
You must be signed in to change notification settings - Fork 292
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
Add type hints to variables.py and platforms.py #1042
Conversation
|
||
|
||
def requires_python(dist): | ||
# type: (Distribution) -> Optional[SpecifierSet] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that MyPy doesn't actually know what these are due to the vendoring. But I believe that it will at least check we are using type A, rather than type Z; it just doesn't understand the methods/fields on the type.
And this helpful for the reader.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can possibly create stubs for these if needed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, that'd be interesting as a followup once we have higher coverage. pkg_resources
is pretty key to Pex. Having type hints working with Pex would be great.
|
||
class PEXWarning(Warning): | ||
"""Indicates a warning from PEX about suspect buildtime or runtime configuration.""" | ||
|
||
|
||
def configure_warnings(pex_info, env): | ||
if env.PEX_VERBOSE > 0: | ||
# type: (PexInfo, Variables) -> None | ||
if env.PEX_VERBOSE is not None and env.PEX_VERBOSE > 0: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was a bug, although I don't know if we ever hit it. It's possible for PEX_VERBOSE
to be None
, such as if you call ENV.strip()
and the user did not define the value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a bug lurking but its unhittable:
https://github.com/pantsbuild/pex/blob/aae2a6ad55e148ada43f36c1d486af9b2312af50/pex/variables.py#L364-L372
https://github.com/pantsbuild/pex/blob/aae2a6ad55e148ada43f36c1d486af9b2312af50/pex/variables.py#L104-L113
... combined with use_defaults
is True for the global ENV which is what the only use of configure_warnings
in production passes (all of production only uses the global ENV).
pex/platforms.py
Outdated
|
||
def __init__(self, platform, impl, version, abi): | ||
super(Platform, self).__init__() | ||
if not all((platform, impl, version, abi)): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It'd be better to check if these are str
, rather than simply being truthy. But I tried to minimize my changes. Lmk if I should add it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we might want to make abi
at least into an enum when we can drop py2, although I'm not sure checking for str
now makes it harder to do later. I think leaving it as you've got it here sounds good.
self._use_defaults = use_defaults | ||
self._environ = (environ if environ is not None else os.environ).copy() | ||
self._environ = environ.copy() if environ is not None else os.environ.copy() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
MyPy was getting confused trying to find the common denominator between our Dict
vs. the _OSEnviron
type, then complaining that .copy()
wasn't define on that common interface of MutableMapping
. This fixes it.
else: | ||
return self._defaulted(default) | ||
if value is None: | ||
return self._defaulted(default) # type: ignore[return-value] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have to ignore due to the imprecise ._defaulted
method.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might this be the place for a cast()
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can't because it returns Optional[bool]
:/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's quite annoying.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Noted in #1042, but you can use cast, just pass the types as strings when those types (or aliases) are only available at TYPE_CHECKING
time.
value = self._environ.get(variable) | ||
if value is not None: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This method is the same code as before, only refactored by inverting the conditional and early returns.
# type: () -> Optional[bool] | ||
"""Boolean. | ||
|
||
Enable application profiling. If specified and PEX_PROFILE_FILENAME is not specified, PEX | ||
will print profiling information to stdout. | ||
""" | ||
return self._get_path("PEX_PROFILE", default=None) | ||
return self._get_bool("PEX_PROFILE", default=False) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was confusing to me. I think a bug. We document it as a bool
, but treat it as a path
. @jsirois lmk if you know what we intended.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM.
I don't know but git does. See 0fd58f3 via git log -S PEX_PROFILE_FILENAME
.
It looks like an oversight in that change to switch from path to bool when PEX_PROFILE_FILENAME was introduced / split out to parallel PEX_COVERAGE*.
|
||
|
||
def requires_python(dist): | ||
# type: (Distribution) -> Optional[SpecifierSet] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can possibly create stubs for these if needed?
@@ -21,15 +25,17 @@ class Variables(object): | |||
|
|||
@classmethod | |||
def process_pydoc(cls, pydoc): | |||
# type: (Optional[str]) -> Tuple[str, str] | |||
if pydoc is None: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Possibly consider extending this to extract type hints in the future.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Once we require Python 3, that would be super easy to do with typing.get_type_hints()
, which is how the Pants rule signature parsing code works.
|
||
class PEXWarning(Warning): | ||
"""Indicates a warning from PEX about suspect buildtime or runtime configuration.""" | ||
|
||
|
||
def configure_warnings(pex_info, env): | ||
if env.PEX_VERBOSE > 0: | ||
# type: (PexInfo, Variables) -> None | ||
if env.PEX_VERBOSE is not None and env.PEX_VERBOSE > 0: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a bug lurking but its unhittable:
https://github.com/pantsbuild/pex/blob/aae2a6ad55e148ada43f36c1d486af9b2312af50/pex/variables.py#L364-L372
https://github.com/pantsbuild/pex/blob/aae2a6ad55e148ada43f36c1d486af9b2312af50/pex/variables.py#L104-L113
... combined with use_defaults
is True for the global ENV which is what the only use of configure_warnings
in production passes (all of production only uses the global ENV).
# type: () -> Optional[bool] | ||
"""Boolean. | ||
|
||
Enable application profiling. If specified and PEX_PROFILE_FILENAME is not specified, PEX | ||
will print profiling information to stdout. | ||
""" | ||
return self._get_path("PEX_PROFILE", default=None) | ||
return self._get_bool("PEX_PROFILE", default=False) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM.
I don't know but git does. See 0fd58f3 via git log -S PEX_PROFILE_FILENAME
.
It looks like an oversight in that change to switch from path to bool when PEX_PROFILE_FILENAME was introduced / split out to parallel PEX_COVERAGE*.
We don't fix IntegResults, though. That's test only, and we don't seem to need any of the generated dunders. It would be lots of boilerplate to go back. In contrast, `Platform` is used in production so worth the boilerplate.
Unfortunately, so long as we require Python 2, we cannot use
namedtuple
robustly with MyPy because it does not support annotating the fields of a named tuple. So, we recreate namedtuple through our own conventional class. This can be fixed once we require Python 3 to run. See #1041.