diff options
author | Christian Tismer <tismer@stackless.com> | 2019-08-22 18:57:11 +0200 |
---|---|---|
committer | Christian Tismer <tismer@stackless.com> | 2019-08-29 15:44:07 +0200 |
commit | d4acbacd7a655e3ff9e17663a23ed0d822b84850 (patch) | |
tree | cfe5b2666c5e98c848b22ef7b493c775cff5aebc /sources/pyside2 | |
parent | 4d63dfffb661115f58cca60c80c4649ba982e01b (diff) |
signature: Support typing.Optional[T] and refine a bit
The signature was missing "typing.Optional[T]" which has to be wrapped
around any argument with a default value of "None".
This is the only case where the repr of a type looks different than
it was written, because it renders as "typing.Union[T, NoneType]".
Solving that by redefining a few typing structures was way too
hard and too error prone. It was finally solved by a regex replacemet
that is run as a post process in generate_pyi.py .
The enumerations are now even more complete, since toplevel enums
are also included. This had the effect that enums with Python
keywords were revealed, and so the function "createEnumItem" had
to be modified.
The order of creation was also changed to avoid name clashes.
The overall structure was improved, and instead of parsing the
generated signatures to find out if something is a class method,
this is now very cleanly implemented as an inquiry to get_signature().
I tried to make sense of the flags structure that comes with many
enums. PyQt5 has a standard set of "__...__" methods without useful
signature information. I could mimick that as well, but that would
create a whole lot of pointless extra information. We should decide
later if it makes sense to include that. Right now the flags
structures show the class name, only.
This patch will be merged with the 5.14 branch. The additions of this
patch could fortunately be placed into areas which do almost not
overlap with the 5.14 signature additions.
Change-Id: Ie513e15917b04d746ab597fb7a9eb1fd766f7c73
Fixes: PYSIDE-1079
Reviewed-by: Cristian Maureira-Fredes <cristian.maureira-fredes@qt.io>
Diffstat (limited to 'sources/pyside2')
-rw-r--r-- | sources/pyside2/PySide2/support/generate_pyi.py | 73 |
1 files changed, 52 insertions, 21 deletions
diff --git a/sources/pyside2/PySide2/support/generate_pyi.py b/sources/pyside2/PySide2/support/generate_pyi.py index 8aa69c983..d5bbe5d7c 100644 --- a/sources/pyside2/PySide2/support/generate_pyi.py +++ b/sources/pyside2/PySide2/support/generate_pyi.py @@ -100,6 +100,38 @@ class Formatter(Writer): The separation in formatter and enumerator is done to keep the unrelated tasks of enumeration and formatting apart. """ + def __init__(self, *args): + Writer.__init__(self, *args) + # patching __repr__ to disable the __repr__ of typing.TypeVar: + """ + def __repr__(self): + if self.__covariant__: + prefix = '+' + elif self.__contravariant__: + prefix = '-' + else: + prefix = '~' + return prefix + self.__name__ + """ + def _typevar__repr__(self): + return "typing." + self.__name__ + typing.TypeVar.__repr__ = _typevar__repr__ + + # Adding a pattern to substitute "Union[T, NoneType]" by "Optional[T]" + # I tried hard to replace typing.Optional by a simple override, but + # this became _way_ too much. + # See also the comment in layout.py . + brace_pat = build_brace_pattern(3) + pattern = (r"\b Union \s* \[ \s* {brace_pat} \s*, \s* NoneType \s* \]" + .format(**locals())) + replace = r"Optional[\1]" + optional_searcher = re.compile(pattern, flags=re.VERBOSE) + def optional_replacer(source): + return optional_searcher.sub(replace, str(source)) + self.optional_replacer = optional_replacer + # self.level is maintained by enum_sig.py + # self.after_enum() is a one-shot set by enum_sig.py . + @contextmanager def module(self, mod_name): self.mod_name = mod_name @@ -121,26 +153,21 @@ class Formatter(Writer): @contextmanager def klass(self, class_name, class_str): - self.class_name = class_name - spaces = "" + spaces = indent * self.level while "." in class_name: - spaces += indent class_name = class_name.split(".", 1)[-1] class_str = class_str.split(".", 1)[-1] self.print() - if not spaces: + if self.level == 0: self.print() here = self.outfile.tell() self.print("{spaces}class {class_str}:".format(**locals())) - self.print() pos = self.outfile.tell() - self.spaces = spaces yield if pos == self.outfile.tell(): # we have not written any function self.outfile.seek(here) self.outfile.truncate() - # Note: we cannot use class_str when we have no body. self.print("{spaces}class {class_str}: ...".format(**locals())) if "<" in class_name: # This is happening in QtQuick for some reason: @@ -150,29 +177,32 @@ class Formatter(Writer): self.outfile.truncate() @contextmanager - def function(self, func_name, signature): + def function(self, func_name, signature, modifier=None): + if self.after_enum() or func_name == "__init__": + self.print() key = func_name - spaces = indent + self.spaces if self.class_name else "" + spaces = indent * self.level if type(signature) == type([]): for sig in signature: self.print('{spaces}@typing.overload'.format(**locals())) - self._function(func_name, sig, spaces) + self._function(func_name, sig, modifier, spaces) else: - self._function(func_name, signature, spaces) + self._function(func_name, signature, modifier, spaces) + if func_name == "__init__": + self.print() yield key - def _function(self, func_name, signature, spaces): - # this would be nicer to get somehow together with the signature - is_meth = re.match(r"\((\w*)", str(signature)).group(1) == "self" - if self.class_name and not is_meth: - self.print('{spaces}@staticmethod'.format(**locals())) + def _function(self, func_name, signature, modifier, spaces): + if modifier: + self.print('{spaces}@{modifier}'.format(**locals())) + signature = self.optional_replacer(signature) self.print('{spaces}def {func_name}{signature}: ...'.format(**locals())) @contextmanager def enum(self, class_name, enum_name, value): - spaces = self.spaces + spaces = indent * self.level hexval = hex(value) - self.print("{spaces}{enum_name:20}: {class_name} = ... # {hexval}".format(**locals())) + self.print("{spaces}{enum_name:25}: {class_name} = ... # {hexval}".format(**locals())) yield @@ -254,10 +284,11 @@ def generate_all_pyi(outpath, options): os.environ["PYTHONPATH"] = pypath # now we can import - global PySide2, inspect, HintingEnumerator, EnumType + global PySide2, inspect, typing, HintingEnumerator, build_brace_pattern import PySide2 - from PySide2.support.signature import inspect - from PySide2.support.signature.lib.enum_sig import HintingEnumerator, EnumType + from PySide2.support.signature import inspect, typing + from PySide2.support.signature.lib.enum_sig import HintingEnumerator + from PySide2.support.signature.lib.tool import build_brace_pattern # propagate USE_PEP563 to the mapping module. # Perhaps this can be automated? |