Adding trial type annotations to functions with correct return types.#202
Adding trial type annotations to functions with correct return types.#202mitchellkennedy wants to merge 3 commits intodaviddrysdale:devfrom
Conversation
daviddrysdale
left a comment
There was a problem hiding this comment.
I've got some initial questions that I suspect just expose my ignorance of Python type annotations…
|
|
||
|
|
||
| def _extract_possible_number(number): | ||
| # type: (str) -> None |
There was a problem hiding this comment.
I'd naively expect this to be (str) -> str rather than None – maybe I need to learn more about Python type annotations…
There was a problem hiding this comment.
I believe you are correct. I was attempting to follow the convention laid out in examples provided in PEP 484 here. The code they include is as follows:
def embezzle(self, account, funds=1000000, *fake_receipts):
# type: (str, int, *str) -> None
"""Embezzle funds from account using fake receipts."""
<code goes here>
I was assuming they were using None for some sort of compatibility reason, but digging further into the documents, this is meant to specify the return type. I will correct this and submit another PR.
|
|
||
|
|
||
| def _is_viable_phone_number(number): | ||
| # type: (str) -> None |
There was a problem hiding this comment.
As previously noted, you are correct.
|
|
||
| def parse(number, region=None, keep_raw_input=False, | ||
| numobj=None, _check_region=True): | ||
| # type: (str, str, bool, **Any, bool) -> None |
There was a problem hiding this comment.
Again, without knowing much about Python type annotations I'd expect the 4th parameter to have a type like Optional[PhoneNumber] – does that not work?
(BTW, the codebase has a general convention that a parameter called numobj is supposed to be a PhoneNumber object)
There was a problem hiding this comment.
I have just tested this under Python 2 and 3, and it does appear to work. Pardon my confusion on the backwards compatible aspects. I will amend the next PR with this as well.
There was a problem hiding this comment.
Cool, sounds good – thanks for doing this.
By the way, how are you checking that the type annotations work? I'm thinking that I could/should add some type checking to the continuous integration GitHub actions.
There was a problem hiding this comment.
No problem, happy to contribute!
To be specific, what I am implementing is type commenting rather than annotating. Both were introduced in Python 3, but annotating has not been backported to Python 2. Commenting is the suggested alternative to annotating if backwards compatibility needs to be maintained under the heading "Suggested syntax for Python 2.7 and straddling code" in PEP 484.
I've been validating by ensuring the examples I wrote run correctly and also that my IDE (PyCharm) correctly parses and code-completes the functions for which the type hints have been added.
Thinking about checking, I am sure there would be some way to implement that, but I'm not certain at this moment how. Since I have been digging into the documentation, I will give this some thought and raise a feature request if I can come up with something that works once this pull request is complete.
There was a problem hiding this comment.
I've got a hack to do mypy checking in #203; it will be interesting to see how it combines with this PR…
There was a problem hiding this comment.
I don't yet understand the failures in https://github.com/daviddrysdale/python-phonenumbers/runs/3363632239?check_suite_focus=true so I think I've got some more reading to do.
|
|
||
| def parse(number, region=None, keep_raw_input=False, | ||
| numobj=None, _check_region=True): | ||
| # type: (str, str, bool, PhoneNumber, bool) -> Optional[PhoneNumber] |
There was a problem hiding this comment.
Can this ever return None (i.e. should the return type just be PhoneNumber)?
There was a problem hiding this comment.
This line specifically is stating that it should always return PhoneNumber. None can be used just as any other type. It is possibly worth noting that for obvious reasons keeping hinting correct and accurate is the preferred method of operation, but any violation will not result in an exception.
There was a problem hiding this comment.
Doesn't the -> Optional[PhoneNumber] at the end imply that this function can return None as a normal return value (because Optional[T] is the same as Union[T, None])?
In other words I'm suspecting that the last part should be -> PhoneNumber.
There was a problem hiding this comment.
I completely misunderstood what you were asking, sorry. Earlier in this thread, you had used Optional on that line as an example. I was under the impression that you were suggesting that should be the production code for a reason I had not looked hard enough to understand.
I have now removed that and pushed that change.
There was a problem hiding this comment.
Apologies for confusing things, I should have included my guesses at the full type signature.
… which I think should be:
# type: (str, str, bool, Optional[PhoneNumber], bool) -> PhoneNumber
(i.e. the function always returns a PhoneNumber object not None, but the 4th parameter can be either None or PhoneNumber)
WDYT?
|
|
||
| def parse(number, region=None, keep_raw_input=False, | ||
| numobj=None, _check_region=True): | ||
| # type: (str, str, bool, **Any, bool) -> None |
There was a problem hiding this comment.
I've got a hack to do mypy checking in #203; it will be interesting to see how it combines with this PR…
|
@mitchellkennedy thanks for getting the ball rolling with this – your initial type annotations look to match those in #207, so that's been helpful as a cross-check. (Closing because I think this is now subsumed by #207) |
I added a trial set of type annotations relating to #200 for the following functions:
parse
_extract_possible_number
_is_viable_phone_number
_normalize
normalize_digits_only
normalize_diallable_chars_only
convert_alpha_characters_in_number
This has been tested on 3.9, 3.8, 3.7, 3.6, 3.5, and 2.7. thus far.