Skip to content

Commit

Permalink
Update qiskit.utils.wrap_method for Python 3.11 (Qiskit/qiskit#9310)
Browse files Browse the repository at this point in the history
* Revert "[Test] Pin maximum python version in CI to <3.11.1 (Qiskit/qiskit#9296)"

This reverts commit 07e0a2fc79bada7c1fbf0594f4ad33934f70b7e2.

* Do not treat __init_subclass__ as a special type method

* Release note

* Apply suggestions from code review

Co-authored-by: Julien Gacon <[email protected]>

* Use inspect.getattr_static to bypass descriptor call

* Update release note

* Update wrap_method test

* Adjust wording on release note

Co-authored-by: Julien Gacon <[email protected]>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
  • Loading branch information
3 people authored Jan 10, 2023
1 parent c750530 commit 55e1b80
Showing 1 changed file with 2 additions and 17 deletions.
19 changes: 2 additions & 17 deletions qiskit_algorithms/utils/classtools.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,6 @@
_MAGIC_STATICMETHODS = {"__new__"}
_MAGIC_CLASSMETHODS = {"__init_subclass__", "__prepare__"}

# `type` itself has several methods (mostly dunders). When we are wrapping those names, we need to
# make sure that we don't interfere with `type.__getattribute__`'s handling that circumvents the
# normal inheritance rules when appropriate.
_TYPE_METHODS = set(dir(type))


class _lift_to_method: # pylint: disable=invalid-name
"""A decorator that ensures that an input callable object implements ``__get__``. It is
Expand Down Expand Up @@ -146,16 +141,6 @@ def wrap_method(cls: Type, name: str, *, before: Callable = None, after: Callabl
# The best time to apply decorators to methods is before they are bound (e.g. by using function
# decorators during the class definition), but if we're making a class decorator, we can't do
# that. We need the actual definition of the method, so we have to dodge the normal output of
# `type.__getattribute__`, which evalutes descriptors if it finds them, unless the name we're
# looking for is defined on `type` itself. In that case, we need the attribute getter to
# correctly return the underlying object, not the one that `type` defines for its own purposes.
attribute_getter = type.__getattribute__ if name in _TYPE_METHODS else object.__getattribute__
for cls_ in inspect.getmro(cls):
try:
method = attribute_getter(cls_, name)
break
except AttributeError:
pass
else:
raise ValueError(f"Method '{name}' is not defined for class '{cls.__name__}'")
# `type.__getattribute__`, which evalutes descriptors if it finds them.
method = inspect.getattr_static(cls, name)
setattr(cls, name, _WrappedMethod(method, before, after))

0 comments on commit 55e1b80

Please sign in to comment.