aboutsummaryrefslogtreecommitdiffstats
path: root/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/lib/enum_sig.py
diff options
context:
space:
mode:
Diffstat (limited to 'sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/lib/enum_sig.py')
-rw-r--r--sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/lib/enum_sig.py228
1 files changed, 153 insertions, 75 deletions
diff --git a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/lib/enum_sig.py b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/lib/enum_sig.py
index 400c36de5..5650e2bc1 100644
--- a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/lib/enum_sig.py
+++ b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/lib/enum_sig.py
@@ -1,41 +1,5 @@
-#############################################################################
-##
-## Copyright (C) 2020 The Qt Company Ltd.
-## Contact: https://www.qt.io/licensing/
-##
-## This file is part of Qt for Python.
-##
-## $QT_BEGIN_LICENSE:LGPL$
-## Commercial License Usage
-## Licensees holding valid commercial Qt licenses may use this file in
-## accordance with the commercial license agreement provided with the
-## Software or, alternatively, in accordance with the terms contained in
-## a written agreement between you and The Qt Company. For licensing terms
-## and conditions see https://www.qt.io/terms-conditions. For further
-## information use the contact form at https://www.qt.io/contact-us.
-##
-## GNU Lesser General Public License Usage
-## Alternatively, this file may be used under the terms of the GNU Lesser
-## General Public License version 3 as published by the Free Software
-## Foundation and appearing in the file LICENSE.LGPL3 included in the
-## packaging of this file. Please review the following information to
-## ensure the GNU Lesser General Public License version 3 requirements
-## will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-##
-## GNU General Public License Usage
-## Alternatively, this file may be used under the terms of the GNU
-## General Public License version 2.0 or (at your option) the GNU General
-## Public license version 3 or any later version approved by the KDE Free
-## Qt Foundation. The licenses are as published by the Free Software
-## Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-## included in the packaging of this file. Please review the following
-## information to ensure the GNU General Public License requirements will
-## be met: https://www.gnu.org/licenses/gpl-2.0.html and
-## https://www.gnu.org/licenses/gpl-3.0.html.
-##
-## $QT_END_LICENSE$
-##
-#############################################################################
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
"""
enum_sig.py
@@ -47,12 +11,35 @@ It is not easy to adhere to this protocol, but in the end, it paid off
by producing a lot of clarity.
"""
+import inspect
import sys
import types
-from shibokensupport.signature import inspect
from shibokensupport.signature import get_signature as get_sig
+"""
+PYSIDE-1599: Making sure that pyi files always are tested.
+
+A new problem popped up when supporting true properties:
+When there exists an item named "property", then we cannot use
+the builtin `property` as decorator, but need to prefix it with "builtins".
+
+We scan for such a name in a class, and if there should a property be
+declared in the same class, we use `builtins.property` in the class and
+all sub-classes. The same consideration holds for "overload".
+"""
+
+_normal_functions = (types.BuiltinFunctionType, types.FunctionType)
+if hasattr(sys, "pypy_version_info"):
+ # In PyPy, there are more types because our builtin functions
+ # are created differently in C++ and not in PyPy.
+ _normal_functions += (type(get_sig),)
+
+
+def signal_check(thing):
+ return thing and type(thing) in (Signal, SignalInstance)
+
+
class ExactEnumerator(object):
"""
ExactEnumerator enumerates all signatures in a module as they are.
@@ -63,20 +50,19 @@ class ExactEnumerator(object):
"""
def __init__(self, formatter, result_type=dict):
- global EnumMeta
+ global EnumMeta, Signal, SignalInstance
try:
# Lazy import
- from PySide6.QtCore import Qt
+ from PySide6.QtCore import Qt, Signal, SignalInstance
EnumMeta = type(Qt.Key)
except ImportError:
- EnumMeta = None
+ EnumMeta = Signal = SignalInstance = None
self.fmt = formatter
self.result_type = result_type
self.fmt.level = 0
- self.fmt.after_enum = self.after_enum
- self._after_enum = False
self.fmt.is_method = self.is_method
+ self.collision_candidates = {"property", "overload"}
def is_method(self):
"""
@@ -84,11 +70,11 @@ class ExactEnumerator(object):
We check if it is a simple function.
"""
tp = type(self.func)
- return tp not in (types.BuiltinFunctionType, types.FunctionType)
+ return tp not in _normal_functions
- def after_enum(self):
- ret = self._after_enum
- self._after_enum = False
+ def section(self):
+ if hasattr(self.fmt, "section"):
+ self.fmt.section()
def module(self, mod_name):
__import__(mod_name)
@@ -100,24 +86,31 @@ class ExactEnumerator(object):
ret = self.result_type()
self.fmt.class_name = None
for class_name, klass in members:
+ self.collision_track = set()
ret.update(self.klass(class_name, klass))
- if isinstance(klass, EnumMeta):
- raise SystemError("implement enum instances at module level")
+ if len(members):
+ self.section()
for func_name, func in functions:
ret.update(self.function(func_name, func))
+ if len(functions):
+ self.section()
return ret
def klass(self, class_name, klass):
ret = self.result_type()
+ if ("._") in class_name:
+ # This happens when introspecting enum.Enum etc. Python 3.8.8 does not
+ # like this, but we want to remove that, anyway.
+ return ret
if "<" in class_name:
# This is happening in QtQuick for some reason:
- ## class QSharedPointer<QQuickItemGrabResult >:
+ # class std::shared_ptr<QQuickItemGrabResult >:
# We simply skip over this class.
return ret
bases_list = []
for base in klass.__bases__:
- name = base.__name__
- if name not in ("object", "type"):
+ name = base.__qualname__
+ if name not in ("object", "property", "type"):
name = base.__module__ + "." + name
bases_list.append(name)
bases_str = ', '.join(bases_list)
@@ -128,60 +121,126 @@ class ExactEnumerator(object):
subclasses = []
functions = []
enums = []
+ properties = []
+ signals = []
+ attributes = {}
for thing_name, thing in class_members:
- if inspect.isclass(thing):
+ if signal_check(thing):
+ signals.append((thing_name, thing))
+ elif inspect.isclass(thing):
+ # If this is the only member of the class, it causes the stub
+ # to be printed empty without ..., as self.fmt.have_body will
+ # then be True. (Example: QtCore.QCborTag). Skip it to avoid
+ # this problem.
+ if thing_name == "_member_type_":
+ continue
subclass_name = ".".join((class_name, thing_name))
subclasses.append((subclass_name, thing))
elif inspect.isroutine(thing):
func_name = thing_name.split(".")[0] # remove ".overload"
- signature = getattr(thing, "__signature__", None)
- if signature is not None:
- functions.append((func_name, thing))
+ functions.append((func_name, thing))
elif type(type(thing)) is EnumMeta:
# take the real enum name, not what is in the dict
- enums.append((thing_name, type(thing).__qualname__, thing))
+ if not thing_name.startswith("_"):
+ enums.append((thing_name, type(thing).__qualname__, thing))
+ elif isinstance(thing, property):
+ properties.append((thing_name, thing))
+ # Support attributes that have PySide types as values,
+ # but we skip the 'staticMetaObject' that needs
+ # to be defined at a QObject level.
+ elif "PySide" in str(type(thing)) and "QMetaObject" not in str(type(thing)):
+ if class_name not in attributes:
+ attributes[class_name] = {}
+ attributes[class_name][thing_name] = thing
+
+ if thing_name in self.collision_candidates:
+ self.collision_track.add(thing_name)
+
init_signature = getattr(klass, "__signature__", None)
- enums.sort(key=lambda tup: tup[1 : 3]) # sort by class then enum value
- self.fmt.have_body = bool(subclasses or functions or enums or init_signature)
+ # sort by class then enum value
+ enums.sort(key=lambda tup: (tup[1], tup[2].value))
+
+ # We want to handle functions and properties together.
+ func_prop = sorted(functions + properties, key=lambda tup: tup[0])
+
+ # find out how many functions create a signature
+ sigs = list(_ for _ in functions if get_sig(_[1]))
+ self.fmt.have_body = bool(subclasses or sigs or properties or enums or # noqa W:504
+ init_signature or signals or attributes)
with self.fmt.klass(class_name, class_str):
self.fmt.level += 1
self.fmt.class_name = class_name
if hasattr(self.fmt, "enum"):
# this is an optional feature
+ if len(enums):
+ self.section()
for enum_name, enum_class_name, value in enums:
- with self.fmt.enum(enum_class_name, enum_name, int(value)):
+ with self.fmt.enum(enum_class_name, enum_name, value.value):
+ pass
+ if hasattr(self.fmt, "signal"):
+ # this is an optional feature
+ if len(signals):
+ self.section()
+ for signal_name, signal in signals:
+ sig_class = type(signal)
+ sig_class_name = f"{sig_class.__qualname__}"
+ sig_str = str(signal)
+ with self.fmt.signal(sig_class_name, signal_name, sig_str):
pass
+ if hasattr(self.fmt, "attribute"):
+ if len(attributes):
+ self.section()
+ for class_name, attrs in attributes.items():
+ for attr_name, attr_value in attrs.items():
+ with self.fmt.attribute(attr_name, attr_value):
+ pass
+ if len(subclasses):
+ self.section()
for subclass_name, subclass in subclasses:
- if klass == subclass:
- # this is a side effect of the typing module for Python 2.7
- # via the "._gorg" property, which we can safely ignore.
- print(f"Warning: {class_name} points to itself via {subclass_name}, skipped!")
- continue
+ save = self.collision_track.copy()
ret.update(self.klass(subclass_name, subclass))
+ self.collision_track = save
self.fmt.class_name = class_name
+ if len(subclasses):
+ self.section()
ret.update(self.function("__init__", klass))
- for func_name, func in functions:
+ for func_name, func in func_prop:
if func_name != "__init__":
- ret.update(self.function(func_name, func))
+ if isinstance(func, property):
+ ret.update(self.fproperty(func_name, func))
+ else:
+ ret.update(self.function(func_name, func))
self.fmt.level -= 1
+ if len(func_prop):
+ self.section()
return ret
@staticmethod
def get_signature(func):
- return func.__signature__
+ return get_sig(func)
- def function(self, func_name, func):
+ def function(self, func_name, func, decorator=None):
self.func = func # for is_method()
ret = self.result_type()
- signature = self.get_signature(func)
+ if decorator in self.collision_track:
+ decorator = f"builtins.{decorator}"
+ signature = self.get_signature(func, decorator)
if signature is not None:
- with self.fmt.function(func_name, signature) as key:
+ with self.fmt.function(func_name, signature, decorator) as key:
ret[key] = signature
del self.func
return ret
+ def fproperty(self, prop_name, prop):
+ ret = self.function(prop_name, prop.fget, type(prop).__qualname__)
+ if prop.fset:
+ ret.update(self.function(prop_name, prop.fset, f"{prop_name}.setter"))
+ if prop.fdel:
+ ret.update(self.function(prop_name, prop.fdel, f"{prop_name}.deleter"))
+ return ret
+
def stringify(signature):
if isinstance(signature, list):
@@ -221,6 +280,25 @@ class HintingEnumerator(ExactEnumerator):
hinting stubs. Only default values are replaced by "...".
"""
- @staticmethod
- def get_signature(func):
- return get_sig(func, "hintingstub")
+ def __init__(self, *args, **kwds):
+ super().__init__(*args, **kwds)
+ # We need to provide default signatures for class properties.
+ cls_param = inspect.Parameter("cls", inspect._POSITIONAL_OR_KEYWORD)
+ set_param = inspect.Parameter("arg_1", inspect._POSITIONAL_OR_KEYWORD, annotation=object)
+ self.getter_sig = inspect.Signature([cls_param], return_annotation=object)
+ self.setter_sig = inspect.Signature([cls_param, set_param])
+ self.deleter_sig = inspect.Signature([cls_param])
+
+ def get_signature(self, func, decorator=None):
+ # Class properties don't have signature support (yet).
+ # In that case, produce a fake one.
+ sig = get_sig(func, "hintingstub")
+ if not sig:
+ if decorator:
+ if decorator.endswith(".setter"):
+ sig = self.setter_sig
+ elif decorator.endswith(".deleter"):
+ sig = self.deleter_sig
+ else:
+ sig = self.getter_sig
+ return sig