Skip to content

Refine types for distutils.version #1835

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

Merged

Conversation

Michael0x2a
Copy link
Contributor

Note: these type signatures were derived mainly by looking at the docstrings inside distutils.version. For reference:

(Context for why I'm improving this (obscure) corner of stdlib: I'm running mypy with nearly every warning enabled on a project, and it complained that this module was missing type signatures.)

def __ge__(self: T, other: Union[T, str]) -> bool: ...

# Methods part of the 'Version' interface, but not implemented
# within the class itself
Copy link
Member

Choose a reason for hiding this comment

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

Isn't the recommended pattern here to use @AbstractMethod in the base class and add concrete methods to the subclasses? (Or, as a compromise, make only __init__ abstract and add just a concrete __init__ to the subclasses.) Since presumably you can't instantiate Version.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That's true -- the main reason I didn't do that is because the actual implementations of version.py don't import and use the abc module or use the @abstractmethod decorator.

Should I go ahead and do that within the stubs? I don't quite remember if there are any issues with having just the stubs use AbcMeta as a metaclass when the concrete implementations don't.

@gvanrossum
Copy link
Member

At least for mypy, you don't even need to use ABCMeta -- unless CPython's runtime, mypy checks @abstractmethod even without that.

@Michael0x2a
Copy link
Contributor Author

Michael0x2a commented Jan 19, 2018

Ok, I made those changes. I made Version.__init__ abstract as well since Version will crash at runtime if you try instantiating it since it calls the (missing) parse(...) method.

(That said, I think decorating __init__ like this will actually cause mypy to silently ignore any cases where you try directly instantiating Version and just convert that into Any, probably due to this bug? But that's a separate issue from this pull request...)


@abstractmethod
def __init__(self, vstring: Optional[str] = None) -> None: ...
Copy link
Member

Choose a reason for hiding this comment

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

Defaults should always be ....

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ok, done.


def __init__(self, vstring: Optional[str] = None) -> None: ...
def parse(self: _T, vstring: str) -> _T: ...
def __str__(self) -> str: ...
Copy link
Member

Choose a reason for hiding this comment

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

I don't think this needs to be in the stub, since it's unchanged from the base class.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think we do need them -- without them, mypy complains that it can't instantiate StrictVersion and LooseVersion because they contain abstract attributes.

Copy link
Member

Choose a reason for hiding this comment

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

Oh, because the base class has an abstract __str__ implementation; I didn't notice that.

@Michael0x2a
Copy link
Contributor Author

@JelleZijlstra -- I think I fixed the things you pointed out in your review. Was there anything else you wanted me to change?

@JelleZijlstra JelleZijlstra merged commit 1e4c2a9 into python:master Jan 23, 2018
rhysparry added a commit to rhysparry/typeshed that referenced this pull request Feb 8, 2018
* python/master: (269 commits)
  allow Optional[float] for asyncio.wait() timeout arg (python#1860)
  Clean up the pytype blacklist. (python#1851)
  filter function: make the callable of the first overload non-optional so that mypy is able to select the second overload for the  case. (python#1855)
  Accept Text in distutils *Version classes (python#1854)
  Add attrs library (python#1838)
  Add type stub for the lzma module (python#1844)
  Add ImportError attributes name, path for Python 3.3+ (python#1849)
  Add 'message' to click.decorators.version_option (python#1845)
  PEP 553 and PEP 564 (python#1846)
  Adding py36 additions to datetime module (python#1848)
  Remove incomplete thrift stubs that cause false positives. (python#1827)
  adding curses.ascii, curses.panel and curses.textpad modules (python#1792)
  Fix requests session hooks type (python#1794)
  Add StringIO.name and BytesIO.name (python#1802)
  Fix werkzeug environ type (python#1831)
  Change the return type of unittest.TestCase.fail() to NoReturn (python#1843)
  _curses.tparm works on bytes, not str (python#1828)
  Refine types for distutils.version (python#1835)
  Add stub for stat.filemode (python#1837)
  modify pytype_test to run from within pytype too, and support python3 (python#1817)
  ...
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.

3 participants