aboutsummaryrefslogtreecommitdiffstats
path: root/sources/shiboken2/shibokenmodule
diff options
context:
space:
mode:
authorChristian Tismer <tismer@stackless.com>2018-07-14 15:10:56 +0200
committerChristian Tismer <tismer@stackless.com>2018-11-24 10:31:02 +0000
commitb92fb6e81be252a2ffae26768434028c5029ddc7 (patch)
tree88338bea02faff38ac986ba9d39c24d17670f795 /sources/shiboken2/shibokenmodule
parent4413f505ebcc39882ab7052488b37e38300b5219 (diff)
Split The Signature Module After The Project Split
The PySide project has been split into three pieces, including Shiboken. This had far-reaching consequences for the signature project. Shiboken can be run together with PySide or alone, with tests or without. In every configuration, the signature module has to work correctly. During tests, the shiboken binary also hides the shiboken module, and we had to use extra efforts to always guarantee the accessibility of all signature modules. This commit is the preparation for typeerrors implemented with the signature module. It has been split off because the splitting is not directly related, besides these unawaited consequences. I re-added and corrected voidptr_test and simplified the calls. Remark.. We should rename shiboken to Shiboken in all imports. I also simplified initialization. After "from PySide2 import QtCore", now a simple access like "type.__signature__" triggers initialization. Further, I removed all traces of "signature_loader" and allowed loading everything from PySide2.support.signature, again. The loader is now needed internally, only. Also, moved the type patching into FinishSignatureInitialization to support modules with no classes at all. The "testbinding" problem was finally identified as a name clash when the same function is also a signal. A further investigation showed that there exists also a regular PySide method with that problem. The test was extended to all methods, and it maps now all these cases to "{name}.overload". Updated the included typing27.py from https://pypi.org/project/typing/ from version 3.6.2 to version 3.6.6 . Task-number: PYSIDE-749 Change-Id: Ie33b8c6b0df5640212f8991539088593a041a05c Reviewed-by: Cristian Maureira-Fredes <cristian.maureira-fredes@qt.io>
Diffstat (limited to 'sources/shiboken2/shibokenmodule')
-rw-r--r--sources/shiboken2/shibokenmodule/CMakeLists.txt27
-rw-r--r--sources/shiboken2/shibokenmodule/support/__init__.py40
-rw-r--r--sources/shiboken2/shibokenmodule/support/signature/PSF-3.7.0.txt43
-rw-r--r--sources/shiboken2/shibokenmodule/support/signature/__init__.py44
-rw-r--r--sources/shiboken2/shibokenmodule/support/signature/backport_inspect.py956
-rw-r--r--sources/shiboken2/shibokenmodule/support/signature/fix-complaints.py91
-rw-r--r--sources/shiboken2/shibokenmodule/support/signature/layout.py245
-rw-r--r--sources/shiboken2/shibokenmodule/support/signature/lib/__init__.py40
-rw-r--r--sources/shiboken2/shibokenmodule/support/signature/lib/enum_sig.py135
-rw-r--r--sources/shiboken2/shibokenmodule/support/signature/loader.py176
-rw-r--r--sources/shiboken2/shibokenmodule/support/signature/mapping.py199
-rw-r--r--sources/shiboken2/shibokenmodule/support/signature/parser.py285
-rw-r--r--sources/shiboken2/shibokenmodule/support/signature/qt_attribution.json13
-rw-r--r--sources/shiboken2/shibokenmodule/support/signature/typing27.py2293
14 files changed, 4587 insertions, 0 deletions
diff --git a/sources/shiboken2/shibokenmodule/CMakeLists.txt b/sources/shiboken2/shibokenmodule/CMakeLists.txt
index 20baf9f7e..342b6d908 100644
--- a/sources/shiboken2/shibokenmodule/CMakeLists.txt
+++ b/sources/shiboken2/shibokenmodule/CMakeLists.txt
@@ -52,6 +52,33 @@ install(FILES "${CMAKE_CURRENT_BINARY_DIR}/_config.py"
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/__init__.py.in"
"${CMAKE_CURRENT_BINARY_DIR}/__init__.py" @ONLY)
+
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/support/__init__.py"
+ "${CMAKE_CURRENT_BINARY_DIR}/support/__init__.py" COPYONLY)
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/support/signature/__init__.py"
+ "${CMAKE_CURRENT_BINARY_DIR}/support/signature/__init__.py" COPYONLY)
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/support/signature/layout.py"
+ "${CMAKE_CURRENT_BINARY_DIR}/support/signature/layout.py" COPYONLY)
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/support/signature/loader.py"
+ "${CMAKE_CURRENT_BINARY_DIR}/support/signature/loader.py" COPYONLY)
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/support/signature/mapping.py"
+ "${CMAKE_CURRENT_BINARY_DIR}/support/signature/mapping.py" COPYONLY)
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/support/signature/parser.py"
+ "${CMAKE_CURRENT_BINARY_DIR}/support/signature/parser.py" COPYONLY)
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/support/signature/lib/__init__.py"
+ "${CMAKE_CURRENT_BINARY_DIR}/support/signature/lib/__init__.py" COPYONLY)
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/support/signature/lib/enum_sig.py"
+ "${CMAKE_CURRENT_BINARY_DIR}/support/signature/lib/enum_sig.py" COPYONLY)
+if (PYTHON_VERSION_MAJOR EQUAL 3)
+else()
+ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/support/signature/backport_inspect.py"
+ "${CMAKE_CURRENT_BINARY_DIR}/support/signature/backport_inspect.py" COPYONLY)
+ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/support/signature/typing27.py"
+ "${CMAKE_CURRENT_BINARY_DIR}/support/signature/typing.py" COPYONLY)
+endif()
+install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/support"
+ DESTINATION "${PYTHON_SITE_PACKAGES}/shiboken2")
+
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/__init__.py"
DESTINATION "${PYTHON_SITE_PACKAGES}/shiboken2")
diff --git a/sources/shiboken2/shibokenmodule/support/__init__.py b/sources/shiboken2/shibokenmodule/support/__init__.py
new file mode 100644
index 000000000..760d89571
--- /dev/null
+++ b/sources/shiboken2/shibokenmodule/support/__init__.py
@@ -0,0 +1,40 @@
+#############################################################################
+##
+## Copyright (C) 2017 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$
+##
+#############################################################################
+
+# this file intentionally left blank
diff --git a/sources/shiboken2/shibokenmodule/support/signature/PSF-3.7.0.txt b/sources/shiboken2/shibokenmodule/support/signature/PSF-3.7.0.txt
new file mode 100644
index 000000000..be42010dd
--- /dev/null
+++ b/sources/shiboken2/shibokenmodule/support/signature/PSF-3.7.0.txt
@@ -0,0 +1,43 @@
+PSF LICENSE AGREEMENT FOR PYTHON 3.7.0
+
+1. This LICENSE AGREEMENT is between the Python Software Foundation ("PSF"), and
+ the Individual or Organization ("Licensee") accessing and otherwise using Python
+ 3.7.0 software in source or binary form and its associated documentation.
+
+2. Subject to the terms and conditions of this License Agreement, PSF hereby
+ grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce,
+ analyze, test, perform and/or display publicly, prepare derivative works,
+ distribute, and otherwise use Python 3.7.0 alone or in any derivative
+ version, provided, however, that PSF's License Agreement and PSF's notice of
+ copyright, i.e., "Copyright © 2001-2018 Python Software Foundation; All Rights
+ Reserved" are retained in Python 3.7.0 alone or in any derivative version
+ prepared by Licensee.
+
+3. In the event Licensee prepares a derivative work that is based on or
+ incorporates Python 3.7.0 or any part thereof, and wants to make the
+ derivative work available to others as provided herein, then Licensee hereby
+ agrees to include in any such work a brief summary of the changes made to Python
+ 3.7.0.
+
+4. PSF is making Python 3.7.0 available to Licensee on an "AS IS" basis.
+ PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF
+ EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND DISCLAIMS ANY REPRESENTATION OR
+ WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE
+ USE OF PYTHON 3.7.0 WILL NOT INFRINGE ANY THIRD PARTY RIGHTS.
+
+5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON 3.7.0
+ FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF
+ MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 3.7.0, OR ANY DERIVATIVE
+ THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
+
+6. This License Agreement will automatically terminate upon a material breach of
+ its terms and conditions.
+
+7. Nothing in this License Agreement shall be deemed to create any relationship
+ of agency, partnership, or joint venture between PSF and Licensee. This License
+ Agreement does not grant permission to use PSF trademarks or trade name in a
+ trademark sense to endorse or promote products or services of Licensee, or any
+ third party.
+
+8. By copying, installing or otherwise using Python 3.7.0, Licensee agrees
+ to be bound by the terms and conditions of this License Agreement.
diff --git a/sources/shiboken2/shibokenmodule/support/signature/__init__.py b/sources/shiboken2/shibokenmodule/support/signature/__init__.py
new file mode 100644
index 000000000..f639f1ad0
--- /dev/null
+++ b/sources/shiboken2/shibokenmodule/support/signature/__init__.py
@@ -0,0 +1,44 @@
+#############################################################################
+##
+## Copyright (C) 2018 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$
+##
+#############################################################################
+
+from __future__ import print_function, absolute_import
+
+# Trigger initialization phase 2.
+_ = type.__signature__
+from signature_loader import get_signature, inspect
diff --git a/sources/shiboken2/shibokenmodule/support/signature/backport_inspect.py b/sources/shiboken2/shibokenmodule/support/signature/backport_inspect.py
new file mode 100644
index 000000000..0eafe9caa
--- /dev/null
+++ b/sources/shiboken2/shibokenmodule/support/signature/backport_inspect.py
@@ -0,0 +1,956 @@
+# This Python file uses the following encoding: utf-8
+# It has been edited by fix-complaints.py .
+
+#############################################################################
+##
+## Copyright (C) 2018 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$
+##
+#############################################################################
+
+from __future__ import print_function
+
+"""
+PSF LICENSE AGREEMENT FOR PYTHON 3.7.0
+
+1. This LICENSE AGREEMENT is between the Python Software Foundation ("PSF"), and
+ the Individual or Organization ("Licensee") accessing and otherwise using Python
+ 3.7.0 software in source or binary form and its associated documentation.
+
+2. Subject to the terms and conditions of this License Agreement, PSF hereby
+ grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce,
+ analyze, test, perform and/or display publicly, prepare derivative works,
+ distribute, and otherwise use Python 3.7.0 alone or in any derivative
+ version, provided, however, that PSF's License Agreement and PSF's notice of
+ copyright, i.e., "Copyright © 2001-2018 Python Software Foundation; All Rights
+ Reserved" are retained in Python 3.7.0 alone or in any derivative version
+ prepared by Licensee.
+
+3. In the event Licensee prepares a derivative work that is based on or
+ incorporates Python 3.7.0 or any part thereof, and wants to make the
+ derivative work available to others as provided herein, then Licensee hereby
+ agrees to include in any such work a brief summary of the changes made to Python
+ 3.7.0.
+
+4. PSF is making Python 3.7.0 available to Licensee on an "AS IS" basis.
+ PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF
+ EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND DISCLAIMS ANY REPRESENTATION OR
+ WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE
+ USE OF PYTHON 3.7.0 WILL NOT INFRINGE ANY THIRD PARTY RIGHTS.
+
+5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON 3.7.0
+ FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF
+ MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 3.7.0, OR ANY DERIVATIVE
+ THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
+
+6. This License Agreement will automatically terminate upon a material breach of
+ its terms and conditions.
+
+7. Nothing in this License Agreement shall be deemed to create any relationship
+ of agency, partnership, or joint venture between PSF and Licensee. This License
+ Agreement does not grant permission to use PSF trademarks or trade name in a
+ trademark sense to endorse or promote products or services of Licensee, or any
+ third party.
+
+8. By copying, installing or otherwise using Python 3.7.0, Licensee agrees
+ to be bound by the terms and conditions of this License Agreement.
+"""
+
+__doc__ = """
+ signature() - get a Signature object for the callable
+"""
+
+import sys
+from collections import OrderedDict
+
+CO_OPTIMIZED = 0x0001
+CO_NEWLOCALS = 0x0002
+CO_VARARGS = 0x0004
+CO_VARKEYWORDS = 0x0008
+CO_NESTED = 0x0010
+CO_GENERATOR = 0x0020
+CO_NOFREE = 0x0040
+
+
+###############################################################################
+### Function Signature Object (PEP 362)
+###############################################################################
+
+
+# This function was changed: 'builtins' and 'qualname' don't exist.
+# We use '__builtin__' and '__name__' instead.
+# It is further changed because we use a local copy of typing
+def formatannotation(annotation, base_module=None):
+ if getattr(annotation, '__module__', None) == 'PySide2.support.signature.typing':
+ return repr(annotation).replace('PySide2.support.signature.typing.', '')
+ if isinstance(annotation, type):
+ if annotation.__module__ in ('__builtin__', base_module):
+ return annotation.__name__
+ return annotation.__module__+'.'+annotation.__name__
+ return repr(annotation)
+
+
+def _signature_is_functionlike(obj):
+ """Private helper to test if `obj` is a duck type of FunctionType.
+ A good example of such objects are functions compiled with
+ Cython, which have all attributes that a pure Python function
+ would have, but have their code statically compiled.
+ """
+
+ if not callable(obj) or isclass(obj):
+ # All function-like objects are obviously callables,
+ # and not classes.
+ return False
+
+ name = getattr(obj, '__name__', None)
+ code = getattr(obj, '__code__', None)
+ defaults = getattr(obj, '__defaults__', _void) # Important to use _void ...
+ kwdefaults = getattr(obj, '__kwdefaults__', _void) # ... and not None here
+ annotations = getattr(obj, '__annotations__', None)
+
+ return (isinstance(code, types.CodeType) and
+ isinstance(name, str) and
+ (defaults is None or isinstance(defaults, tuple)) and
+ (kwdefaults is None or isinstance(kwdefaults, dict)) and
+ isinstance(annotations, dict))
+
+
+
+def _signature_from_function(cls, func):
+ """Private helper: constructs Signature for the given python function."""
+
+ is_duck_function = False
+ if not isfunction(func):
+ if _signature_is_functionlike(func):
+ is_duck_function = True
+ else:
+ # If it's not a pure Python function, and not a duck type
+ # of pure function:
+ raise TypeError('{!r} is not a Python function'.format(func))
+
+ Parameter = cls._parameter_cls
+
+ # Parameter information.
+ func_code = func.__code__
+ pos_count = func_code.co_argcount
+ arg_names = func_code.co_varnames
+ positional = tuple(arg_names[:pos_count])
+ keyword_only_count = 0 # func_code.co_kwonlyargcount
+ keyword_only = arg_names[pos_count:(pos_count + keyword_only_count)]
+ annotations = func.__annotations__
+ defaults = func.__defaults__
+ kwdefaults = func.__kwdefaults__
+
+ if defaults:
+ pos_default_count = len(defaults)
+ else:
+ pos_default_count = 0
+
+ parameters = []
+
+ # Non-keyword-only parameters w/o defaults.
+ non_default_count = pos_count - pos_default_count
+ for name in positional[:non_default_count]:
+ annotation = annotations.get(name, _empty)
+ parameters.append(Parameter(name, annotation=annotation,
+ kind=_POSITIONAL_OR_KEYWORD))
+
+ # ... w/ defaults.
+ for offset, name in enumerate(positional[non_default_count:]):
+ annotation = annotations.get(name, _empty)
+ parameters.append(Parameter(name, annotation=annotation,
+ kind=_POSITIONAL_OR_KEYWORD,
+ default=defaults[offset]))
+
+ # *args
+ if func_code.co_flags & CO_VARARGS:
+ name = arg_names[pos_count + keyword_only_count]
+ annotation = annotations.get(name, _empty)
+ parameters.append(Parameter(name, annotation=annotation,
+ kind=_VAR_POSITIONAL))
+
+ # Keyword-only parameters.
+ for name in keyword_only:
+ default = _empty
+ if kwdefaults is not None:
+ default = kwdefaults.get(name, _empty)
+
+ annotation = annotations.get(name, _empty)
+ parameters.append(Parameter(name, annotation=annotation,
+ kind=_KEYWORD_ONLY,
+ default=default))
+ # **kwargs
+ if func_code.co_flags & CO_VARKEYWORDS:
+ index = pos_count + keyword_only_count
+ if func_code.co_flags & CO_VARARGS:
+ index += 1
+
+ name = arg_names[index]
+ annotation = annotations.get(name, _empty)
+ parameters.append(Parameter(name, annotation=annotation,
+ kind=_VAR_KEYWORD))
+
+ # Is 'func' is a pure Python function - don't validate the
+ # parameters list (for correct order and defaults), it should be OK.
+ return cls(parameters,
+ return_annotation=annotations.get('return', _empty),
+ __validate_parameters__=is_duck_function)
+
+
+
+
+class _void(object):
+ """A private marker - used in Parameter & Signature."""
+
+
+class _empty(object):
+ """Marker object for Signature.empty and Parameter.empty."""
+
+
+class _ParameterKind(object): # (enum.IntEnum):
+ POSITIONAL_ONLY = 0
+ POSITIONAL_OR_KEYWORD = 1
+ VAR_POSITIONAL = 2
+ KEYWORD_ONLY = 3
+ VAR_KEYWORD = 4
+
+ def __str__(self):
+ return self._name_
+
+
+_POSITIONAL_ONLY = _ParameterKind.POSITIONAL_ONLY
+_POSITIONAL_OR_KEYWORD = _ParameterKind.POSITIONAL_OR_KEYWORD
+_VAR_POSITIONAL = _ParameterKind.VAR_POSITIONAL
+_KEYWORD_ONLY = _ParameterKind.KEYWORD_ONLY
+_VAR_KEYWORD = _ParameterKind.VAR_KEYWORD
+
+
+class Parameter(object):
+ """Represents a parameter in a function signature.
+
+ Has the following public attributes:
+
+ * name : str
+ The name of the parameter as a string.
+ * default : object
+ The default value for the parameter if specified. If the
+ parameter has no default value, this attribute is set to
+ `Parameter.empty`.
+ * annotation
+ The annotation for the parameter if specified. If the
+ parameter has no annotation, this attribute is set to
+ `Parameter.empty`.
+ * kind : str
+ Describes how argument values are bound to the parameter.
+ Possible values: `Parameter.POSITIONAL_ONLY`,
+ `Parameter.POSITIONAL_OR_KEYWORD`, `Parameter.VAR_POSITIONAL`,
+ `Parameter.KEYWORD_ONLY`, `Parameter.VAR_KEYWORD`.
+ """
+
+ __slots__ = ('_name', '_kind', '_default', '_annotation')
+
+ POSITIONAL_ONLY = _POSITIONAL_ONLY
+ POSITIONAL_OR_KEYWORD = _POSITIONAL_OR_KEYWORD
+ VAR_POSITIONAL = _VAR_POSITIONAL
+ KEYWORD_ONLY = _KEYWORD_ONLY
+ VAR_KEYWORD = _VAR_KEYWORD
+
+ empty = _empty
+
+ def __init__(self, name, kind, default=_empty, annotation=_empty):
+
+ if kind not in (_POSITIONAL_ONLY, _POSITIONAL_OR_KEYWORD,
+ _VAR_POSITIONAL, _KEYWORD_ONLY, _VAR_KEYWORD):
+ raise ValueError("invalid value for 'Parameter.kind' attribute")
+ self._kind = kind
+
+ if default is not _empty:
+ if kind in (_VAR_POSITIONAL, _VAR_KEYWORD):
+ msg = '{} parameters cannot have default values'.format(kind)
+ raise ValueError(msg)
+ self._default = default
+ self._annotation = annotation
+
+ if name is _empty:
+ raise ValueError('name is a required attribute for Parameter')
+
+ if not isinstance(name, str):
+ raise TypeError("name must be a str, not a {!r}".format(name))
+
+ if name[0] == '.' and name[1:].isdigit():
+ # These are implicit arguments generated by comprehensions. In
+ # order to provide a friendlier interface to users, we recast
+ # their name as "implicitN" and treat them as positional-only.
+ # See issue 19611.
+ if kind != _POSITIONAL_OR_KEYWORD:
+ raise ValueError(
+ 'implicit arguments must be passed in as {}'.format(
+ _POSITIONAL_OR_KEYWORD
+ )
+ )
+ self._kind = _POSITIONAL_ONLY
+ name = 'implicit{}'.format(name[1:])
+
+ if not True: # name.isidentifier():
+ raise ValueError('{!r} is not a valid parameter name'.format(name))
+
+ self._name = name
+
+ def __reduce__(self):
+ return (type(self),
+ (self._name, self._kind),
+ {'_default': self._default,
+ '_annotation': self._annotation})
+
+ def __setstate__(self, state):
+ self._default = state['_default']
+ self._annotation = state['_annotation']
+
+ @property
+ def name(self):
+ return self._name
+
+ @property
+ def default(self):
+ return self._default
+
+ @property
+ def annotation(self):
+ return self._annotation
+
+ @property
+ def kind(self):
+ return self._kind
+
+ def replace(self, name=_void, kind=_void,
+ annotation=_void, default=_void):
+ """Creates a customized copy of the Parameter."""
+
+ if name is _void:
+ name = self._name
+
+ if kind is _void:
+ kind = self._kind
+
+ if annotation is _void:
+ annotation = self._annotation
+
+ if default is _void:
+ default = self._default
+
+ return type(self)(name, kind, default=default, annotation=annotation)
+
+ def __str__(self):
+ kind = self.kind
+ formatted = self._name
+
+ # Add annotation and default value
+ if self._annotation is not _empty:
+ formatted = '{}:{}'.format(formatted,
+ formatannotation(self._annotation))
+
+ if self._default is not _empty:
+ formatted = '{}={}'.format(formatted, repr(self._default))
+
+ if kind == _VAR_POSITIONAL:
+ formatted = '*' + formatted
+ elif kind == _VAR_KEYWORD:
+ formatted = '**' + formatted
+
+ return formatted
+
+ def __repr__(self):
+ return '<{} "{}">'.format(self.__class__.__name__, self)
+
+ def __hash__(self):
+ return hash((self.name, self.kind, self.annotation, self.default))
+
+ def __eq__(self, other):
+ if self is other:
+ return True
+ if not isinstance(other, Parameter):
+ return NotImplemented
+ return (self._name == other._name and
+ self._kind == other._kind and
+ self._default == other._default and
+ self._annotation == other._annotation)
+
+
+class BoundArguments(object):
+ """Result of `Signature.bind` call. Holds the mapping of arguments
+ to the function's parameters.
+
+ Has the following public attributes:
+
+ * arguments : OrderedDict
+ An ordered mutable mapping of parameters' names to arguments' values.
+ Does not contain arguments' default values.
+ * signature : Signature
+ The Signature object that created this instance.
+ * args : tuple
+ Tuple of positional arguments values.
+ * kwargs : dict
+ Dict of keyword arguments values.
+ """
+
+ __slots__ = ('arguments', '_signature', '__weakref__')
+
+ def __init__(self, signature, arguments):
+ self.arguments = arguments
+ self._signature = signature
+
+ @property
+ def signature(self):
+ return self._signature
+
+ @property
+ def args(self):
+ args = []
+ for param_name, param in self._signature.parameters.items():
+ if param.kind in (_VAR_KEYWORD, _KEYWORD_ONLY):
+ break
+
+ try:
+ arg = self.arguments[param_name]
+ except KeyError:
+ # We're done here. Other arguments
+ # will be mapped in 'BoundArguments.kwargs'
+ break
+ else:
+ if param.kind == _VAR_POSITIONAL:
+ # *args
+ args.extend(arg)
+ else:
+ # plain argument
+ args.append(arg)
+
+ return tuple(args)
+
+ @property
+ def kwargs(self):
+ kwargs = {}
+ kwargs_started = False
+ for param_name, param in self._signature.parameters.items():
+ if not kwargs_started:
+ if param.kind in (_VAR_KEYWORD, _KEYWORD_ONLY):
+ kwargs_started = True
+ else:
+ if param_name not in self.arguments:
+ kwargs_started = True
+ continue
+
+ if not kwargs_started:
+ continue
+
+ try:
+ arg = self.arguments[param_name]
+ except KeyError:
+ pass
+ else:
+ if param.kind == _VAR_KEYWORD:
+ # **kwargs
+ kwargs.update(arg)
+ else:
+ # plain keyword argument
+ kwargs[param_name] = arg
+
+ return kwargs
+
+ def apply_defaults(self):
+ """Set default values for missing arguments.
+
+ For variable-positional arguments (*args) the default is an
+ empty tuple.
+
+ For variable-keyword arguments (**kwargs) the default is an
+ empty dict.
+ """
+ arguments = self.arguments
+ new_arguments = []
+ for name, param in self._signature.parameters.items():
+ try:
+ new_arguments.append((name, arguments[name]))
+ except KeyError:
+ if param.default is not _empty:
+ val = param.default
+ elif param.kind is _VAR_POSITIONAL:
+ val = ()
+ elif param.kind is _VAR_KEYWORD:
+ val = {}
+ else:
+ # This BoundArguments was likely produced by
+ # Signature.bind_partial().
+ continue
+ new_arguments.append((name, val))
+ self.arguments = OrderedDict(new_arguments)
+
+ def __eq__(self, other):
+ if self is other:
+ return True
+ if not isinstance(other, BoundArguments):
+ return NotImplemented
+ return (self.signature == other.signature and
+ self.arguments == other.arguments)
+
+ def __setstate__(self, state):
+ self._signature = state['_signature']
+ self.arguments = state['arguments']
+
+ def __getstate__(self):
+ return {'_signature': self._signature, 'arguments': self.arguments}
+
+ def __repr__(self):
+ args = []
+ for arg, value in self.arguments.items():
+ args.append('{}={!r}'.format(arg, value))
+ return '<{} ({})>'.format(self.__class__.__name__, ', '.join(args))
+
+
+class Signature(object):
+ """A Signature object represents the overall signature of a function.
+ It stores a Parameter object for each parameter accepted by the
+ function, as well as information specific to the function itself.
+
+ A Signature object has the following public attributes and methods:
+
+ * parameters : OrderedDict
+ An ordered mapping of parameters' names to the corresponding
+ Parameter objects (keyword-only arguments are in the same order
+ as listed in `code.co_varnames`).
+ * return_annotation : object
+ The annotation for the return type of the function if specified.
+ If the function has no annotation for its return type, this
+ attribute is set to `Signature.empty`.
+ * bind(*args, **kwargs) -> BoundArguments
+ Creates a mapping from positional and keyword arguments to
+ parameters.
+ * bind_partial(*args, **kwargs) -> BoundArguments
+ Creates a partial mapping from positional and keyword arguments
+ to parameters (simulating 'functools.partial' behavior.)
+ """
+
+ __slots__ = ('_return_annotation', '_parameters')
+
+ _parameter_cls = Parameter
+ _bound_arguments_cls = BoundArguments
+
+ empty = _empty
+
+ def __init__(self, parameters=None, return_annotation=_empty,
+ __validate_parameters__=True):
+ """Constructs Signature from the given list of Parameter
+ objects and 'return_annotation'. All arguments are optional.
+ """
+
+ if parameters is None:
+ params = OrderedDict()
+ else:
+ if __validate_parameters__:
+ params = OrderedDict()
+ top_kind = _POSITIONAL_ONLY
+ kind_defaults = False
+
+ for idx, param in enumerate(parameters):
+ kind = param.kind
+ name = param.name
+
+ if kind < top_kind:
+ msg = 'wrong parameter order: {!r} before {!r}'
+ msg = msg.format(top_kind, kind)
+ raise ValueError(msg)
+ elif kind > top_kind:
+ kind_defaults = False
+ top_kind = kind
+
+ if kind in (_POSITIONAL_ONLY, _POSITIONAL_OR_KEYWORD):
+ if param.default is _empty:
+ if kind_defaults:
+ # No default for this parameter, but the
+ # previous parameter of the same kind had
+ # a default
+ msg = 'non-default argument follows default ' \
+ 'argument'
+ raise ValueError(msg)
+ else:
+ # There is a default for this parameter.
+ kind_defaults = True
+
+ if name in params:
+ msg = 'duplicate parameter name: {!r}'.format(name)
+ raise ValueError(msg)
+
+ params[name] = param
+ else:
+ params = OrderedDict(((param.name, param)
+ for param in parameters))
+
+ self._parameters = params # types.MappingProxyType(params)
+ self._return_annotation = return_annotation
+
+ @classmethod
+ def from_function(cls, func):
+ """Constructs Signature for the given python function."""
+
+ warnings.warn("inspect.Signature.from_function() is deprecated, "
+ "use Signature.from_callable()",
+ DeprecationWarning, stacklevel=2)
+ return _signature_from_function(cls, func)
+
+ @classmethod
+ def from_builtin(cls, func):
+ """Constructs Signature for the given builtin function."""
+
+ warnings.warn("inspect.Signature.from_builtin() is deprecated, "
+ "use Signature.from_callable()",
+ DeprecationWarning, stacklevel=2)
+ return _signature_from_builtin(cls, func)
+
+ @classmethod
+ def from_callable(cls, obj, follow_wrapped=True):
+ """Constructs Signature for the given callable object."""
+ return _signature_from_callable(obj, sigcls=cls,
+ follow_wrapper_chains=follow_wrapped)
+
+ @property
+ def parameters(self):
+ return self._parameters
+
+ @property
+ def return_annotation(self):
+ return self._return_annotation
+
+ def replace(self, parameters=_void, return_annotation=_void):
+ """Creates a customized copy of the Signature.
+ Pass 'parameters' and/or 'return_annotation' arguments
+ to override them in the new copy.
+ """
+
+ if parameters is _void:
+ parameters = self.parameters.values()
+
+ if return_annotation is _void:
+ return_annotation = self._return_annotation
+
+ return type(self)(parameters,
+ return_annotation=return_annotation)
+
+ def _hash_basis(self):
+ params = tuple(param for param in self.parameters.values()
+ if param.kind != _KEYWORD_ONLY)
+
+ kwo_params = {param.name: param for param in self.parameters.values()
+ if param.kind == _KEYWORD_ONLY}
+
+ return params, kwo_params, self.return_annotation
+
+ def __hash__(self):
+ params, kwo_params, return_annotation = self._hash_basis()
+ kwo_params = frozenset(kwo_params.values())
+ return hash((params, kwo_params, return_annotation))
+
+ def __eq__(self, other):
+ if self is other:
+ return True
+ if not isinstance(other, Signature):
+ return NotImplemented
+ return self._hash_basis() == other._hash_basis()
+
+ def _bind(self, args, kwargs, partial=False):
+ """Private method. Don't use directly."""
+
+ arguments = OrderedDict()
+
+ parameters = iter(self.parameters.values())
+ parameters_ex = ()
+ arg_vals = iter(args)
+
+ while True:
+ # Let's iterate through the positional arguments and corresponding
+ # parameters
+ try:
+ arg_val = next(arg_vals)
+ except StopIteration:
+ # No more positional arguments
+ try:
+ param = next(parameters)
+ except StopIteration:
+ # No more parameters. That's it. Just need to check that
+ # we have no `kwargs` after this while loop
+ break
+ else:
+ if param.kind == _VAR_POSITIONAL:
+ # That's OK, just empty *args. Let's start parsing
+ # kwargs
+ break
+ elif param.name in kwargs:
+ if param.kind == _POSITIONAL_ONLY:
+ msg = '{arg!r} parameter is positional only, ' \
+ 'but was passed as a keyword'
+ msg = msg.format(arg=param.name)
+ raise TypeError(msg)# from None
+ parameters_ex = (param,)
+ break
+ elif (param.kind == _VAR_KEYWORD or
+ param.default is not _empty):
+ # That's fine too - we have a default value for this
+ # parameter. So, lets start parsing `kwargs`, starting
+ # with the current parameter
+ parameters_ex = (param,)
+ break
+ else:
+ # No default, not VAR_KEYWORD, not VAR_POSITIONAL,
+ # not in `kwargs`
+ if partial:
+ parameters_ex = (param,)
+ break
+ else:
+ msg = 'missing a required argument: {arg!r}'
+ msg = msg.format(arg=param.name)
+ raise TypeError(msg)# from None
+ else:
+ # We have a positional argument to process
+ try:
+ param = next(parameters)
+ except StopIteration:
+ raise TypeError('too many positional arguments')# from None
+ else:
+ if param.kind in (_VAR_KEYWORD, _KEYWORD_ONLY):
+ # Looks like we have no parameter for this positional
+ # argument
+ raise TypeError(
+ 'too many positional arguments')# from None
+
+ if param.kind == _VAR_POSITIONAL:
+ # We have an '*args'-like argument, let's fill it with
+ # all positional arguments we have left and move on to
+ # the next phase
+ values = [arg_val]
+ values.extend(arg_vals)
+ arguments[param.name] = tuple(values)
+ break
+
+ if param.name in kwargs:
+ raise TypeError(
+ 'multiple values for argument {arg!r}'.format(
+ arg=param.name))# from None
+
+ arguments[param.name] = arg_val
+
+ # Now, we iterate through the remaining parameters to process
+ # keyword arguments
+ kwargs_param = None
+ for param in itertools.chain(parameters_ex, parameters):
+ if param.kind == _VAR_KEYWORD:
+ # Memorize that we have a '**kwargs'-like parameter
+ kwargs_param = param
+ continue
+
+ if param.kind == _VAR_POSITIONAL:
+ # Named arguments don't refer to '*args'-like parameters.
+ # We only arrive here if the positional arguments ended
+ # before reaching the last parameter before *args.
+ continue
+
+ param_name = param.name
+ try:
+ arg_val = kwargs.pop(param_name)
+ except KeyError:
+ # We have no value for this parameter. It's fine though,
+ # if it has a default value, or it is an '*args'-like
+ # parameter, left alone by the processing of positional
+ # arguments.
+ if (not partial and param.kind != _VAR_POSITIONAL and
+ param.default is _empty):
+ raise TypeError('missing a required argument: {arg!r}'. \
+ format(arg=param_name))# from None
+
+ else:
+ if param.kind == _POSITIONAL_ONLY:
+ # This should never happen in case of a properly built
+ # Signature object (but let's have this check here
+ # to ensure correct behavior just in case)
+ raise TypeError('{arg!r} parameter is positional only, '
+ 'but was passed as a keyword'. \
+ format(arg=param.name))
+
+ arguments[param_name] = arg_val
+
+ if kwargs:
+ if kwargs_param is not None:
+ # Process our '**kwargs'-like parameter
+ arguments[kwargs_param.name] = kwargs
+ else:
+ raise TypeError(
+ 'got an unexpected keyword argument {arg!r}'.format(
+ arg=next(iter(kwargs))))
+
+ return self._bound_arguments_cls(self, arguments)
+
+ def bind(*args, **kwargs):
+ """Get a BoundArguments object, that maps the passed `args`
+ and `kwargs` to the function's signature. Raises `TypeError`
+ if the passed arguments can not be bound.
+ """
+ return args[0]._bind(args[1:], kwargs)
+
+ def bind_partial(*args, **kwargs):
+ """Get a BoundArguments object, that partially maps the
+ passed `args` and `kwargs` to the function's signature.
+ Raises `TypeError` if the passed arguments can not be bound.
+ """
+ return args[0]._bind(args[1:], kwargs, partial=True)
+
+ def __reduce__(self):
+ return (type(self),
+ (tuple(self._parameters.values()),),
+ {'_return_annotation': self._return_annotation})
+
+ def __setstate__(self, state):
+ self._return_annotation = state['_return_annotation']
+
+ def __repr__(self):
+ return '<{} {}>'.format(self.__class__.__name__, self)
+
+ def __str__(self):
+ result = []
+ render_pos_only_separator = False
+ render_kw_only_separator = True
+ for param in self.parameters.values():
+ formatted = str(param)
+
+ kind = param.kind
+
+ if kind == _POSITIONAL_ONLY:
+ render_pos_only_separator = True
+ elif render_pos_only_separator:
+ # It's not a positional-only parameter, and the flag
+ # is set to 'True' (there were pos-only params before.)
+ result.append('/')
+ render_pos_only_separator = False
+
+ if kind == _VAR_POSITIONAL:
+ # OK, we have an '*args'-like parameter, so we won't need
+ # a '*' to separate keyword-only arguments
+ render_kw_only_separator = False
+ elif kind == _KEYWORD_ONLY and render_kw_only_separator:
+ # We have a keyword-only parameter to render and we haven't
+ # rendered an '*args'-like parameter before, so add a '*'
+ # separator to the parameters list ("foo(arg1, *, arg2)" case)
+ result.append('*')
+ # This condition should be only triggered once, so
+ # reset the flag
+ render_kw_only_separator = False
+
+ result.append(formatted)
+
+ if render_pos_only_separator:
+ # There were only positional-only parameters, hence the
+ # flag was not reset to 'False'
+ result.append('/')
+
+ rendered = '({})'.format(', '.join(result))
+
+ if self.return_annotation is not _empty:
+ anno = formatannotation(self.return_annotation)
+ rendered += ' -> {}'.format(anno)
+
+ return rendered
+
+
+def signature(obj, follow_wrapped=True):
+ """Get a signature object for the passed callable."""
+ return Signature.from_callable(obj, follow_wrapped=follow_wrapped)
+
+
+def _main():
+ """ Logic for inspecting an object given at command line """
+ import argparse
+ import importlib
+
+ parser = argparse.ArgumentParser()
+ parser.add_argument(
+ 'object',
+ help="The object to be analysed. "
+ "It supports the 'module:qualname' syntax")
+ parser.add_argument(
+ '-d', '--details', action='store_true',
+ help='Display info about the module rather than its source code')
+
+ args = parser.parse_args()
+
+ target = args.object
+ mod_name, has_attrs, attrs = target.partition(":")
+ try:
+ obj = module = importlib.import_module(mod_name)
+ except Exception as exc:
+ msg = "Failed to import {} ({}: {})".format(mod_name,
+ type(exc).__name__,
+ exc)
+ print(msg, file=sys.stderr)
+ exit(2)
+
+ if has_attrs:
+ parts = attrs.split(".")
+ obj = module
+ for part in parts:
+ obj = getattr(obj, part)
+
+ if module.__name__ in sys.builtin_module_names:
+ print("Can't get info for builtin modules.", file=sys.stderr)
+ exit(1)
+
+ if args.details:
+ print('Target: {}'.format(target))
+ print('Origin: {}'.format(getsourcefile(module)))
+ print('Cached: {}'.format(module.__cached__))
+ if obj is module:
+ print('Loader: {}'.format(repr(module.__loader__)))
+ if hasattr(module, '__path__'):
+ print('Submodule search path: {}'.format(module.__path__))
+ else:
+ try:
+ __, lineno = findsource(obj)
+ except Exception:
+ pass
+ else:
+ print('Line: {}'.format(lineno))
+
+ print('\n')
+ else:
+ print(getsource(obj))
+
+
+if __name__ == "__main__":
+ _main()
diff --git a/sources/shiboken2/shibokenmodule/support/signature/fix-complaints.py b/sources/shiboken2/shibokenmodule/support/signature/fix-complaints.py
new file mode 100644
index 000000000..e078ef1ab
--- /dev/null
+++ b/sources/shiboken2/shibokenmodule/support/signature/fix-complaints.py
@@ -0,0 +1,91 @@
+#############################################################################
+##
+## Copyright (C) 2018 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$
+##
+#############################################################################
+
+from __future__ import print_function, absolute_import
+
+"""
+fix-complaints.py
+
+This module fixes the buildbot messages of external python modules.
+Run it once after copying a new version. It is idem-potent, unless
+you are changing messages (what I did, of course :-) .
+"""
+
+import os
+
+patched_modules = "backport_inspect typing27"
+
+offending_words = {
+ "behavio""ur": "behavior",
+ "at""least": "at_least",
+ "reali""sed": "realized",
+}
+
+utf8_line = "# This Python file uses the following encoding: utf-8\n"
+marker_line = "# It has been edited by {} .\n".format(
+ os.path.basename(__file__))
+
+def patch_file(fname):
+ with open(fname) as f:
+ lines = f.readlines()
+ dup = lines[:]
+ for idx, line in enumerate(lines):
+ for word, repl in offending_words.items():
+ if word in line:
+ lines[idx] = line.replace(word, repl)
+ print("line:{!r} {!r}->{!r}".format(line, word, repl))
+ if lines[0].strip() != utf8_line.strip():
+ lines[:0] = [utf8_line, "\n"]
+ if lines[1] != marker_line:
+ lines[1:1] = marker_line
+ if lines != dup:
+ with open(fname, "w") as f:
+ f.write("".join(lines))
+
+def doit():
+ dir = os.path.dirname(__file__)
+ for name in patched_modules.split():
+ fname = os.path.join(dir, name + ".py")
+ print("Working on", fname)
+ patch_file(fname)
+
+if __name__ == "__main__":
+ doit()
+
+# end of file
diff --git a/sources/shiboken2/shibokenmodule/support/signature/layout.py b/sources/shiboken2/shibokenmodule/support/signature/layout.py
new file mode 100644
index 000000000..47f97fc2b
--- /dev/null
+++ b/sources/shiboken2/shibokenmodule/support/signature/layout.py
@@ -0,0 +1,245 @@
+#############################################################################
+##
+## Copyright (C) 2018 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$
+##
+#############################################################################
+
+from __future__ import print_function, absolute_import
+
+"""
+layout.py
+
+The signature module now has the capability to configure
+differently formatted versions of signatures. The default
+layout is known from the "__signature__" attribute.
+
+The function "get_signature(ob, modifier=None)" produces the same
+signatures by default. By passing different modifiers, you
+can select different layouts.
+
+This module configures the different layouts which can be used.
+It also implements them in this file. The configurations are
+used literally as strings like "signature", "existence", etc.
+"""
+
+from textwrap import dedent
+from signature_loader import inspect
+
+
+class SimpleNamespace(object):
+ # From types.rst, because the builtin is implemented in Python 3, only.
+ def __init__(self, **kwargs):
+ self.__dict__.update(kwargs)
+
+ def __repr__(self):
+ keys = sorted(self.__dict__)
+ items = ("{}={!r}".format(k, self.__dict__[k]) for k in keys)
+ return "{}({})".format(type(self).__name__, ", ".join(items))
+
+ def __eq__(self, other):
+ return self.__dict__ == other.__dict__
+
+
+class SignatureLayout(SimpleNamespace):
+ """
+ Configure a signature.
+
+ The layout of signatures can have different layouts which are
+ controlled by keyword arguments:
+
+ definition=True Determines if self will generated.
+ defaults=True
+ ellipsis=False Replaces defaults by "...".
+ return_annotation=True
+ parameter_names=True False removes names before ":".
+ """
+ allowed_keys = SimpleNamespace(definition=True,
+ defaults=True,
+ ellipsis=False,
+ return_annotation=True,
+ parameter_names=True)
+ allowed_values = True, False
+
+ def __init__(self, **kwds):
+ args = SimpleNamespace(**self.allowed_keys.__dict__)
+ args.__dict__.update(kwds)
+ self.__dict__.update(args.__dict__)
+ err_keys = list(set(self.__dict__) - set(self.allowed_keys.__dict__))
+ if err_keys:
+ self._attributeerror(err_keys)
+ err_values = list(set(self.__dict__.values()) - set(self.allowed_values))
+ if err_values:
+ self._valueerror(err_values)
+
+ def __setattr__(self, key, value):
+ if key not in self.allowed_keys.__dict__:
+ self._attributeerror([key])
+ if value not in self.allowed_values:
+ self._valueerror([value])
+ self.__dict__[key] = value
+
+ def _attributeerror(self, err_keys):
+ err_keys = ", ".join(err_keys)
+ allowed_keys = ", ".join(self.allowed_keys.__dict__.keys())
+ raise AttributeError(dedent("""\
+ Not allowed: '{err_keys}'.
+ The only allowed keywords are '{allowed_keys}'.
+ """.format(**locals())))
+
+ def _valueerror(self, err_values):
+ err_values = ", ".join(map(str, err_values))
+ allowed_values = ", ".join(map(str, self.allowed_values))
+ raise ValueError(dedent("""\
+ Not allowed: '{err_values}'.
+ The only allowed values are '{allowed_values}'.
+ """.format(**locals())))
+
+# The following names are used literally in this module.
+# This way, we avoid the dict hashing problem.
+signature = SignatureLayout()
+
+existence = SignatureLayout(definition=False,
+ defaults=False,
+ return_annotation=False,
+ parameter_names=False)
+
+hintingstub = SignatureLayout(ellipsis=True)
+
+typeerror = SignatureLayout(definition=False,
+ return_annotation=False,
+ parameter_names=False)
+
+
+def define_nameless_parameter():
+ """
+ Create Nameless Parameters
+
+ A nameless parameter has a reduced string representation.
+ This is done by cloning the parameter type and overwriting its
+ __str__ method. The inner structure is still a valid parameter.
+ """
+ def __str__(self):
+ # for Python 2, we must change self to be an instance of P
+ klass = self.__class__
+ self.__class__ = P
+ txt = P.__str__(self)
+ self.__class__ = klass
+ txt = txt[txt.index(":") + 1:].strip() if ":" in txt else txt
+ return txt
+
+ P = inspect.Parameter
+ newname = "NamelessParameter"
+ bases = P.__bases__
+ body = dict(P.__dict__) # get rid of mappingproxy
+ if "__slots__" in body:
+ # __slots__ would create duplicates
+ for name in body["__slots__"]:
+ del body[name]
+ body["__str__"] = __str__
+ return type(newname, bases, body)
+
+
+NamelessParameter = define_nameless_parameter()
+
+
+def make_signature_nameless(signature):
+ """
+ Make a Signature Nameless
+
+ We use an existing signature and change the type of its parameters.
+ The signature looks different, but is totally intact.
+ """
+ for key in signature.parameters.keys():
+ signature.parameters[key].__class__ = NamelessParameter
+
+
+def create_signature(props, key):
+ if not props:
+ # empty signatures string
+ return
+ if isinstance(props["multi"], list):
+ # multi sig: call recursively
+ return list(create_signature(elem, key)
+ for elem in props["multi"])
+ if type(key) is tuple:
+ sig_kind, modifier = key
+ else:
+ sig_kind, modifier = key, "signature"
+
+ layout = globals()[modifier] # lookup of the modifier in this module
+ if not isinstance(layout, SignatureLayout):
+ raise SystemError("Modifiers must be names of a SignatureLayout "
+ "instance")
+
+ # this is the basic layout of a signature
+ varnames = props["varnames"]
+ if layout.definition:
+ if sig_kind == "function":
+ pass
+ elif sig_kind == "method":
+ varnames = ("self",) + varnames
+ elif sig_kind == "staticmethod":
+ pass
+ elif sig_kind == "classmethod":
+ varnames = ("klass",) + varnames
+ else:
+ raise SystemError("Methods must be function, method, staticmethod or "
+ "classmethod")
+ # calculate the modifications
+ defaults = props["defaults"][:]
+ if not layout.defaults:
+ defaults = ()
+ if layout.ellipsis:
+ defaults = ("...",) * len(defaults)
+ annotations = props["annotations"].copy()
+ if not layout.return_annotation and "return" in annotations:
+ del annotations["return"]
+
+ # attach parameters to a fake function and build a signature
+ argstr = ", ".join(varnames)
+ fakefunc = eval("lambda {}: None".format(argstr))
+ fakefunc.__name__ = props["name"]
+ fakefunc.__defaults__ = defaults
+ fakefunc.__kwdefaults__ = props["kwdefaults"]
+ fakefunc.__annotations__ = annotations
+ sig = inspect._signature_from_function(inspect.Signature, fakefunc)
+
+ # the special case of nameless parameters
+ if not layout.parameter_names:
+ make_signature_nameless(sig)
+ return sig
+
+# end of file
diff --git a/sources/shiboken2/shibokenmodule/support/signature/lib/__init__.py b/sources/shiboken2/shibokenmodule/support/signature/lib/__init__.py
new file mode 100644
index 000000000..2d640cb89
--- /dev/null
+++ b/sources/shiboken2/shibokenmodule/support/signature/lib/__init__.py
@@ -0,0 +1,40 @@
+#############################################################################
+##
+## Copyright (C) 2018 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$
+##
+#############################################################################
+
+# this file intentionally left blank
diff --git a/sources/shiboken2/shibokenmodule/support/signature/lib/enum_sig.py b/sources/shiboken2/shibokenmodule/support/signature/lib/enum_sig.py
new file mode 100644
index 000000000..2ec14d62b
--- /dev/null
+++ b/sources/shiboken2/shibokenmodule/support/signature/lib/enum_sig.py
@@ -0,0 +1,135 @@
+#############################################################################
+##
+## Copyright (C) 2018 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$
+##
+#############################################################################
+
+from __future__ import print_function, absolute_import
+
+import sys
+from signature_loader import get_signature, inspect
+
+
+class ExactEnumerator(object):
+ """
+ ExactEnumerator enumerates all signatures in a module as they are.
+
+ This class is used for generating complete listings of all signatures.
+ An appropriate formatter should be supplied, if printable output
+ is desired.
+ """
+ def __init__(self, formatter, result_type=dict):
+ self.fmt = formatter
+ self.result_type = result_type
+
+ def module(self, mod_name):
+ __import__(mod_name)
+ with self.fmt.module(mod_name):
+ module = sys.modules[mod_name]
+ members = inspect.getmembers(module, inspect.isclass)
+ functions = inspect.getmembers(module, inspect.isroutine)
+ ret = self.result_type()
+ self.fmt.class_name = None
+ for func_name, func in functions:
+ ret.update(self.function(func_name, func))
+ for class_name, klass in members:
+ ret.update(self.klass(class_name, klass))
+ return ret
+
+ def klass(self, class_name, klass):
+ bases_list = []
+ for base in klass.__bases__:
+ name = base.__name__
+ if name == "object":
+ pass
+ else:
+ modname = base.__module__
+ name = modname + "." + base.__name__
+ bases_list.append(name)
+ class_str = "{}({})".format(class_name, ", ".join(bases_list))
+ with self.fmt.klass(class_name, class_str):
+ ret = self.function("__init__", klass)
+ # class_members = inspect.getmembers(klass)
+ # gives us also the inherited things.
+ class_members = sorted(list(klass.__dict__.items()))
+ subclasses = []
+ for thing_name, thing in class_members:
+ if inspect.isclass(thing):
+ subclass_name = ".".join((class_name, thing_name))
+ subclasses.append((subclass_name, thing))
+ else:
+ ret.update(self.function(thing_name, thing))
+ for subclass_name, subclass in subclasses:
+ ret.update(self.klass(subclass_name, subclass))
+ return ret
+
+ def function(self, func_name, func):
+ ret = self.result_type()
+ signature = getattr(func, '__signature__', None)
+ if signature is not None:
+ with self.fmt.function(func_name, signature) as key:
+ ret[key] = str(signature)
+ return ret
+
+
+def stringify(signature):
+ if isinstance(signature, list):
+ # remove duplicates which still sometimes occour:
+ ret = set(stringify(sig) for sig in signature)
+ return sorted(ret) if len(ret) > 1 else list(ret)[0]
+ return tuple(str(pv) for pv in signature.parameters.values())
+
+
+class SimplifyingEnumerator(ExactEnumerator):
+ """
+ SimplifyingEnumerator enumerates all signatures in a module filtered.
+
+ There are no default values, no variable
+ names and no self parameter. Only types are present after simplification.
+ The functions 'next' resp. '__next__' are removed
+ to make the output identical for Python 2 and 3.
+ An appropriate formatter should be supplied, if printable output
+ is desired.
+ """
+
+ def function(self, func_name, func):
+ ret = self.result_type()
+ signature = get_signature(func, 'existence')
+ sig = stringify(signature) if signature is not None else None
+ if sig is not None and func_name not in ("next", "__next__", "__div__"):
+ with self.fmt.function(func_name, sig) as key:
+ ret[key] = sig
+ return ret
diff --git a/sources/shiboken2/shibokenmodule/support/signature/loader.py b/sources/shiboken2/shibokenmodule/support/signature/loader.py
new file mode 100644
index 000000000..83493e511
--- /dev/null
+++ b/sources/shiboken2/shibokenmodule/support/signature/loader.py
@@ -0,0 +1,176 @@
+#############################################################################
+##
+## Copyright (C) 2018 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$
+##
+#############################################################################
+
+from __future__ import print_function, absolute_import
+
+"""
+loader.py
+
+The loader has to lazy-load the signature module and also provides a few
+Python modules to support Python 2.7 .
+
+This file was originally directly embedded into the C source.
+After it grew more and more, I now prefer to have it as Python file.
+The remaining stub loader in the C source is now only a short string.
+
+This version does no longer use an embedded .zip file but is a package.
+The old code without a package but with zip compression can still be found
+at https://codereview.qt-project.org/#/c/203533/ for reference.
+"""
+
+import sys
+import os
+import traceback
+import types
+from contextlib import contextmanager
+from distutils.sysconfig import get_python_lib
+
+"""
+A note on the import problem (solved):
+
+During the tests, the shiboken build structure has the layout
+
+ shiboken2/shibokenmodule/shiboken2.abi3.so
+
+and the name "shiboken2" in sys.modules points directly to the binary
+file, hiding the outer shiboken2 module.
+
+To fix that, we temporarily remove the binary from sys.path,
+do the needed imports and then restore the binary.
+This action was put into a context manager for readability.
+"""
+
+# On Python 2, we only have ImportError, which is way too coarse.
+# When problems occour, please use Python 3, because it has the finer
+# ModuleNotFoundError.
+
+try:
+ ModuleNotFoundError
+except NameError:
+ ModuleNotFoundError = ImportError
+
+@contextmanager
+def ensure_import_support():
+ # Make sure that we always have the shiboken containing package first.
+ # This is sometimes hidden by the ctest paths.
+ # We adjust the path in a way that the support folder comes first.
+ # This can be in "shiboken2/support" or in "shibokenmodule/support",
+ # so we use the "support" folder as toplevel.
+ sbk_support_dir = os.path.abspath(os.path.join(__file__, "..", "..", ".."))
+ sys.path.insert(0, sbk_support_dir)
+ sbk = "shiboken2"
+ save_sbk = sys.modules.pop(sbk) if sbk in sys.modules else None
+ # make sure that we get at the support folder
+ try:
+ import support
+ yield
+ except Exception as e:
+ print("Problem importing support:")
+ print(e)
+ traceback.print_exc()
+ sys.stdout.flush()
+ sys.exit(-1)
+ if save_sbk:
+ sys.modules[sbk] = save_sbk
+ sys.path.pop(0)
+
+
+with ensure_import_support():
+ # We store all needed modules in signature_loader.
+ # This way, they are always accessible.
+ import signature_loader
+
+ if sys.version_info >= (3,):
+ import typing
+ import inspect
+ else:
+ import inspect
+ namespace = inspect.__dict__
+ from support.signature import typing
+ from support.signature import backport_inspect as inspect
+ _doc = inspect.__doc__
+ inspect.__dict__.update(namespace)
+ inspect.__doc__ += _doc
+ # force inspect to find all attributes. See "heuristic" in pydoc.py!
+ inspect.__all__ = list(x for x in dir(inspect) if not x.startswith("_"))
+
+ def put_into_loader_package(module, loader=signature_loader):
+ # Note: the "with" statement hides that we are no longer in a
+ # global context, but inside ensure_import_support. Therefore,
+ # we need to explicitly pass the signature_loader in.
+
+ # take the last component of the module name
+ name = module.__name__.rsplit(".", 1)[-1]
+ # allow access as signature_loader.typing
+ setattr(loader, name, module)
+ # put into sys.modules as a package to allow all import options
+ fullname = "{}.{}".format(loader.__name__, name)
+ sys.modules[fullname] = module
+
+ put_into_loader_package(typing)
+ put_into_loader_package(inspect)
+ from support.signature import mapping as sbk_mapping
+ sbk_mapping.__name__ = "sbk_mapping"
+ put_into_loader_package(sbk_mapping)
+ # We may or may not use PySide.
+ try:
+ from PySide2.support.signature import mapping
+ except ModuleNotFoundError:
+ mapping = sbk_mapping
+ mapping.__name__ = "mapping"
+ put_into_loader_package(mapping)
+ from support.signature import layout
+ put_into_loader_package(layout)
+ from support.signature.lib import enum_sig
+ put_into_loader_package(enum_sig)
+ from support.signature.parser import pyside_type_init
+
+
+# Note also that during the tests we have a different encoding that would
+# break the Python license decorated files without an encoding line.
+
+# name used in signature.cpp
+def create_signature(props, key):
+ return layout.create_signature(props, key)
+
+# name used in signature.cpp
+def seterror_argument(args, func_name):
+ return errorhandler.seterror_argument(args, func_name)
+
+# end of file
diff --git a/sources/shiboken2/shibokenmodule/support/signature/mapping.py b/sources/shiboken2/shibokenmodule/support/signature/mapping.py
new file mode 100644
index 000000000..724b0c751
--- /dev/null
+++ b/sources/shiboken2/shibokenmodule/support/signature/mapping.py
@@ -0,0 +1,199 @@
+#############################################################################
+##
+## Copyright (C) 2018 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$
+##
+#############################################################################
+
+from __future__ import print_function, absolute_import
+
+"""
+mapping.py
+
+This module has the mapping from the pyside C-modules view of signatures
+to the Python representation.
+
+The PySide modules are not loaded in advance, but only after they appear
+in sys.modules. This minimizes the loading overhead.
+"""
+
+import sys
+import struct
+import os
+import pkgutil
+
+from signature_loader import typing
+
+ellipsis = "..."
+Char = typing.Union[str, int] # how do I model the limitation to 1 char?
+StringList = typing.List[str]
+IntList = typing.List[int]
+Point = typing.Tuple[float, float]
+PointList = typing.List[Point]
+IntMatrix = typing.List[IntList]
+Variant = typing.Any
+ModelIndexList = typing.List[int]
+QImageCleanupFunction = typing.Callable
+FloatList = typing.List[float]
+FloatMatrix = typing.List[FloatList]
+# Pair could be more specific, but we loose the info in the generator.
+Pair = typing.Tuple[typing.Any, typing.Any]
+MultiMap = typing.DefaultDict[str, typing.List[str]]
+
+# ulong_max is only 32 bit on windows.
+ulong_max = 2*sys.maxsize+1 if len(struct.pack("L", 1)) != 4 else 0xffffffff
+ushort_max = 0xffff
+
+GL_COLOR_BUFFER_BIT = 0x00004000
+GL_NEAREST = 0x2600
+
+WId = int
+
+# from 5.9
+GL_TEXTURE_2D = 0x0DE1
+GL_RGBA = 0x1908
+
+class _NotCalled(str):
+ """
+ Wrap some text with semantics
+
+ This class is wrapped around text in order to avoid calling it.
+ There are three reasons for this:
+
+ - some instances cannot be created since they are abstract,
+ - some can only be created after qApp was created,
+ - some have an ugly __repr__ with angle brackets in it.
+
+ By using derived classes, good looking instances can be created
+ which can be used to generate source code or .pyi files. When the
+ real object is needed, the wrapper can simply be called.
+ """
+ def __repr__(self):
+ suppress = "PySide2.support.signature.typing."
+ text = self[len(suppress):] if self.startswith(suppress) else self
+ return "{}({})".format(type(self).__name__, text)
+
+ def __call__(self):
+ from signature_loader.mapping import __dict__ as namespace
+ text = self if self.endswith(")") else self + "()"
+ return eval(text, namespace)
+
+# Some types are abstract. They just show their name.
+class Virtual(_NotCalled):
+ pass
+
+# Other types I simply could not find.
+class Missing(_NotCalled):
+ pass
+
+class Invalid(_NotCalled):
+ pass
+
+# Helper types
+class Default(_NotCalled):
+ pass
+
+class Instance(_NotCalled):
+ pass
+
+
+class Reloader(object):
+ _uninitialized = ["sample"]
+ _prefixes = [""]
+
+ def __init__(self):
+ self.sys_module_count = 0
+ self.uninitialized = self._uninitialized
+
+ def update(self, g=None):
+ if self.sys_module_count == len(sys.modules):
+ return
+ self.sys_module_count = len(sys.modules)
+ if g is None:
+ g = globals()
+ for mod_name in self.uninitialized[:]:
+ for prefix in self._prefixes:
+ if prefix + mod_name in sys.modules:
+ self.uninitialized.remove(mod_name)
+ proc_name = "init_" + mod_name
+ if proc_name in g:
+ g.update(g[proc_name]())
+
+
+update_mapping = Reloader().update
+type_map = {}
+
+
+def init_sample():
+ import sample
+ import datetime
+ type_map.update({
+ "sample.int": int,
+ "Complex": complex,
+ "sample.OddBool": bool,
+ "sample.bool": bool,
+ "sample.PStr": str,
+ "double[]": FloatList,
+ "OddBool": bool,
+ "PStr": str,
+ "sample.char": Char,
+ "double[][]": FloatMatrix,
+ "int[]": IntList,
+ "int[][]": IntMatrix,
+ "sample.Point": Point,
+ "sample.ObjectType": object,
+ "std.string": str,
+ "HANDLE": int,
+ "Foo.HANDLE": int,
+ "sample.Photon.TemplateBase": Missing("sample.Photon.TemplateBase"),
+ "ObjectType.Identifier": Missing("sample.ObjectType.Identifier"),
+ "zero(HANDLE)": 0,
+ "Null": None,
+ "zero(sample.ObjectType)": None,
+ "std.size_t": int,
+ 'Str("<unknown>")': "<unknown>",
+ 'Str("<unk")': "<unk",
+ 'Str("nown>")': "nown>",
+ "zero(sample.ObjectModel)": None,
+ "sample.unsigned char": Char,
+ "sample.double": float,
+ "zero(sample.bool)": False,
+ "PyDate": datetime.date,
+ "ZeroIn": 0,
+ "Point[]": PointList,
+ })
+ return locals()
+
+# end of file
diff --git a/sources/shiboken2/shibokenmodule/support/signature/parser.py b/sources/shiboken2/shibokenmodule/support/signature/parser.py
new file mode 100644
index 000000000..82cd9aab3
--- /dev/null
+++ b/sources/shiboken2/shibokenmodule/support/signature/parser.py
@@ -0,0 +1,285 @@
+#############################################################################
+##
+## Copyright (C) 2018 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$
+##
+#############################################################################
+
+from __future__ import print_function, absolute_import
+
+import sys
+import re
+import warnings
+import types
+import keyword
+import functools
+from signature_loader.mapping import (
+ type_map, update_mapping, __dict__ as namespace)
+
+_DEBUG = False
+LIST_KEYWORDS = False
+
+"""
+parser.py
+
+This module parses the signature text and creates properties for the
+signature objects.
+
+PySide has a new function 'CppGenerator::writeSignatureInfo()'
+that extracts the gathered information about the function arguments
+and defaults as good as it can. But what PySide generates is still
+very C-ish and has many constants that Python doesn't understand.
+
+The function 'try_to_guess()' below understands a lot of PySide's
+peculiar way to assume local context. If it is able to do the guess,
+then the result is inserted into the dict, so the search happens
+not again. For everything that is not covered by these automatic
+guesses, we provide an entry in 'type_map' that resolves it.
+
+In effect, 'type_map' maps text to real Python objects.
+"""
+
+def dprint(*args, **kw):
+ if _DEBUG:
+ import pprint
+ for arg in args:
+ pprint.pprint(arg)
+
+def _parse_line(line):
+ line_re = r"""
+ ((?P<multi> ([0-9]+)) : )? # the optional multi-index
+ (?P<funcname> \w+(\.\w+)*) # the function name
+ \( (?P<arglist> .*?) \) # the argument list
+ ( -> (?P<returntype> .*) )? # the optional return type
+ $
+ """
+ ret = re.match(line_re, line, re.VERBOSE).groupdict()
+ arglist = ret["arglist"]
+ # The following is a split re. The string is broken into pieces which are
+ # between the recognized strings. Because the re has groups, both the
+ # strings and the delimiters are returned, where the strings are not
+ # interesting at all: They are just the commata.
+ # Note that it is necessary to put the characters with special handling in
+ # the first group (comma, brace, angle bracket).
+ # Then they are not recognized there, and we can handle them differently
+ # in the following expressions.
+ arglist = list(x.strip() for x in re.split(r"""
+ (
+ (?: # inner group is not capturing
+ [^,()<>] # no commas or braces or angle brackets
+ |
+ \(
+ (?:
+ [^()]* # or one brace pair
+ |
+ \(
+ [^()]* # or doubls nested pair
+ \)
+ )*
+ \)
+ |
+ < # or one angle bracket pair
+ [^<>]*
+ >
+ )+ # longest possible span
+ ) # this list is interspersed with "," and surrounded by ""
+ """, arglist, flags=re.VERBOSE)
+ if x.strip() not in ("", ","))
+ args = []
+ for arg in arglist:
+ name, ann = arg.split(":")
+ if name in keyword.kwlist:
+ if LIST_KEYWORDS:
+ print("KEYWORD", ret)
+ name = name + "_"
+ if "=" in ann:
+ ann, default = ann.split("=")
+ tup = name, ann, default
+ else:
+ tup = name, ann
+ args.append(tup)
+ ret["arglist"] = args
+ multi = ret["multi"]
+ if multi is not None:
+ ret["multi"] = int(multi)
+ funcname = ret["funcname"]
+ parts = funcname.split(".")
+ if parts[-1] in keyword.kwlist:
+ ret["funcname"] = funcname + "_"
+ return ret
+
+def make_good_value(thing, valtype):
+ try:
+ if thing.endswith("()"):
+ thing = 'Default("{}")'.format(thing[:-2])
+ else:
+ ret = eval(thing, namespace)
+ if valtype and repr(ret).startswith("<"):
+ thing = 'Instance("{}")'.format(thing)
+ return eval(thing, namespace)
+ except Exception:
+ pass
+
+def try_to_guess(thing, valtype):
+ if "." not in thing and "(" not in thing:
+ text = "{}.{}".format(valtype, thing)
+ ret = make_good_value(text, valtype)
+ if ret is not None:
+ return ret
+ typewords = valtype.split(".")
+ valwords = thing.split(".")
+ braceless = valwords[0] # Yes, not -1. Relevant is the overlapped word.
+ if "(" in braceless:
+ braceless = braceless[:braceless.index("(")]
+ for idx, w in enumerate(typewords):
+ if w == braceless:
+ text = ".".join(typewords[:idx] + valwords)
+ ret = make_good_value(text, valtype)
+ if ret is not None:
+ return ret
+ return None
+
+def _resolve_value(thing, valtype, line):
+ if thing in ("0", "None") and valtype:
+ thing = "zero({})".format(valtype)
+ if thing in type_map:
+ return type_map[thing]
+ res = make_good_value(thing, valtype)
+ if res is not None:
+ type_map[thing] = res
+ return res
+ res = try_to_guess(thing, valtype) if valtype else None
+ if res is not None:
+ type_map[thing] = res
+ return res
+ warnings.warn("""pyside_type_init:
+
+ UNRECOGNIZED: {!r}
+ OFFENDING LINE: {!r}
+ """.format(thing, line), RuntimeWarning)
+ return thing
+
+def _resolve_type(thing, line):
+ return _resolve_value(thing, None, line)
+
+def calculate_props(line):
+ line = line.strip()
+ res = _parse_line(line)
+ arglist = res["arglist"]
+ annotations = {}
+ _defaults = []
+ for idx, tup in enumerate(arglist):
+ name, ann = tup[:2]
+ if ann == "...":
+ name = "*args"
+ # copy the fields back :()
+ ann = 'NULL' # maps to None
+ tup = name, ann
+ arglist[idx] = tup
+ annotations[name] = _resolve_type(ann, line)
+ if len(tup) == 3:
+ default = _resolve_value(tup[2], ann, line)
+ _defaults.append(default)
+ defaults = tuple(_defaults)
+ returntype = res["returntype"]
+ if returntype is not None:
+ annotations["return"] = _resolve_type(returntype, line)
+ props = {}
+ props["defaults"] = defaults
+ props["kwdefaults"] = {}
+ props["annotations"] = annotations
+ props["varnames"] = varnames = tuple(tup[0] for tup in arglist)
+ funcname = res["funcname"]
+ props["fullname"] = funcname
+ shortname = funcname[funcname.rindex(".")+1:]
+ props["name"] = shortname
+ props["multi"] = res["multi"]
+ return props
+
+def fixup_multilines(sig_str):
+ lines = list(line.strip() for line in sig_str.strip().splitlines())
+ res = []
+ multi_lines = []
+ for line in lines:
+ multi = re.match(r"([0-9]+):", line)
+ if multi:
+ idx, rest = int(multi.group(1)), line[multi.end():]
+ multi_lines.append(rest)
+ if idx > 0:
+ continue
+ # remove duplicates
+ multi_lines = list(set(multi_lines))
+ # renumber or return a single line
+ nmulti = len(multi_lines)
+ if nmulti > 1:
+ for idx, line in enumerate(multi_lines):
+ res.append("{}:{}".format(nmulti-idx-1, line))
+ else:
+ res.append(multi_lines[0])
+ multi_lines = []
+ else:
+ res.append(line)
+ return res
+
+def pyside_type_init(typemod, sig_str):
+ dprint()
+ if type(typemod) is types.ModuleType:
+ dprint("Initialization of module '{}'".format(typemod.__name__))
+ else:
+ dprint("Initialization of type '{}.{}'".format(typemod.__module__,
+ typemod.__name__))
+ update_mapping()
+ lines = fixup_multilines(sig_str)
+ ret = {}
+ multi_props = []
+ for line in lines:
+ props = calculate_props(line)
+ shortname = props["name"]
+ multi = props["multi"]
+ if multi is None:
+ ret[shortname] = props
+ dprint(props)
+ else:
+ multi_props.append(props)
+ if multi > 0:
+ continue
+ fullname = props.pop("fullname")
+ multi_props = {"multi": multi_props, "fullname": fullname}
+ ret[shortname] = multi_props
+ dprint(multi_props)
+ multi_props = []
+ return ret
+
+# end of file
diff --git a/sources/shiboken2/shibokenmodule/support/signature/qt_attribution.json b/sources/shiboken2/shibokenmodule/support/signature/qt_attribution.json
new file mode 100644
index 000000000..491ae8054
--- /dev/null
+++ b/sources/shiboken2/shibokenmodule/support/signature/qt_attribution.json
@@ -0,0 +1,13 @@
+{
+ "Id": "python",
+ "Name": "Python",
+ "QDocModule": "QtForPython",
+ "QtUsage": "Used for Qt for Python in the signature extension.",
+ "Description": "Qt for Python is an add-on for Python. The signature packages of PySide uses certain copied and adapted source files (backport_inspect.py, typing27.py). See the folder sources/pyside2/PySide2/support/signature .",
+ "Homepage": "http://www.python.org/",
+ "Version": "3.7.0",
+ "LicenseId": "Python-2.0",
+ "License": "Python License 2.0",
+ "LicenseFile": "PSF-3.7.0.txt",
+ "Copyright": "© Copyright 2001-2018, Python Software Foundation."
+}
diff --git a/sources/shiboken2/shibokenmodule/support/signature/typing27.py b/sources/shiboken2/shibokenmodule/support/signature/typing27.py
new file mode 100644
index 000000000..5d1c6058b
--- /dev/null
+++ b/sources/shiboken2/shibokenmodule/support/signature/typing27.py
@@ -0,0 +1,2293 @@
+# This Python file uses the following encoding: utf-8
+# It has been edited by fix-complaints.py .
+
+#############################################################################
+##
+## Copyright (C) 2018 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$
+##
+#############################################################################
+
+"""
+PSF LICENSE AGREEMENT FOR PYTHON 3.7.0
+
+1. This LICENSE AGREEMENT is between the Python Software Foundation ("PSF"), and
+ the Individual or Organization ("Licensee") accessing and otherwise using Python
+ 3.7.0 software in source or binary form and its associated documentation.
+
+2. Subject to the terms and conditions of this License Agreement, PSF hereby
+ grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce,
+ analyze, test, perform and/or display publicly, prepare derivative works,
+ distribute, and otherwise use Python 3.7.0 alone or in any derivative
+ version, provided, however, that PSF's License Agreement and PSF's notice of
+ copyright, i.e., "Copyright © 2001-2018 Python Software Foundation; All Rights
+ Reserved" are retained in Python 3.7.0 alone or in any derivative version
+ prepared by Licensee.
+
+3. In the event Licensee prepares a derivative work that is based on or
+ incorporates Python 3.7.0 or any part thereof, and wants to make the
+ derivative work available to others as provided herein, then Licensee hereby
+ agrees to include in any such work a brief summary of the changes made to Python
+ 3.7.0.
+
+4. PSF is making Python 3.7.0 available to Licensee on an "AS IS" basis.
+ PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF
+ EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND DISCLAIMS ANY REPRESENTATION OR
+ WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE
+ USE OF PYTHON 3.7.0 WILL NOT INFRINGE ANY THIRD PARTY RIGHTS.
+
+5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON 3.7.0
+ FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF
+ MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 3.7.0, OR ANY DERIVATIVE
+ THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
+
+6. This License Agreement will automatically terminate upon a material breach of
+ its terms and conditions.
+
+7. Nothing in this License Agreement shall be deemed to create any relationship
+ of agency, partnership, or joint venture between PSF and Licensee. This License
+ Agreement does not grant permission to use PSF trademarks or trade name in a
+ trademark sense to endorse or promote products or services of Licensee, or any
+ third party.
+
+8. By copying, installing or otherwise using Python 3.7.0, Licensee agrees
+ to be bound by the terms and conditions of this License Agreement.
+"""
+
+from __future__ import absolute_import, unicode_literals
+
+import abc
+from abc import abstractmethod, abstractproperty
+import collections
+import functools
+import re as stdlib_re # Avoid confusion with the re we export.
+import sys
+import types
+import copy
+try:
+ import collections.abc as collections_abc
+except ImportError:
+ import collections as collections_abc # Fallback for PY3.2.
+
+
+# Please keep __all__ alphabetized within each category.
+__all__ = [
+ # Super-special typing primitives.
+ 'Any',
+ 'Callable',
+ 'ClassVar',
+ 'Generic',
+ 'Optional',
+ 'Tuple',
+ 'Type',
+ 'TypeVar',
+ 'Union',
+
+ # ABCs (from collections.abc).
+ 'AbstractSet', # collections.abc.Set.
+ 'GenericMeta', # subclass of abc.ABCMeta and a metaclass
+ # for 'Generic' and ABCs below.
+ 'ByteString',
+ 'Container',
+ 'ContextManager',
+ 'Hashable',
+ 'ItemsView',
+ 'Iterable',
+ 'Iterator',
+ 'KeysView',
+ 'Mapping',
+ 'MappingView',
+ 'MutableMapping',
+ 'MutableSequence',
+ 'MutableSet',
+ 'Sequence',
+ 'Sized',
+ 'ValuesView',
+
+ # Structural checks, a.k.a. protocols.
+ 'Reversible',
+ 'SupportsAbs',
+ 'SupportsComplex',
+ 'SupportsFloat',
+ 'SupportsInt',
+
+ # Concrete collection types.
+ 'Counter',
+ 'Deque',
+ 'Dict',
+ 'DefaultDict',
+ 'List',
+ 'Set',
+ 'FrozenSet',
+ 'NamedTuple', # Not really a type.
+ 'Generator',
+
+ # One-off things.
+ 'AnyStr',
+ 'cast',
+ 'get_type_hints',
+ 'NewType',
+ 'no_type_check',
+ 'no_type_check_decorator',
+ 'NoReturn',
+ 'overload',
+ 'Text',
+ 'TYPE_CHECKING',
+]
+
+# The pseudo-submodules 're' and 'io' are part of the public
+# namespace, but excluded from __all__ because they might stomp on
+# legitimate imports of those modules.
+
+
+def _qualname(x):
+ if sys.version_info[:2] >= (3, 3):
+ return x.__qualname__
+ else:
+ # Fall back to just name.
+ return x.__name__
+
+
+def _trim_name(nm):
+ whitelist = ('_TypeAlias', '_ForwardRef', '_TypingBase', '_FinalTypingBase')
+ if nm.startswith('_') and nm not in whitelist:
+ nm = nm[1:]
+ return nm
+
+
+class TypingMeta(type):
+ """Metaclass for most types defined in typing module
+ (not a part of public API).
+
+ This also defines a dummy constructor (all the work for most typing
+ constructs is done in __new__) and a nicer repr().
+ """
+
+ _is_protocol = False
+
+ def __new__(cls, name, bases, namespace):
+ return super(TypingMeta, cls).__new__(cls, str(name), bases, namespace)
+
+ @classmethod
+ def assert_no_subclassing(cls, bases):
+ for base in bases:
+ if isinstance(base, cls):
+ raise TypeError("Cannot subclass %s" %
+ (', '.join(map(_type_repr, bases)) or '()'))
+
+ def __init__(self, *args, **kwds):
+ pass
+
+ def _eval_type(self, globalns, localns):
+ """Override this in subclasses to interpret forward references.
+
+ For example, List['C'] is internally stored as
+ List[_ForwardRef('C')], which should evaluate to List[C],
+ where C is an object found in globalns or localns (searching
+ localns first, of course).
+ """
+ return self
+
+ def _get_type_vars(self, tvars):
+ pass
+
+ def __repr__(self):
+ qname = _trim_name(_qualname(self))
+ return '%s.%s' % (self.__module__, qname)
+
+
+class _TypingBase(object):
+ """Internal indicator of special typing constructs."""
+ __metaclass__ = TypingMeta
+ __slots__ = ('__weakref__',)
+
+ def __init__(self, *args, **kwds):
+ pass
+
+ def __new__(cls, *args, **kwds):
+ """Constructor.
+
+ This only exists to give a better error message in case
+ someone tries to subclass a special typing object (not a good idea).
+ """
+ if (len(args) == 3 and
+ isinstance(args[0], str) and
+ isinstance(args[1], tuple)):
+ # Close enough.
+ raise TypeError("Cannot subclass %r" % cls)
+ return super(_TypingBase, cls).__new__(cls)
+
+ # Things that are not classes also need these.
+ def _eval_type(self, globalns, localns):
+ return self
+
+ def _get_type_vars(self, tvars):
+ pass
+
+ def __repr__(self):
+ cls = type(self)
+ qname = _trim_name(_qualname(cls))
+ return '%s.%s' % (cls.__module__, qname)
+
+ def __call__(self, *args, **kwds):
+ raise TypeError("Cannot instantiate %r" % type(self))
+
+
+class _FinalTypingBase(_TypingBase):
+ """Internal mix-in class to prevent instantiation.
+
+ Prevents instantiation unless _root=True is given in class call.
+ It is used to create pseudo-singleton instances Any, Union, Optional, etc.
+ """
+
+ __slots__ = ()
+
+ def __new__(cls, *args, **kwds):
+ self = super(_FinalTypingBase, cls).__new__(cls, *args, **kwds)
+ if '_root' in kwds and kwds['_root'] is True:
+ return self
+ raise TypeError("Cannot instantiate %r" % cls)
+
+ def __reduce__(self):
+ return _trim_name(type(self).__name__)
+
+
+class _ForwardRef(_TypingBase):
+ """Internal wrapper to hold a forward reference."""
+
+ __slots__ = ('__forward_arg__', '__forward_code__',
+ '__forward_evaluated__', '__forward_value__')
+
+ def __init__(self, arg):
+ super(_ForwardRef, self).__init__(arg)
+ if not isinstance(arg, basestring):
+ raise TypeError('Forward reference must be a string -- got %r' % (arg,))
+ try:
+ code = compile(arg, '<string>', 'eval')
+ except SyntaxError:
+ raise SyntaxError('Forward reference must be an expression -- got %r' %
+ (arg,))
+ self.__forward_arg__ = arg
+ self.__forward_code__ = code
+ self.__forward_evaluated__ = False
+ self.__forward_value__ = None
+
+ def _eval_type(self, globalns, localns):
+ if not self.__forward_evaluated__ or localns is not globalns:
+ if globalns is None and localns is None:
+ globalns = localns = {}
+ elif globalns is None:
+ globalns = localns
+ elif localns is None:
+ localns = globalns
+ self.__forward_value__ = _type_check(
+ eval(self.__forward_code__, globalns, localns),
+ "Forward references must evaluate to types.")
+ self.__forward_evaluated__ = True
+ return self.__forward_value__
+
+ def __eq__(self, other):
+ if not isinstance(other, _ForwardRef):
+ return NotImplemented
+ return (self.__forward_arg__ == other.__forward_arg__ and
+ self.__forward_value__ == other.__forward_value__)
+
+ def __hash__(self):
+ return hash((self.__forward_arg__, self.__forward_value__))
+
+ def __instancecheck__(self, obj):
+ raise TypeError("Forward references cannot be used with isinstance().")
+
+ def __subclasscheck__(self, cls):
+ raise TypeError("Forward references cannot be used with issubclass().")
+
+ def __repr__(self):
+ return '_ForwardRef(%r)' % (self.__forward_arg__,)
+
+
+class _TypeAlias(_TypingBase):
+ """Internal helper class for defining generic variants of concrete types.
+
+ Note that this is not a type; let's call it a pseudo-type. It cannot
+ be used in instance and subclass checks in parameterized form, i.e.
+ ``isinstance(42, Match[str])`` raises ``TypeError`` instead of returning
+ ``False``.
+ """
+
+ __slots__ = ('name', 'type_var', 'impl_type', 'type_checker')
+
+ def __init__(self, name, type_var, impl_type, type_checker):
+ """Initializer.
+
+ Args:
+ name: The name, e.g. 'Pattern'.
+ type_var: The type parameter, e.g. AnyStr, or the
+ specific type, e.g. str.
+ impl_type: The implementation type.
+ type_checker: Function that takes an impl_type instance.
+ and returns a value that should be a type_var instance.
+ """
+ assert isinstance(name, basestring), repr(name)
+ assert isinstance(impl_type, type), repr(impl_type)
+ assert not isinstance(impl_type, TypingMeta), repr(impl_type)
+ assert isinstance(type_var, (type, _TypingBase)), repr(type_var)
+ self.name = name
+ self.type_var = type_var
+ self.impl_type = impl_type
+ self.type_checker = type_checker
+
+ def __repr__(self):
+ return "%s[%s]" % (self.name, _type_repr(self.type_var))
+
+ def __getitem__(self, parameter):
+ if not isinstance(self.type_var, TypeVar):
+ raise TypeError("%s cannot be further parameterized." % self)
+ if self.type_var.__constraints__ and isinstance(parameter, type):
+ if not issubclass(parameter, self.type_var.__constraints__):
+ raise TypeError("%s is not a valid substitution for %s." %
+ (parameter, self.type_var))
+ if isinstance(parameter, TypeVar) and parameter is not self.type_var:
+ raise TypeError("%s cannot be re-parameterized." % self)
+ return self.__class__(self.name, parameter,
+ self.impl_type, self.type_checker)
+
+ def __eq__(self, other):
+ if not isinstance(other, _TypeAlias):
+ return NotImplemented
+ return self.name == other.name and self.type_var == other.type_var
+
+ def __hash__(self):
+ return hash((self.name, self.type_var))
+
+ def __instancecheck__(self, obj):
+ if not isinstance(self.type_var, TypeVar):
+ raise TypeError("Parameterized type aliases cannot be used "
+ "with isinstance().")
+ return isinstance(obj, self.impl_type)
+
+ def __subclasscheck__(self, cls):
+ if not isinstance(self.type_var, TypeVar):
+ raise TypeError("Parameterized type aliases cannot be used "
+ "with issubclass().")
+ return issubclass(cls, self.impl_type)
+
+
+def _get_type_vars(types, tvars):
+ for t in types:
+ if isinstance(t, TypingMeta) or isinstance(t, _TypingBase):
+ t._get_type_vars(tvars)
+
+
+def _type_vars(types):
+ tvars = []
+ _get_type_vars(types, tvars)
+ return tuple(tvars)
+
+
+def _eval_type(t, globalns, localns):
+ if isinstance(t, TypingMeta) or isinstance(t, _TypingBase):
+ return t._eval_type(globalns, localns)
+ return t
+
+
+def _type_check(arg, msg):
+ """Check that the argument is a type, and return it (internal helper).
+
+ As a special case, accept None and return type(None) instead.
+ Also, _TypeAlias instances (e.g. Match, Pattern) are acceptable.
+
+ The msg argument is a human-readable error message, e.g.
+
+ "Union[arg, ...]: arg should be a type."
+
+ We append the repr() of the actual value (truncated to 100 chars).
+ """
+ if arg is None:
+ return type(None)
+ if isinstance(arg, basestring):
+ arg = _ForwardRef(arg)
+ if (
+ isinstance(arg, _TypingBase) and type(arg).__name__ == '_ClassVar' or
+ not isinstance(arg, (type, _TypingBase)) and not callable(arg)
+ ):
+ raise TypeError(msg + " Got %.100r." % (arg,))
+ # Bare Union etc. are not valid as type arguments
+ if (
+ type(arg).__name__ in ('_Union', '_Optional') and
+ not getattr(arg, '__origin__', None) or
+ isinstance(arg, TypingMeta) and arg._gorg in (Generic, _Protocol)
+ ):
+ raise TypeError("Plain %s is not valid as type argument" % arg)
+ return arg
+
+
+def _type_repr(obj):
+ """Return the repr() of an object, special-casing types (internal helper).
+
+ If obj is a type, we return a shorter version than the default
+ type.__repr__, based on the module and qualified name, which is
+ typically enough to uniquely identify a type. For everything
+ else, we fall back on repr(obj).
+ """
+ if isinstance(obj, type) and not isinstance(obj, TypingMeta):
+ if obj.__module__ == '__builtin__':
+ return _qualname(obj)
+ return '%s.%s' % (obj.__module__, _qualname(obj))
+ if obj is Ellipsis:
+ return('...')
+ if isinstance(obj, types.FunctionType):
+ return obj.__name__
+ return repr(obj)
+
+
+class ClassVarMeta(TypingMeta):
+ """Metaclass for _ClassVar"""
+
+ def __new__(cls, name, bases, namespace):
+ cls.assert_no_subclassing(bases)
+ self = super(ClassVarMeta, cls).__new__(cls, name, bases, namespace)
+ return self
+
+
+class _ClassVar(_FinalTypingBase):
+ """Special type construct to mark class variables.
+
+ An annotation wrapped in ClassVar indicates that a given
+ attribute is intended to be used as a class variable and
+ should not be set on instances of that class. Usage::
+
+ class Starship:
+ stats = {} # type: ClassVar[Dict[str, int]] # class variable
+ damage = 10 # type: int # instance variable
+
+ ClassVar accepts only types and cannot be further subscribed.
+
+ Note that ClassVar is not a class itself, and should not
+ be used with isinstance() or issubclass().
+ """
+
+ __metaclass__ = ClassVarMeta
+ __slots__ = ('__type__',)
+
+ def __init__(self, tp=None, _root=False):
+ self.__type__ = tp
+
+ def __getitem__(self, item):
+ cls = type(self)
+ if self.__type__ is None:
+ return cls(_type_check(item,
+ '{} accepts only types.'.format(cls.__name__[1:])),
+ _root=True)
+ raise TypeError('{} cannot be further subscripted'
+ .format(cls.__name__[1:]))
+
+ def _eval_type(self, globalns, localns):
+ return type(self)(_eval_type(self.__type__, globalns, localns),
+ _root=True)
+
+ def __repr__(self):
+ r = super(_ClassVar, self).__repr__()
+ if self.__type__ is not None:
+ r += '[{}]'.format(_type_repr(self.__type__))
+ return r
+
+ def __hash__(self):
+ return hash((type(self).__name__, self.__type__))
+
+ def __eq__(self, other):
+ if not isinstance(other, _ClassVar):
+ return NotImplemented
+ if self.__type__ is not None:
+ return self.__type__ == other.__type__
+ return self is other
+
+
+ClassVar = _ClassVar(_root=True)
+
+
+class AnyMeta(TypingMeta):
+ """Metaclass for Any."""
+
+ def __new__(cls, name, bases, namespace):
+ cls.assert_no_subclassing(bases)
+ self = super(AnyMeta, cls).__new__(cls, name, bases, namespace)
+ return self
+
+
+class _Any(_FinalTypingBase):
+ """Special type indicating an unconstrained type.
+
+ - Any is compatible with every type.
+ - Any assumed to have all methods.
+ - All values assumed to be instances of Any.
+
+ Note that all the above statements are true from the point of view of
+ static type checkers. At runtime, Any should not be used with instance
+ or class checks.
+ """
+ __metaclass__ = AnyMeta
+ __slots__ = ()
+
+ def __instancecheck__(self, obj):
+ raise TypeError("Any cannot be used with isinstance().")
+
+ def __subclasscheck__(self, cls):
+ raise TypeError("Any cannot be used with issubclass().")
+
+
+Any = _Any(_root=True)
+
+
+class NoReturnMeta(TypingMeta):
+ """Metaclass for NoReturn."""
+
+ def __new__(cls, name, bases, namespace):
+ cls.assert_no_subclassing(bases)
+ self = super(NoReturnMeta, cls).__new__(cls, name, bases, namespace)
+ return self
+
+
+class _NoReturn(_FinalTypingBase):
+ """Special type indicating functions that never return.
+ Example::
+
+ from typing import NoReturn
+
+ def stop() -> NoReturn:
+ raise Exception('no way')
+
+ This type is invalid in other positions, e.g., ``List[NoReturn]``
+ will fail in static type checkers.
+ """
+ __metaclass__ = NoReturnMeta
+ __slots__ = ()
+
+ def __instancecheck__(self, obj):
+ raise TypeError("NoReturn cannot be used with isinstance().")
+
+ def __subclasscheck__(self, cls):
+ raise TypeError("NoReturn cannot be used with issubclass().")
+
+
+NoReturn = _NoReturn(_root=True)
+
+
+class TypeVarMeta(TypingMeta):
+ def __new__(cls, name, bases, namespace):
+ cls.assert_no_subclassing(bases)
+ return super(TypeVarMeta, cls).__new__(cls, name, bases, namespace)
+
+
+class TypeVar(_TypingBase):
+ """Type variable.
+
+ Usage::
+
+ T = TypeVar('T') # Can be anything
+ A = TypeVar('A', str, bytes) # Must be str or bytes
+
+ Type variables exist primarily for the benefit of static type
+ checkers. They serve as the parameters for generic types as well
+ as for generic function definitions. See class Generic for more
+ information on generic types. Generic functions work as follows:
+
+ def repeat(x: T, n: int) -> List[T]:
+ '''Return a list containing n references to x.'''
+ return [x]*n
+
+ def longest(x: A, y: A) -> A:
+ '''Return the longest of two strings.'''
+ return x if len(x) >= len(y) else y
+
+ The latter example's signature is essentially the overloading
+ of (str, str) -> str and (bytes, bytes) -> bytes. Also note
+ that if the arguments are instances of some subclass of str,
+ the return type is still plain str.
+
+ At runtime, isinstance(x, T) and issubclass(C, T) will raise TypeError.
+
+ Type variables defined with covariant=True or contravariant=True
+ can be used do declare covariant or contravariant generic types.
+ See PEP 484 for more details. By default generic types are invariant
+ in all type variables.
+
+ Type variables can be introspected. e.g.:
+
+ T.__name__ == 'T'
+ T.__constraints__ == ()
+ T.__covariant__ == False
+ T.__contravariant__ = False
+ A.__constraints__ == (str, bytes)
+ """
+
+ __metaclass__ = TypeVarMeta
+ __slots__ = ('__name__', '__bound__', '__constraints__',
+ '__covariant__', '__contravariant__')
+
+ def __init__(self, name, *constraints, **kwargs):
+ super(TypeVar, self).__init__(name, *constraints, **kwargs)
+ bound = kwargs.get('bound', None)
+ covariant = kwargs.get('covariant', False)
+ contravariant = kwargs.get('contravariant', False)
+ self.__name__ = name
+ if covariant and contravariant:
+ raise ValueError("Bivariant types are not supported.")
+ self.__covariant__ = bool(covariant)
+ self.__contravariant__ = bool(contravariant)
+ if constraints and bound is not None:
+ raise TypeError("Constraints cannot be combined with bound=...")
+ if constraints and len(constraints) == 1:
+ raise TypeError("A single constraint is not allowed")
+ msg = "TypeVar(name, constraint, ...): constraints must be types."
+ self.__constraints__ = tuple(_type_check(t, msg) for t in constraints)
+ if bound:
+ self.__bound__ = _type_check(bound, "Bound must be a type.")
+ else:
+ self.__bound__ = None
+
+ def _get_type_vars(self, tvars):
+ if self not in tvars:
+ tvars.append(self)
+
+ def __repr__(self):
+ if self.__covariant__:
+ prefix = '+'
+ elif self.__contravariant__:
+ prefix = '-'
+ else:
+ prefix = '~'
+ return prefix + self.__name__
+
+ def __instancecheck__(self, instance):
+ raise TypeError("Type variables cannot be used with isinstance().")
+
+ def __subclasscheck__(self, cls):
+ raise TypeError("Type variables cannot be used with issubclass().")
+
+
+# Some unconstrained type variables. These are used by the container types.
+# (These are not for export.)
+T = TypeVar('T') # Any type.
+KT = TypeVar('KT') # Key type.
+VT = TypeVar('VT') # Value type.
+T_co = TypeVar('T_co', covariant=True) # Any type covariant containers.
+V_co = TypeVar('V_co', covariant=True) # Any type covariant containers.
+VT_co = TypeVar('VT_co', covariant=True) # Value type covariant containers.
+T_contra = TypeVar('T_contra', contravariant=True) # Ditto contravariant.
+
+# A useful type variable with constraints. This represents string types.
+# (This one *is* for export!)
+AnyStr = TypeVar('AnyStr', bytes, unicode)
+
+
+def _replace_arg(arg, tvars, args):
+ """An internal helper function: replace arg if it is a type variable
+ found in tvars with corresponding substitution from args or
+ with corresponding substitution sub-tree if arg is a generic type.
+ """
+
+ if tvars is None:
+ tvars = []
+ if hasattr(arg, '_subs_tree') and isinstance(arg, (GenericMeta, _TypingBase)):
+ return arg._subs_tree(tvars, args)
+ if isinstance(arg, TypeVar):
+ for i, tvar in enumerate(tvars):
+ if arg == tvar:
+ return args[i]
+ return arg
+
+
+# Special typing constructs Union, Optional, Generic, Callable and Tuple
+# use three special attributes for internal bookkeeping of generic types:
+# * __parameters__ is a tuple of unique free type parameters of a generic
+# type, for example, Dict[T, T].__parameters__ == (T,);
+# * __origin__ keeps a reference to a type that was subscripted,
+# e.g., Union[T, int].__origin__ == Union;
+# * __args__ is a tuple of all arguments used in subscripting,
+# e.g., Dict[T, int].__args__ == (T, int).
+
+
+def _subs_tree(cls, tvars=None, args=None):
+ """An internal helper function: calculate substitution tree
+ for generic cls after replacing its type parameters with
+ substitutions in tvars -> args (if any).
+ Repeat the same following __origin__'s.
+
+ Return a list of arguments with all possible substitutions
+ performed. Arguments that are generic classes themselves are represented
+ as tuples (so that no new classes are created by this function).
+ For example: _subs_tree(List[Tuple[int, T]][str]) == [(Tuple, int, str)]
+ """
+
+ if cls.__origin__ is None:
+ return cls
+ # Make of chain of origins (i.e. cls -> cls.__origin__)
+ current = cls.__origin__
+ orig_chain = []
+ while current.__origin__ is not None:
+ orig_chain.append(current)
+ current = current.__origin__
+ # Replace type variables in __args__ if asked ...
+ tree_args = []
+ for arg in cls.__args__:
+ tree_args.append(_replace_arg(arg, tvars, args))
+ # ... then continue replacing down the origin chain.
+ for ocls in orig_chain:
+ new_tree_args = []
+ for arg in ocls.__args__:
+ new_tree_args.append(_replace_arg(arg, ocls.__parameters__, tree_args))
+ tree_args = new_tree_args
+ return tree_args
+
+
+def _remove_dups_flatten(parameters):
+ """An internal helper for Union creation and substitution: flatten Union's
+ among parameters, then remove duplicates and strict subclasses.
+ """
+
+ # Flatten out Union[Union[...], ...].
+ params = []
+ for p in parameters:
+ if isinstance(p, _Union) and p.__origin__ is Union:
+ params.extend(p.__args__)
+ elif isinstance(p, tuple) and len(p) > 0 and p[0] is Union:
+ params.extend(p[1:])
+ else:
+ params.append(p)
+ # Weed out strict duplicates, preserving the first of each occurrence.
+ all_params = set(params)
+ if len(all_params) < len(params):
+ new_params = []
+ for t in params:
+ if t in all_params:
+ new_params.append(t)
+ all_params.remove(t)
+ params = new_params
+ assert not all_params, all_params
+ # Weed out subclasses.
+ # E.g. Union[int, Employee, Manager] == Union[int, Employee].
+ # If object is present it will be sole survivor among proper classes.
+ # Never discard type variables.
+ # (In particular, Union[str, AnyStr] != AnyStr.)
+ all_params = set(params)
+ for t1 in params:
+ if not isinstance(t1, type):
+ continue
+ if any(isinstance(t2, type) and issubclass(t1, t2)
+ for t2 in all_params - {t1}
+ if not (isinstance(t2, GenericMeta) and
+ t2.__origin__ is not None)):
+ all_params.remove(t1)
+ return tuple(t for t in params if t in all_params)
+
+
+def _check_generic(cls, parameters):
+ # Check correct count for parameters of a generic cls (internal helper).
+ if not cls.__parameters__:
+ raise TypeError("%s is not a generic class" % repr(cls))
+ alen = len(parameters)
+ elen = len(cls.__parameters__)
+ if alen != elen:
+ raise TypeError("Too %s parameters for %s; actual %s, expected %s" %
+ ("many" if alen > elen else "few", repr(cls), alen, elen))
+
+
+_cleanups = []
+
+
+def _tp_cache(func):
+ maxsize = 128
+ cache = {}
+ _cleanups.append(cache.clear)
+
+ @functools.wraps(func)
+ def inner(*args):
+ key = args
+ try:
+ return cache[key]
+ except TypeError:
+ # Assume it's an unhashable argument.
+ return func(*args)
+ except KeyError:
+ value = func(*args)
+ if len(cache) >= maxsize:
+ # If the cache grows too much, just start over.
+ cache.clear()
+ cache[key] = value
+ return value
+
+ return inner
+
+
+class UnionMeta(TypingMeta):
+ """Metaclass for Union."""
+
+ def __new__(cls, name, bases, namespace):
+ cls.assert_no_subclassing(bases)
+ return super(UnionMeta, cls).__new__(cls, name, bases, namespace)
+
+
+class _Union(_FinalTypingBase):
+ """Union type; Union[X, Y] means either X or Y.
+
+ To define a union, use e.g. Union[int, str]. Details:
+
+ - The arguments must be types and there must be at least one.
+
+ - None as an argument is a special case and is replaced by
+ type(None).
+
+ - Unions of unions are flattened, e.g.::
+
+ Union[Union[int, str], float] == Union[int, str, float]
+
+ - Unions of a single argument vanish, e.g.::
+
+ Union[int] == int # The constructor actually returns int
+
+ - Redundant arguments are skipped, e.g.::
+
+ Union[int, str, int] == Union[int, str]
+
+ - When comparing unions, the argument order is ignored, e.g.::
+
+ Union[int, str] == Union[str, int]
+
+ - When two arguments have a subclass relationship, the least
+ derived argument is kept, e.g.::
+
+ class Employee: pass
+ class Manager(Employee): pass
+ Union[int, Employee, Manager] == Union[int, Employee]
+ Union[Manager, int, Employee] == Union[int, Employee]
+ Union[Employee, Manager] == Employee
+
+ - Similar for object::
+
+ Union[int, object] == object
+
+ - You cannot subclass or instantiate a union.
+
+ - You can use Optional[X] as a shorthand for Union[X, None].
+ """
+
+ __metaclass__ = UnionMeta
+ __slots__ = ('__parameters__', '__args__', '__origin__', '__tree_hash__')
+
+ def __new__(cls, parameters=None, origin=None, *args, **kwds):
+ self = super(_Union, cls).__new__(cls, parameters, origin, *args, **kwds)
+ if origin is None:
+ self.__parameters__ = None
+ self.__args__ = None
+ self.__origin__ = None
+ self.__tree_hash__ = hash(frozenset(('Union',)))
+ return self
+ if not isinstance(parameters, tuple):
+ raise TypeError("Expected parameters=<tuple>")
+ if origin is Union:
+ parameters = _remove_dups_flatten(parameters)
+ # It's not a union if there's only one type left.
+ if len(parameters) == 1:
+ return parameters[0]
+ self.__parameters__ = _type_vars(parameters)
+ self.__args__ = parameters
+ self.__origin__ = origin
+ # Pre-calculate the __hash__ on instantiation.
+ # This improves speed for complex substitutions.
+ subs_tree = self._subs_tree()
+ if isinstance(subs_tree, tuple):
+ self.__tree_hash__ = hash(frozenset(subs_tree))
+ else:
+ self.__tree_hash__ = hash(subs_tree)
+ return self
+
+ def _eval_type(self, globalns, localns):
+ if self.__args__ is None:
+ return self
+ ev_args = tuple(_eval_type(t, globalns, localns) for t in self.__args__)
+ ev_origin = _eval_type(self.__origin__, globalns, localns)
+ if ev_args == self.__args__ and ev_origin == self.__origin__:
+ # Everything is already evaluated.
+ return self
+ return self.__class__(ev_args, ev_origin, _root=True)
+
+ def _get_type_vars(self, tvars):
+ if self.__origin__ and self.__parameters__:
+ _get_type_vars(self.__parameters__, tvars)
+
+ def __repr__(self):
+ if self.__origin__ is None:
+ return super(_Union, self).__repr__()
+ tree = self._subs_tree()
+ if not isinstance(tree, tuple):
+ return repr(tree)
+ return tree[0]._tree_repr(tree)
+
+ def _tree_repr(self, tree):
+ arg_list = []
+ for arg in tree[1:]:
+ if not isinstance(arg, tuple):
+ arg_list.append(_type_repr(arg))
+ else:
+ arg_list.append(arg[0]._tree_repr(arg))
+ return super(_Union, self).__repr__() + '[%s]' % ', '.join(arg_list)
+
+ @_tp_cache
+ def __getitem__(self, parameters):
+ if parameters == ():
+ raise TypeError("Cannot take a Union of no types.")
+ if not isinstance(parameters, tuple):
+ parameters = (parameters,)
+ if self.__origin__ is None:
+ msg = "Union[arg, ...]: each arg must be a type."
+ else:
+ msg = "Parameters to generic types must be types."
+ parameters = tuple(_type_check(p, msg) for p in parameters)
+ if self is not Union:
+ _check_generic(self, parameters)
+ return self.__class__(parameters, origin=self, _root=True)
+
+ def _subs_tree(self, tvars=None, args=None):
+ if self is Union:
+ return Union # Nothing to substitute
+ tree_args = _subs_tree(self, tvars, args)
+ tree_args = _remove_dups_flatten(tree_args)
+ if len(tree_args) == 1:
+ return tree_args[0] # Union of a single type is that type
+ return (Union,) + tree_args
+
+ def __eq__(self, other):
+ if isinstance(other, _Union):
+ return self.__tree_hash__ == other.__tree_hash__
+ elif self is not Union:
+ return self._subs_tree() == other
+ else:
+ return self is other
+
+ def __hash__(self):
+ return self.__tree_hash__
+
+ def __instancecheck__(self, obj):
+ raise TypeError("Unions cannot be used with isinstance().")
+
+ def __subclasscheck__(self, cls):
+ raise TypeError("Unions cannot be used with issubclass().")
+
+
+Union = _Union(_root=True)
+
+
+class OptionalMeta(TypingMeta):
+ """Metaclass for Optional."""
+
+ def __new__(cls, name, bases, namespace):
+ cls.assert_no_subclassing(bases)
+ return super(OptionalMeta, cls).__new__(cls, name, bases, namespace)
+
+
+class _Optional(_FinalTypingBase):
+ """Optional type.
+
+ Optional[X] is equivalent to Union[X, None].
+ """
+
+ __metaclass__ = OptionalMeta
+ __slots__ = ()
+
+ @_tp_cache
+ def __getitem__(self, arg):
+ arg = _type_check(arg, "Optional[t] requires a single type.")
+ return Union[arg, type(None)]
+
+
+Optional = _Optional(_root=True)
+
+
+def _next_in_mro(cls):
+ """Helper for Generic.__new__.
+
+ Returns the class after the last occurrence of Generic or
+ Generic[...] in cls.__mro__.
+ """
+ next_in_mro = object
+ # Look for the last occurrence of Generic or Generic[...].
+ for i, c in enumerate(cls.__mro__[:-1]):
+ if isinstance(c, GenericMeta) and c._gorg is Generic:
+ next_in_mro = cls.__mro__[i + 1]
+ return next_in_mro
+
+
+def _make_subclasshook(cls):
+ """Construct a __subclasshook__ callable that incorporates
+ the associated __extra__ class in subclass checks performed
+ against cls.
+ """
+ if isinstance(cls.__extra__, abc.ABCMeta):
+ # The logic mirrors that of ABCMeta.__subclasscheck__.
+ # Registered classes need not be checked here because
+ # cls and its extra share the same _abc_registry.
+ def __extrahook__(cls, subclass):
+ res = cls.__extra__.__subclasshook__(subclass)
+ if res is not NotImplemented:
+ return res
+ if cls.__extra__ in getattr(subclass, '__mro__', ()):
+ return True
+ for scls in cls.__extra__.__subclasses__():
+ if isinstance(scls, GenericMeta):
+ continue
+ if issubclass(subclass, scls):
+ return True
+ return NotImplemented
+ else:
+ # For non-ABC extras we'll just call issubclass().
+ def __extrahook__(cls, subclass):
+ if cls.__extra__ and issubclass(subclass, cls.__extra__):
+ return True
+ return NotImplemented
+ return classmethod(__extrahook__)
+
+
+class GenericMeta(TypingMeta, abc.ABCMeta):
+ """Metaclass for generic types.
+
+ This is a metaclass for typing.Generic and generic ABCs defined in
+ typing module. User defined subclasses of GenericMeta can override
+ __new__ and invoke super().__new__. Note that GenericMeta.__new__
+ has strict rules on what is allowed in its bases argument:
+ * plain Generic is disallowed in bases;
+ * Generic[...] should appear in bases at most once;
+ * if Generic[...] is present, then it should list all type variables
+ that appear in other bases.
+ In addition, type of all generic bases is erased, e.g., C[int] is
+ stripped to plain C.
+ """
+
+ def __new__(cls, name, bases, namespace,
+ tvars=None, args=None, origin=None, extra=None, orig_bases=None):
+ """Create a new generic class. GenericMeta.__new__ accepts
+ keyword arguments that are used for internal bookkeeping, therefore
+ an override should pass unused keyword arguments to super().
+ """
+ if tvars is not None:
+ # Called from __getitem__() below.
+ assert origin is not None
+ assert all(isinstance(t, TypeVar) for t in tvars), tvars
+ else:
+ # Called from class statement.
+ assert tvars is None, tvars
+ assert args is None, args
+ assert origin is None, origin
+
+ # Get the full set of tvars from the bases.
+ tvars = _type_vars(bases)
+ # Look for Generic[T1, ..., Tn].
+ # If found, tvars must be a subset of it.
+ # If not found, tvars is it.
+ # Also check for and reject plain Generic,
+ # and reject multiple Generic[...].
+ gvars = None
+ for base in bases:
+ if base is Generic:
+ raise TypeError("Cannot inherit from plain Generic")
+ if (isinstance(base, GenericMeta) and
+ base.__origin__ is Generic):
+ if gvars is not None:
+ raise TypeError(
+ "Cannot inherit from Generic[...] multiple types.")
+ gvars = base.__parameters__
+ if gvars is None:
+ gvars = tvars
+ else:
+ tvarset = set(tvars)
+ gvarset = set(gvars)
+ if not tvarset <= gvarset:
+ raise TypeError(
+ "Some type variables (%s) "
+ "are not listed in Generic[%s]" %
+ (", ".join(str(t) for t in tvars if t not in gvarset),
+ ", ".join(str(g) for g in gvars)))
+ tvars = gvars
+
+ initial_bases = bases
+ if extra is None:
+ extra = namespace.get('__extra__')
+ if extra is not None and type(extra) is abc.ABCMeta and extra not in bases:
+ bases = (extra,) + bases
+ bases = tuple(b._gorg if isinstance(b, GenericMeta) else b for b in bases)
+
+ # remove bare Generic from bases if there are other generic bases
+ if any(isinstance(b, GenericMeta) and b is not Generic for b in bases):
+ bases = tuple(b for b in bases if b is not Generic)
+ namespace.update({'__origin__': origin, '__extra__': extra})
+ self = super(GenericMeta, cls).__new__(cls, name, bases, namespace)
+ super(GenericMeta, self).__setattr__('_gorg',
+ self if not origin else origin._gorg)
+
+ self.__parameters__ = tvars
+ # Be prepared that GenericMeta will be subclassed by TupleMeta
+ # and CallableMeta, those two allow ..., (), or [] in __args___.
+ self.__args__ = tuple(Ellipsis if a is _TypingEllipsis else
+ () if a is _TypingEmpty else
+ a for a in args) if args else None
+ # Speed hack (https://github.com/python/typing/issues/196).
+ self.__next_in_mro__ = _next_in_mro(self)
+ # Preserve base classes on subclassing (__bases__ are type erased now).
+ if orig_bases is None:
+ self.__orig_bases__ = initial_bases
+
+ # This allows unparameterized generic collections to be used
+ # with issubclass() and isinstance() in the same way as their
+ # collections.abc counterparts (e.g., isinstance([], Iterable)).
+ if (
+ '__subclasshook__' not in namespace and extra or
+ # allow overriding
+ getattr(self.__subclasshook__, '__name__', '') == '__extrahook__'
+ ):
+ self.__subclasshook__ = _make_subclasshook(self)
+
+ if origin and hasattr(origin, '__qualname__'): # Fix for Python 3.2.
+ self.__qualname__ = origin.__qualname__
+ self.__tree_hash__ = (hash(self._subs_tree()) if origin else
+ super(GenericMeta, self).__hash__())
+ return self
+
+ def __init__(self, *args, **kwargs):
+ super(GenericMeta, self).__init__(*args, **kwargs)
+ if isinstance(self.__extra__, abc.ABCMeta):
+ self._abc_registry = self.__extra__._abc_registry
+ self._abc_cache = self.__extra__._abc_cache
+ elif self.__origin__ is not None:
+ self._abc_registry = self.__origin__._abc_registry
+ self._abc_cache = self.__origin__._abc_cache
+
+ # _abc_negative_cache and _abc_negative_cache_version
+ # realized as descriptors, since GenClass[t1, t2, ...] always
+ # share subclass info with GenClass.
+ # This is an important memory optimization.
+ @property
+ def _abc_negative_cache(self):
+ if isinstance(self.__extra__, abc.ABCMeta):
+ return self.__extra__._abc_negative_cache
+ return self._gorg._abc_generic_negative_cache
+
+ @_abc_negative_cache.setter
+ def _abc_negative_cache(self, value):
+ if self.__origin__ is None:
+ if isinstance(self.__extra__, abc.ABCMeta):
+ self.__extra__._abc_negative_cache = value
+ else:
+ self._abc_generic_negative_cache = value
+
+ @property
+ def _abc_negative_cache_version(self):
+ if isinstance(self.__extra__, abc.ABCMeta):
+ return self.__extra__._abc_negative_cache_version
+ return self._gorg._abc_generic_negative_cache_version
+
+ @_abc_negative_cache_version.setter
+ def _abc_negative_cache_version(self, value):
+ if self.__origin__ is None:
+ if isinstance(self.__extra__, abc.ABCMeta):
+ self.__extra__._abc_negative_cache_version = value
+ else:
+ self._abc_generic_negative_cache_version = value
+
+ def _get_type_vars(self, tvars):
+ if self.__origin__ and self.__parameters__:
+ _get_type_vars(self.__parameters__, tvars)
+
+ def _eval_type(self, globalns, localns):
+ ev_origin = (self.__origin__._eval_type(globalns, localns)
+ if self.__origin__ else None)
+ ev_args = tuple(_eval_type(a, globalns, localns) for a
+ in self.__args__) if self.__args__ else None
+ if ev_origin == self.__origin__ and ev_args == self.__args__:
+ return self
+ return self.__class__(self.__name__,
+ self.__bases__,
+ dict(self.__dict__),
+ tvars=_type_vars(ev_args) if ev_args else None,
+ args=ev_args,
+ origin=ev_origin,
+ extra=self.__extra__,
+ orig_bases=self.__orig_bases__)
+
+ def __repr__(self):
+ if self.__origin__ is None:
+ return super(GenericMeta, self).__repr__()
+ return self._tree_repr(self._subs_tree())
+
+ def _tree_repr(self, tree):
+ arg_list = []
+ for arg in tree[1:]:
+ if arg == ():
+ arg_list.append('()')
+ elif not isinstance(arg, tuple):
+ arg_list.append(_type_repr(arg))
+ else:
+ arg_list.append(arg[0]._tree_repr(arg))
+ return super(GenericMeta, self).__repr__() + '[%s]' % ', '.join(arg_list)
+
+ def _subs_tree(self, tvars=None, args=None):
+ if self.__origin__ is None:
+ return self
+ tree_args = _subs_tree(self, tvars, args)
+ return (self._gorg,) + tuple(tree_args)
+
+ def __eq__(self, other):
+ if not isinstance(other, GenericMeta):
+ return NotImplemented
+ if self.__origin__ is None or other.__origin__ is None:
+ return self is other
+ return self.__tree_hash__ == other.__tree_hash__
+
+ def __hash__(self):
+ return self.__tree_hash__
+
+ @_tp_cache
+ def __getitem__(self, params):
+ if not isinstance(params, tuple):
+ params = (params,)
+ if not params and self._gorg is not Tuple:
+ raise TypeError(
+ "Parameter list to %s[...] cannot be empty" % _qualname(self))
+ msg = "Parameters to generic types must be types."
+ params = tuple(_type_check(p, msg) for p in params)
+ if self is Generic:
+ # Generic can only be subscripted with unique type variables.
+ if not all(isinstance(p, TypeVar) for p in params):
+ raise TypeError(
+ "Parameters to Generic[...] must all be type variables")
+ if len(set(params)) != len(params):
+ raise TypeError(
+ "Parameters to Generic[...] must all be unique")
+ tvars = params
+ args = params
+ elif self in (Tuple, Callable):
+ tvars = _type_vars(params)
+ args = params
+ elif self is _Protocol:
+ # _Protocol is internal, don't check anything.
+ tvars = params
+ args = params
+ elif self.__origin__ in (Generic, _Protocol):
+ # Can't subscript Generic[...] or _Protocol[...].
+ raise TypeError("Cannot subscript already-subscripted %s" %
+ repr(self))
+ else:
+ # Subscripting a regular Generic subclass.
+ _check_generic(self, params)
+ tvars = _type_vars(params)
+ args = params
+
+ prepend = (self,) if self.__origin__ is None else ()
+ return self.__class__(self.__name__,
+ prepend + self.__bases__,
+ dict(self.__dict__),
+ tvars=tvars,
+ args=args,
+ origin=self,
+ extra=self.__extra__,
+ orig_bases=self.__orig_bases__)
+
+ def __subclasscheck__(self, cls):
+ if self.__origin__ is not None:
+ # This should only be modules within the standard
+ # library. singledispatch is the only exception, because
+ # it's a Python 2 backport of functools.singledispatch.
+ if sys._getframe(1).f_globals['__name__'] not in ['abc', 'functools',
+ 'singledispatch']:
+ raise TypeError("Parameterized generics cannot be used with class "
+ "or instance checks")
+ return False
+ if self is Generic:
+ raise TypeError("Class %r cannot be used with class "
+ "or instance checks" % self)
+ return super(GenericMeta, self).__subclasscheck__(cls)
+
+ def __instancecheck__(self, instance):
+ # Since we extend ABC.__subclasscheck__ and
+ # ABC.__instancecheck__ inlines the cache checking done by the
+ # latter, we must extend __instancecheck__ too. For simplicity
+ # we just skip the cache check -- instance checks for generic
+ # classes are supposed to be rare anyways.
+ if not isinstance(instance, type):
+ return issubclass(instance.__class__, self)
+ return False
+
+ def __setattr__(self, attr, value):
+ # We consider all the subscripted genrics as proxies for original class
+ if (
+ attr.startswith('__') and attr.endswith('__') or
+ attr.startswith('_abc_')
+ ):
+ super(GenericMeta, self).__setattr__(attr, value)
+ else:
+ super(GenericMeta, self._gorg).__setattr__(attr, value)
+
+
+def _copy_generic(self):
+ """Hack to work around https://bugs.python.org/issue11480 on Python 2"""
+ return self.__class__(self.__name__, self.__bases__, dict(self.__dict__),
+ self.__parameters__, self.__args__, self.__origin__,
+ self.__extra__, self.__orig_bases__)
+
+
+copy._copy_dispatch[GenericMeta] = _copy_generic
+
+
+# Prevent checks for Generic to crash when defining Generic.
+Generic = None
+
+
+def _generic_new(base_cls, cls, *args, **kwds):
+ # Assure type is erased on instantiation,
+ # but attempt to store it in __orig_class__
+ if cls.__origin__ is None:
+ if (base_cls.__new__ is object.__new__ and
+ cls.__init__ is not object.__init__):
+ return base_cls.__new__(cls)
+ else:
+ return base_cls.__new__(cls, *args, **kwds)
+ else:
+ origin = cls._gorg
+ if (base_cls.__new__ is object.__new__ and
+ cls.__init__ is not object.__init__):
+ obj = base_cls.__new__(origin)
+ else:
+ obj = base_cls.__new__(origin, *args, **kwds)
+ try:
+ obj.__orig_class__ = cls
+ except AttributeError:
+ pass
+ obj.__init__(*args, **kwds)
+ return obj
+
+
+class Generic(object):
+ """Abstract base class for generic types.
+
+ A generic type is typically declared by inheriting from
+ this class parameterized with one or more type variables.
+ For example, a generic mapping type might be defined as::
+
+ class Mapping(Generic[KT, VT]):
+ def __getitem__(self, key: KT) -> VT:
+ ...
+ # Etc.
+
+ This class can then be used as follows::
+
+ def lookup_name(mapping: Mapping[KT, VT], key: KT, default: VT) -> VT:
+ try:
+ return mapping[key]
+ except KeyError:
+ return default
+ """
+
+ __metaclass__ = GenericMeta
+ __slots__ = ()
+
+ def __new__(cls, *args, **kwds):
+ if cls._gorg is Generic:
+ raise TypeError("Type Generic cannot be instantiated; "
+ "it can be used only as a base class")
+ return _generic_new(cls.__next_in_mro__, cls, *args, **kwds)
+
+
+class _TypingEmpty(object):
+ """Internal placeholder for () or []. Used by TupleMeta and CallableMeta
+ to allow empty list/tuple in specific places, without allowing them
+ to sneak in where prohibited.
+ """
+
+
+class _TypingEllipsis(object):
+ """Internal placeholder for ... (ellipsis)."""
+
+
+class TupleMeta(GenericMeta):
+ """Metaclass for Tuple (internal)."""
+
+ @_tp_cache
+ def __getitem__(self, parameters):
+ if self.__origin__ is not None or self._gorg is not Tuple:
+ # Normal generic rules apply if this is not the first subscription
+ # or a subscription of a subclass.
+ return super(TupleMeta, self).__getitem__(parameters)
+ if parameters == ():
+ return super(TupleMeta, self).__getitem__((_TypingEmpty,))
+ if not isinstance(parameters, tuple):
+ parameters = (parameters,)
+ if len(parameters) == 2 and parameters[1] is Ellipsis:
+ msg = "Tuple[t, ...]: t must be a type."
+ p = _type_check(parameters[0], msg)
+ return super(TupleMeta, self).__getitem__((p, _TypingEllipsis))
+ msg = "Tuple[t0, t1, ...]: each t must be a type."
+ parameters = tuple(_type_check(p, msg) for p in parameters)
+ return super(TupleMeta, self).__getitem__(parameters)
+
+ def __instancecheck__(self, obj):
+ if self.__args__ is None:
+ return isinstance(obj, tuple)
+ raise TypeError("Parameterized Tuple cannot be used "
+ "with isinstance().")
+
+ def __subclasscheck__(self, cls):
+ if self.__args__ is None:
+ return issubclass(cls, tuple)
+ raise TypeError("Parameterized Tuple cannot be used "
+ "with issubclass().")
+
+
+copy._copy_dispatch[TupleMeta] = _copy_generic
+
+
+class Tuple(tuple):
+ """Tuple type; Tuple[X, Y] is the cross-product type of X and Y.
+
+ Example: Tuple[T1, T2] is a tuple of two elements corresponding
+ to type variables T1 and T2. Tuple[int, float, str] is a tuple
+ of an int, a float and a string.
+
+ To specify a variable-length tuple of homogeneous type, use Tuple[T, ...].
+ """
+
+ __metaclass__ = TupleMeta
+ __extra__ = tuple
+ __slots__ = ()
+
+ def __new__(cls, *args, **kwds):
+ if cls._gorg is Tuple:
+ raise TypeError("Type Tuple cannot be instantiated; "
+ "use tuple() instead")
+ return _generic_new(tuple, cls, *args, **kwds)
+
+
+class CallableMeta(GenericMeta):
+ """ Metaclass for Callable."""
+
+ def __repr__(self):
+ if self.__origin__ is None:
+ return super(CallableMeta, self).__repr__()
+ return self._tree_repr(self._subs_tree())
+
+ def _tree_repr(self, tree):
+ if self._gorg is not Callable:
+ return super(CallableMeta, self)._tree_repr(tree)
+ # For actual Callable (not its subclass) we override
+ # super(CallableMeta, self)._tree_repr() for nice formatting.
+ arg_list = []
+ for arg in tree[1:]:
+ if not isinstance(arg, tuple):
+ arg_list.append(_type_repr(arg))
+ else:
+ arg_list.append(arg[0]._tree_repr(arg))
+ if arg_list[0] == '...':
+ return repr(tree[0]) + '[..., %s]' % arg_list[1]
+ return (repr(tree[0]) +
+ '[[%s], %s]' % (', '.join(arg_list[:-1]), arg_list[-1]))
+
+ def __getitem__(self, parameters):
+ """A thin wrapper around __getitem_inner__ to provide the latter
+ with hashable arguments to improve speed.
+ """
+
+ if self.__origin__ is not None or self._gorg is not Callable:
+ return super(CallableMeta, self).__getitem__(parameters)
+ if not isinstance(parameters, tuple) or len(parameters) != 2:
+ raise TypeError("Callable must be used as "
+ "Callable[[arg, ...], result].")
+ args, result = parameters
+ if args is Ellipsis:
+ parameters = (Ellipsis, result)
+ else:
+ if not isinstance(args, list):
+ raise TypeError("Callable[args, result]: args must be a list."
+ " Got %.100r." % (args,))
+ parameters = (tuple(args), result)
+ return self.__getitem_inner__(parameters)
+
+ @_tp_cache
+ def __getitem_inner__(self, parameters):
+ args, result = parameters
+ msg = "Callable[args, result]: result must be a type."
+ result = _type_check(result, msg)
+ if args is Ellipsis:
+ return super(CallableMeta, self).__getitem__((_TypingEllipsis, result))
+ msg = "Callable[[arg, ...], result]: each arg must be a type."
+ args = tuple(_type_check(arg, msg) for arg in args)
+ parameters = args + (result,)
+ return super(CallableMeta, self).__getitem__(parameters)
+
+
+copy._copy_dispatch[CallableMeta] = _copy_generic
+
+
+class Callable(object):
+ """Callable type; Callable[[int], str] is a function of (int) -> str.
+
+ The subscription syntax must always be used with exactly two
+ values: the argument list and the return type. The argument list
+ must be a list of types or ellipsis; the return type must be a single type.
+
+ There is no syntax to indicate optional or keyword arguments,
+ such function types are rarely used as callback types.
+ """
+
+ __metaclass__ = CallableMeta
+ __extra__ = collections_abc.Callable
+ __slots__ = ()
+
+ def __new__(cls, *args, **kwds):
+ if cls._gorg is Callable:
+ raise TypeError("Type Callable cannot be instantiated; "
+ "use a non-abstract subclass instead")
+ return _generic_new(cls.__next_in_mro__, cls, *args, **kwds)
+
+
+def cast(typ, val):
+ """Cast a value to a type.
+
+ This returns the value unchanged. To the type checker this
+ signals that the return value has the designated type, but at
+ runtime we intentionally don't check anything (we want this
+ to be as fast as possible).
+ """
+ return val
+
+
+def _get_defaults(func):
+ """Internal helper to extract the default arguments, by name."""
+ code = func.__code__
+ pos_count = code.co_argcount
+ arg_names = code.co_varnames
+ arg_names = arg_names[:pos_count]
+ defaults = func.__defaults__ or ()
+ kwdefaults = func.__kwdefaults__
+ res = dict(kwdefaults) if kwdefaults else {}
+ pos_offset = pos_count - len(defaults)
+ for name, value in zip(arg_names[pos_offset:], defaults):
+ assert name not in res
+ res[name] = value
+ return res
+
+
+def get_type_hints(obj, globalns=None, localns=None):
+ """In Python 2 this is not supported and always returns None."""
+ return None
+
+
+def no_type_check(arg):
+ """Decorator to indicate that annotations are not type hints.
+
+ The argument must be a class or function; if it is a class, it
+ applies recursively to all methods and classes defined in that class
+ (but not to methods defined in its superclasses or subclasses).
+
+ This mutates the function(s) or class(es) in place.
+ """
+ if isinstance(arg, type):
+ arg_attrs = arg.__dict__.copy()
+ for attr, val in arg.__dict__.items():
+ if val in arg.__bases__ + (arg,):
+ arg_attrs.pop(attr)
+ for obj in arg_attrs.values():
+ if isinstance(obj, types.FunctionType):
+ obj.__no_type_check__ = True
+ if isinstance(obj, type):
+ no_type_check(obj)
+ try:
+ arg.__no_type_check__ = True
+ except TypeError: # built-in classes
+ pass
+ return arg
+
+
+def no_type_check_decorator(decorator):
+ """Decorator to give another decorator the @no_type_check effect.
+
+ This wraps the decorator with something that wraps the decorated
+ function in @no_type_check.
+ """
+
+ @functools.wraps(decorator)
+ def wrapped_decorator(*args, **kwds):
+ func = decorator(*args, **kwds)
+ func = no_type_check(func)
+ return func
+
+ return wrapped_decorator
+
+
+def _overload_dummy(*args, **kwds):
+ """Helper for @overload to raise when called."""
+ raise NotImplementedError(
+ "You should not call an overloaded function. "
+ "A series of @overload-decorated functions "
+ "outside a stub module should always be followed "
+ "by an implementation that is not @overload-ed.")
+
+
+def overload(func):
+ """Decorator for overloaded functions/methods.
+
+ In a stub file, place two or more stub definitions for the same
+ function in a row, each decorated with @overload. For example:
+
+ @overload
+ def utf8(value: None) -> None: ...
+ @overload
+ def utf8(value: bytes) -> bytes: ...
+ @overload
+ def utf8(value: str) -> bytes: ...
+
+ In a non-stub file (i.e. a regular .py file), do the same but
+ follow it with an implementation. The implementation should *not*
+ be decorated with @overload. For example:
+
+ @overload
+ def utf8(value: None) -> None: ...
+ @overload
+ def utf8(value: bytes) -> bytes: ...
+ @overload
+ def utf8(value: str) -> bytes: ...
+ def utf8(value):
+ # implementation goes here
+ """
+ return _overload_dummy
+
+
+class _ProtocolMeta(GenericMeta):
+ """Internal metaclass for _Protocol.
+
+ This exists so _Protocol classes can be generic without deriving
+ from Generic.
+ """
+
+ def __instancecheck__(self, obj):
+ if _Protocol not in self.__bases__:
+ return super(_ProtocolMeta, self).__instancecheck__(obj)
+ raise TypeError("Protocols cannot be used with isinstance().")
+
+ def __subclasscheck__(self, cls):
+ if not self._is_protocol:
+ # No structural checks since this isn't a protocol.
+ return NotImplemented
+
+ if self is _Protocol:
+ # Every class is a subclass of the empty protocol.
+ return True
+
+ # Find all attributes defined in the protocol.
+ attrs = self._get_protocol_attrs()
+
+ for attr in attrs:
+ if not any(attr in d.__dict__ for d in cls.__mro__):
+ return False
+ return True
+
+ def _get_protocol_attrs(self):
+ # Get all Protocol base classes.
+ protocol_bases = []
+ for c in self.__mro__:
+ if getattr(c, '_is_protocol', False) and c.__name__ != '_Protocol':
+ protocol_bases.append(c)
+
+ # Get attributes included in protocol.
+ attrs = set()
+ for base in protocol_bases:
+ for attr in base.__dict__.keys():
+ # Include attributes not defined in any non-protocol bases.
+ for c in self.__mro__:
+ if (c is not base and attr in c.__dict__ and
+ not getattr(c, '_is_protocol', False)):
+ break
+ else:
+ if (not attr.startswith('_abc_') and
+ attr != '__abstractmethods__' and
+ attr != '_is_protocol' and
+ attr != '_gorg' and
+ attr != '__dict__' and
+ attr != '__args__' and
+ attr != '__slots__' and
+ attr != '_get_protocol_attrs' and
+ attr != '__next_in_mro__' and
+ attr != '__parameters__' and
+ attr != '__origin__' and
+ attr != '__orig_bases__' and
+ attr != '__extra__' and
+ attr != '__tree_hash__' and
+ attr != '__module__'):
+ attrs.add(attr)
+
+ return attrs
+
+
+class _Protocol(object):
+ """Internal base class for protocol classes.
+
+ This implements a simple-minded structural issubclass check
+ (similar but more general than the one-offs in collections.abc
+ such as Hashable).
+ """
+
+ __metaclass__ = _ProtocolMeta
+ __slots__ = ()
+
+ _is_protocol = True
+
+
+# Various ABCs mimicking those in collections.abc.
+# A few are simply re-exported for completeness.
+
+Hashable = collections_abc.Hashable # Not generic.
+
+
+class Iterable(Generic[T_co]):
+ __slots__ = ()
+ __extra__ = collections_abc.Iterable
+
+
+class Iterator(Iterable[T_co]):
+ __slots__ = ()
+ __extra__ = collections_abc.Iterator
+
+
+class SupportsInt(_Protocol):
+ __slots__ = ()
+
+ @abstractmethod
+ def __int__(self):
+ pass
+
+
+class SupportsFloat(_Protocol):
+ __slots__ = ()
+
+ @abstractmethod
+ def __float__(self):
+ pass
+
+
+class SupportsComplex(_Protocol):
+ __slots__ = ()
+
+ @abstractmethod
+ def __complex__(self):
+ pass
+
+
+class SupportsAbs(_Protocol[T_co]):
+ __slots__ = ()
+
+ @abstractmethod
+ def __abs__(self):
+ pass
+
+
+if hasattr(collections_abc, 'Reversible'):
+ class Reversible(Iterable[T_co]):
+ __slots__ = ()
+ __extra__ = collections_abc.Reversible
+else:
+ class Reversible(_Protocol[T_co]):
+ __slots__ = ()
+
+ @abstractmethod
+ def __reversed__(self):
+ pass
+
+
+Sized = collections_abc.Sized # Not generic.
+
+
+class Container(Generic[T_co]):
+ __slots__ = ()
+ __extra__ = collections_abc.Container
+
+
+# Callable was defined earlier.
+
+
+class AbstractSet(Sized, Iterable[T_co], Container[T_co]):
+ __slots__ = ()
+ __extra__ = collections_abc.Set
+
+
+class MutableSet(AbstractSet[T]):
+ __slots__ = ()
+ __extra__ = collections_abc.MutableSet
+
+
+# NOTE: It is only covariant in the value type.
+class Mapping(Sized, Iterable[KT], Container[KT], Generic[KT, VT_co]):
+ __slots__ = ()
+ __extra__ = collections_abc.Mapping
+
+
+class MutableMapping(Mapping[KT, VT]):
+ __slots__ = ()
+ __extra__ = collections_abc.MutableMapping
+
+
+if hasattr(collections_abc, 'Reversible'):
+ class Sequence(Sized, Reversible[T_co], Container[T_co]):
+ __slots__ = ()
+ __extra__ = collections_abc.Sequence
+else:
+ class Sequence(Sized, Iterable[T_co], Container[T_co]):
+ __slots__ = ()
+ __extra__ = collections_abc.Sequence
+
+
+class MutableSequence(Sequence[T]):
+ __slots__ = ()
+ __extra__ = collections_abc.MutableSequence
+
+
+class ByteString(Sequence[int]):
+ pass
+
+
+ByteString.register(str)
+ByteString.register(bytearray)
+
+
+class List(list, MutableSequence[T]):
+ __slots__ = ()
+ __extra__ = list
+
+ def __new__(cls, *args, **kwds):
+ if cls._gorg is List:
+ raise TypeError("Type List cannot be instantiated; "
+ "use list() instead")
+ return _generic_new(list, cls, *args, **kwds)
+
+
+class Deque(collections.deque, MutableSequence[T]):
+ __slots__ = ()
+ __extra__ = collections.deque
+
+ def __new__(cls, *args, **kwds):
+ if cls._gorg is Deque:
+ return collections.deque(*args, **kwds)
+ return _generic_new(collections.deque, cls, *args, **kwds)
+
+
+class Set(set, MutableSet[T]):
+ __slots__ = ()
+ __extra__ = set
+
+ def __new__(cls, *args, **kwds):
+ if cls._gorg is Set:
+ raise TypeError("Type Set cannot be instantiated; "
+ "use set() instead")
+ return _generic_new(set, cls, *args, **kwds)
+
+
+class FrozenSet(frozenset, AbstractSet[T_co]):
+ __slots__ = ()
+ __extra__ = frozenset
+
+ def __new__(cls, *args, **kwds):
+ if cls._gorg is FrozenSet:
+ raise TypeError("Type FrozenSet cannot be instantiated; "
+ "use frozenset() instead")
+ return _generic_new(frozenset, cls, *args, **kwds)
+
+
+class MappingView(Sized, Iterable[T_co]):
+ __slots__ = ()
+ __extra__ = collections_abc.MappingView
+
+
+class KeysView(MappingView[KT], AbstractSet[KT]):
+ __slots__ = ()
+ __extra__ = collections_abc.KeysView
+
+
+class ItemsView(MappingView[Tuple[KT, VT_co]],
+ AbstractSet[Tuple[KT, VT_co]],
+ Generic[KT, VT_co]):
+ __slots__ = ()
+ __extra__ = collections_abc.ItemsView
+
+
+class ValuesView(MappingView[VT_co]):
+ __slots__ = ()
+ __extra__ = collections_abc.ValuesView
+
+
+class ContextManager(Generic[T_co]):
+ __slots__ = ()
+
+ def __enter__(self):
+ return self
+
+ @abc.abstractmethod
+ def __exit__(self, exc_type, exc_value, traceback):
+ return None
+
+ @classmethod
+ def __subclasshook__(cls, C):
+ if cls is ContextManager:
+ # In Python 3.6+, it is possible to set a method to None to
+ # explicitly indicate that the class does not implement an ABC
+ # (https://bugs.python.org/issue25958), but we do not support
+ # that pattern here because this fallback class is only used
+ # in Python 3.5 and earlier.
+ if (any("__enter__" in B.__dict__ for B in C.__mro__) and
+ any("__exit__" in B.__dict__ for B in C.__mro__)):
+ return True
+ return NotImplemented
+
+
+class Dict(dict, MutableMapping[KT, VT]):
+ __slots__ = ()
+ __extra__ = dict
+
+ def __new__(cls, *args, **kwds):
+ if cls._gorg is Dict:
+ raise TypeError("Type Dict cannot be instantiated; "
+ "use dict() instead")
+ return _generic_new(dict, cls, *args, **kwds)
+
+
+class DefaultDict(collections.defaultdict, MutableMapping[KT, VT]):
+ __slots__ = ()
+ __extra__ = collections.defaultdict
+
+ def __new__(cls, *args, **kwds):
+ if cls._gorg is DefaultDict:
+ return collections.defaultdict(*args, **kwds)
+ return _generic_new(collections.defaultdict, cls, *args, **kwds)
+
+
+class Counter(collections.Counter, Dict[T, int]):
+ __slots__ = ()
+ __extra__ = collections.Counter
+
+ def __new__(cls, *args, **kwds):
+ if cls._gorg is Counter:
+ return collections.Counter(*args, **kwds)
+ return _generic_new(collections.Counter, cls, *args, **kwds)
+
+
+# Determine what base class to use for Generator.
+if hasattr(collections_abc, 'Generator'):
+ # Sufficiently recent versions of 3.5 have a Generator ABC.
+ _G_base = collections_abc.Generator
+else:
+ # Fall back on the exact type.
+ _G_base = types.GeneratorType
+
+
+class Generator(Iterator[T_co], Generic[T_co, T_contra, V_co]):
+ __slots__ = ()
+ __extra__ = _G_base
+
+ def __new__(cls, *args, **kwds):
+ if cls._gorg is Generator:
+ raise TypeError("Type Generator cannot be instantiated; "
+ "create a subclass instead")
+ return _generic_new(_G_base, cls, *args, **kwds)
+
+
+# Internal type variable used for Type[].
+CT_co = TypeVar('CT_co', covariant=True, bound=type)
+
+
+# This is not a real generic class. Don't use outside annotations.
+class Type(Generic[CT_co]):
+ """A special construct usable to annotate class objects.
+
+ For example, suppose we have the following classes::
+
+ class User: ... # Abstract base for User classes
+ class BasicUser(User): ...
+ class ProUser(User): ...
+ class TeamUser(User): ...
+
+ And a function that takes a class argument that's a subclass of
+ User and returns an instance of the corresponding class::
+
+ U = TypeVar('U', bound=User)
+ def new_user(user_class: Type[U]) -> U:
+ user = user_class()
+ # (Here we could write the user object to a database)
+ return user
+
+ joe = new_user(BasicUser)
+
+ At this point the type checker knows that joe has type BasicUser.
+ """
+ __slots__ = ()
+ __extra__ = type
+
+
+def NamedTuple(typename, fields):
+ """Typed version of namedtuple.
+
+ Usage::
+
+ Employee = typing.NamedTuple('Employee', [('name', str), ('id', int)])
+
+ This is equivalent to::
+
+ Employee = collections.namedtuple('Employee', ['name', 'id'])
+
+ The resulting class has one extra attribute: _field_types,
+ giving a dict mapping field names to types. (The field names
+ are in the _fields attribute, which is part of the namedtuple
+ API.)
+ """
+ fields = [(n, t) for n, t in fields]
+ cls = collections.namedtuple(typename, [n for n, t in fields])
+ cls._field_types = dict(fields)
+ # Set the module to the caller's module (otherwise it'd be 'typing').
+ try:
+ cls.__module__ = sys._getframe(1).f_globals.get('__name__', '__main__')
+ except (AttributeError, ValueError):
+ pass
+ return cls
+
+
+def NewType(name, tp):
+ """NewType creates simple unique types with almost zero
+ runtime overhead. NewType(name, tp) is considered a subtype of tp
+ by static type checkers. At runtime, NewType(name, tp) returns
+ a dummy function that simply returns its argument. Usage::
+
+ UserId = NewType('UserId', int)
+
+ def name_by_id(user_id):
+ # type: (UserId) -> str
+ ...
+
+ UserId('user') # Fails type check
+
+ name_by_id(42) # Fails type check
+ name_by_id(UserId(42)) # OK
+
+ num = UserId(5) + 1 # type: int
+ """
+
+ def new_type(x):
+ return x
+
+ # Some versions of Python 2 complain because of making all strings unicode
+ new_type.__name__ = str(name)
+ new_type.__supertype__ = tp
+ return new_type
+
+
+# Python-version-specific alias (Python 2: unicode; Python 3: str)
+Text = unicode
+
+
+# Constant that's True when type checking, but False here.
+TYPE_CHECKING = False
+
+
+class IO(Generic[AnyStr]):
+ """Generic base class for TextIO and BinaryIO.
+
+ This is an abstract, generic version of the return of open().
+
+ NOTE: This does not distinguish between the different possible
+ classes (text vs. binary, read vs. write vs. read/write,
+ append-only, unbuffered). The TextIO and BinaryIO subclasses
+ below capture the distinctions between text vs. binary, which is
+ pervasive in the interface; however we currently do not offer a
+ way to track the other distinctions in the type system.
+ """
+
+ __slots__ = ()
+
+ @abstractproperty
+ def mode(self):
+ pass
+
+ @abstractproperty
+ def name(self):
+ pass
+
+ @abstractmethod
+ def close(self):
+ pass
+
+ @abstractproperty
+ def closed(self):
+ pass
+
+ @abstractmethod
+ def fileno(self):
+ pass
+
+ @abstractmethod
+ def flush(self):
+ pass
+
+ @abstractmethod
+ def isatty(self):
+ pass
+
+ @abstractmethod
+ def read(self, n=-1):
+ pass
+
+ @abstractmethod
+ def readable(self):
+ pass
+
+ @abstractmethod
+ def readline(self, limit=-1):
+ pass
+
+ @abstractmethod
+ def readlines(self, hint=-1):
+ pass
+
+ @abstractmethod
+ def seek(self, offset, whence=0):
+ pass
+
+ @abstractmethod
+ def seekable(self):
+ pass
+
+ @abstractmethod
+ def tell(self):
+ pass
+
+ @abstractmethod
+ def truncate(self, size=None):
+ pass
+
+ @abstractmethod
+ def writable(self):
+ pass
+
+ @abstractmethod
+ def write(self, s):
+ pass
+
+ @abstractmethod
+ def writelines(self, lines):
+ pass
+
+ @abstractmethod
+ def __enter__(self):
+ pass
+
+ @abstractmethod
+ def __exit__(self, type, value, traceback):
+ pass
+
+
+class BinaryIO(IO[bytes]):
+ """Typed version of the return of open() in binary mode."""
+
+ __slots__ = ()
+
+ @abstractmethod
+ def write(self, s):
+ pass
+
+ @abstractmethod
+ def __enter__(self):
+ pass
+
+
+class TextIO(IO[unicode]):
+ """Typed version of the return of open() in text mode."""
+
+ __slots__ = ()
+
+ @abstractproperty
+ def buffer(self):
+ pass
+
+ @abstractproperty
+ def encoding(self):
+ pass
+
+ @abstractproperty
+ def errors(self):
+ pass
+
+ @abstractproperty
+ def line_buffering(self):
+ pass
+
+ @abstractproperty
+ def newlines(self):
+ pass
+
+ @abstractmethod
+ def __enter__(self):
+ pass
+
+
+class io(object):
+ """Wrapper namespace for IO generic classes."""
+
+ __all__ = ['IO', 'TextIO', 'BinaryIO']
+ IO = IO
+ TextIO = TextIO
+ BinaryIO = BinaryIO
+
+
+io.__name__ = __name__ + b'.io'
+sys.modules[io.__name__] = io
+
+
+Pattern = _TypeAlias('Pattern', AnyStr, type(stdlib_re.compile('')),
+ lambda p: p.pattern)
+Match = _TypeAlias('Match', AnyStr, type(stdlib_re.match('', '')),
+ lambda m: m.re.pattern)
+
+
+class re(object):
+ """Wrapper namespace for re type aliases."""
+
+ __all__ = ['Pattern', 'Match']
+ Pattern = Pattern
+ Match = Match
+
+
+re.__name__ = __name__ + b'.re'
+sys.modules[re.__name__] = re