From 925fc894477e8525c1d74675e22e4127a486ad0d Mon Sep 17 00:00:00 2001 From: mwchase Date: Tue, 2 Jul 2019 01:42:59 -0400 Subject: [PATCH] Get typing.NewType working (#1344) Squashed from the following commits: * Update pep0484.py (I don't think I want to know why the cursor jumped to the beginning of the line with every keystroke in GitHub's online editor. Change was entered backwards.) * Added test for inline use of NewType. Currently assuming that wrapped instances should get the underlying type. * Altered tests per https://github.com/davidhalter/jedi/issues/1015#issuecomment-356131566 * Add NewTypeFunction to typing evaluation module * Update AUTHORS.txt * Add a new test, and a speculative justification For now, address only the second comment * Copy code from third comment on the PR From inspection, I *believe* I understand what this code is doing, and as such, I believe this should cause the new test I added in response to the second comment to fail, because that test is based on faulty assumptions. * Explicitly discard the key from the tuple * Update pep0484_typing.py * Test for the wrapped type, not the wrapper "type" * Change the return value from calling a NewType --- AUTHORS.txt | 1 + jedi/evaluate/gradual/typing.py | 28 ++++++++++++++++++++++++++++ test/completion/pep0484_typing.py | 25 +++++++++++++++++++++++++ 3 files changed, 54 insertions(+) diff --git a/AUTHORS.txt b/AUTHORS.txt index 0d4ac10e..b74f628a 100644 --- a/AUTHORS.txt +++ b/AUTHORS.txt @@ -51,5 +51,6 @@ Maksim Novikov (@m-novikov) Tobias Rzepka (@TobiasRzepka) micbou (@micbou) Dima Gerasimov (@karlicoss) +Max Woerner Chase (@mwchase) Note: (@user) means a github user name. diff --git a/jedi/evaluate/gradual/typing.py b/jedi/evaluate/gradual/typing.py index df81821f..b9df8732 100644 --- a/jedi/evaluate/gradual/typing.py +++ b/jedi/evaluate/gradual/typing.py @@ -115,6 +115,8 @@ class TypingModuleName(NameWrapper): yield builtin_from_name(evaluator, u'True') elif name == 'overload': yield OverloadFunction.create_cached(evaluator, self.parent_context, self.tree_name) + elif name == 'NewType': + yield NewTypeFunction.create_cached(evaluator, self.parent_context, self.tree_name) elif name == 'cast': # TODO implement cast yield CastFunction.create_cached(evaluator, self.parent_context, self.tree_name) @@ -459,6 +461,32 @@ class OverloadFunction(_BaseTypingContext): return func_context_set +class NewTypeFunction(_BaseTypingContext): + def py__call__(self, arguments): + ordered_args = arguments.unpack() + next(ordered_args, (None, None)) + _, second_arg = next(ordered_args, (None, None)) + if second_arg is None: + return NO_CONTEXTS + return ContextSet( + NewType( + self.evaluator, + contextualized_node.context, + contextualized_node.node, + second_arg.infer(), + ) for contextualized_node in arguments.get_calling_nodes()) + + +class NewType(Context): + def __init__(self, evaluator, parent_context, tree_node, type_context_set): + super(NewType, self).__init__(evaluator, parent_context) + self._type_context_set = type_context_set + self.tree_node = tree_node + + def py__call__(self, arguments): + return self._type_context_set.execute_annotation() + + class CastFunction(_BaseTypingContext): @repack_with_argument_clinic('type, object, /') def py__call__(self, type_context_set, object_context_set): diff --git a/test/completion/pep0484_typing.py b/test/completion/pep0484_typing.py index c12a8f35..56c506de 100644 --- a/test/completion/pep0484_typing.py +++ b/test/completion/pep0484_typing.py @@ -256,6 +256,31 @@ for key in x.keys(): for value in x.values(): #? int() value + +WrappingType = typing.NewType('WrappingType', str) # Chosen arbitrarily +y = WrappingType(0) # Per https://github.com/davidhalter/jedi/issues/1015#issuecomment-355795929 +#? str() +y + +def testnewtype(y): + """ + :type y: WrappingType + """ + #? str() + y + #? ["upper"] + y.u + +WrappingType2 = typing.NewType() + +def testnewtype2(y): + """ + :type y: WrappingType2 + """ + #? + y + #? [] + y. # python >= 3.4 class TestDefaultDict(typing.DefaultDict[str, int]):