Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
open-source
logilab-common
Commits
f78ed63ca3b5
Commit
804c40f2
authored
Aug 26, 2020
by
Laurent Peuch
Browse files
fix(deprecation): stacked decorators breaks getting the real callable __name__ attribute
parent
de5ae7f7b977
Pipeline
#12605
failed with stages
in 3 minutes and 21 seconds
Changes
2
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
logilab/common/deprecation.py
View file @
f78ed63c
...
@@ -27,6 +27,24 @@ from typing import Any, Callable, Dict, Optional
...
@@ -27,6 +27,24 @@ from typing import Any, Callable, Dict, Optional
from
typing_extensions
import
Protocol
from
typing_extensions
import
Protocol
def
get_real__name__
(
some_callable
:
Callable
)
->
str
:
"""
This is another super edge magic case which is needed because we uses
lazy_wraps because of logilab.common.modutils.LazyObject and because
__name__ has special behavior and doesn't work like a normal attribute and
that __getattribute__ of lazy_wraps is bypassed.
Therefor, to get the real callable name when several lazy_wrapped
decorator are used we need to travers the __wrapped__ attributes chain.
"""
targeted_callable
=
some_callable
while
hasattr
(
targeted_callable
,
"__wrapped__"
):
targeted_callable
=
targeted_callable
.
__wrapped__
# type: ignore
return
targeted_callable
.
__name__
def
lazy_wraps
(
wrapped
:
Callable
)
->
Callable
:
def
lazy_wraps
(
wrapped
:
Callable
)
->
Callable
:
"""
"""
This is the equivalent of the @wraps decorator of functools except it won't
This is the equivalent of the @wraps decorator of functools except it won't
...
@@ -151,8 +169,8 @@ def callable_renamed(
...
@@ -151,8 +169,8 @@ def callable_renamed(
def
wrapped
(
*
args
,
**
kwargs
):
def
wrapped
(
*
args
,
**
kwargs
):
send_warning
(
send_warning
(
(
(
f
"
{
old_name
}
has been renamed and is deprecated, uses
{
new_function
.
__name__
}
"
f
"
{
old_name
}
has been renamed and is deprecated, uses "
f
"instead"
f
"
{
get_real__name__
(
new_function
)
}
instead"
),
),
stacklevel
=
3
,
stacklevel
=
3
,
version
=
version
,
version
=
version
,
...
@@ -186,7 +204,7 @@ def argument_removed(old_argument_name: str, version: Optional[str] = None) -> C
...
@@ -186,7 +204,7 @@ def argument_removed(old_argument_name: str, version: Optional[str] = None) -> C
def
check_kwargs
(
*
args
,
**
kwargs
):
def
check_kwargs
(
*
args
,
**
kwargs
):
if
old_argument_name
in
kwargs
:
if
old_argument_name
in
kwargs
:
send_warning
(
send_warning
(
f
"argument
{
old_argument_name
}
of callable
{
func
.
__name__
}
has been "
f
"argument
{
old_argument_name
}
of callable
{
get_real
__name__
(
func
)
}
has been "
f
"removed and is deprecated"
,
f
"removed and is deprecated"
,
stacklevel
=
3
,
stacklevel
=
3
,
version
=
version
,
version
=
version
,
...
@@ -215,7 +233,7 @@ def callable_deprecated(
...
@@ -215,7 +233,7 @@ def callable_deprecated(
def
wrapped
(
*
args
,
**
kwargs
)
->
Callable
:
def
wrapped
(
*
args
,
**
kwargs
)
->
Callable
:
message
:
str
=
reason
or
'The function "%s" is deprecated'
message
:
str
=
reason
or
'The function "%s" is deprecated'
if
"%s"
in
message
:
if
"%s"
in
message
:
message
%=
func
.
__name__
message
%=
get_real
__name__
(
func
)
send_warning
(
message
,
version
,
stacklevel
+
1
,
module_name
=
func
.
__module__
)
send_warning
(
message
,
version
,
stacklevel
+
1
,
module_name
=
func
.
__module__
)
return
func
(
*
args
,
**
kwargs
)
return
func
(
*
args
,
**
kwargs
)
...
@@ -328,14 +346,14 @@ def argument_renamed(old_name: str, new_name: str, version: Optional[str] = None
...
@@ -328,14 +346,14 @@ def argument_renamed(old_name: str, new_name: str, version: Optional[str] = None
def
check_kwargs
(
*
args
,
**
kwargs
)
->
Callable
:
def
check_kwargs
(
*
args
,
**
kwargs
)
->
Callable
:
if
old_name
in
kwargs
and
new_name
in
kwargs
:
if
old_name
in
kwargs
and
new_name
in
kwargs
:
raise
ValueError
(
raise
ValueError
(
f
"argument
{
old_name
}
of callable
{
func
.
__name__
}
has been "
f
"argument
{
old_name
}
of callable
{
get_real
__name__
(
func
)
}
has been "
f
"renamed to
{
new_name
}
but you are both using
{
old_name
}
and "
f
"renamed to
{
new_name
}
but you are both using
{
old_name
}
and "
f
"
{
new_name
}
has keyword arguments, only uses
{
new_name
}
"
f
"
{
new_name
}
has keyword arguments, only uses
{
new_name
}
"
)
)
if
old_name
in
kwargs
:
if
old_name
in
kwargs
:
send_warning
(
send_warning
(
f
"argument
{
old_name
}
of callable
{
func
.
__name__
}
has been renamed "
f
"argument
{
old_name
}
of callable
{
get_real
__name__
(
func
)
}
has been renamed "
f
"and is deprecated, use keyword argument
{
new_name
}
instead"
,
f
"and is deprecated, use keyword argument
{
new_name
}
instead"
,
stacklevel
=
3
,
stacklevel
=
3
,
version
=
version
,
version
=
version
,
...
...
test/test_deprecation.py
View file @
f78ed63c
...
@@ -143,6 +143,31 @@ class RawInputTC(TestCase):
...
@@ -143,6 +143,31 @@ class RawInputTC(TestCase):
# by default.
# by default.
# See: https://forge.extranet.logilab.fr/cubicweb/cubicweb/blob/3.24.0/cubicweb/schemas/__init__.py#L51 # noqa
# See: https://forge.extranet.logilab.fr/cubicweb/cubicweb/blob/3.24.0/cubicweb/schemas/__init__.py#L51 # noqa
def
test_lazy_wraps_function_name
(
self
):
"""
Avoid conflict from lazy_wraps where __name__ isn't correctly set on
the wrapper from the wrapped and we end up with the name of the wrapper
instead of the wrapped.
Like here it would fail if "check_kwargs" is the name of the new
function instead of new_function_name, this is because the wrapper in
argument_renamed is called check_kwargs and doesn't transmit the
__name__ of the wrapped (new_function_name) correctly.
"""
@
deprecation
.
argument_renamed
(
old_name
=
"a"
,
new_name
=
"b"
)
def
new_function_name
(
b
):
pass
old_function_name
=
deprecation
.
callable_renamed
(
old_name
=
"old_function_name"
,
new_function
=
new_function_name
)
old_function_name
(
None
)
assert
"old_function_name"
in
self
.
messages
[
0
]
assert
"new_function_name"
in
self
.
messages
[
0
]
assert
"check_kwargs"
not
in
self
.
messages
[
0
]
def
test_attribute_renamed
(
self
):
def
test_attribute_renamed
(
self
):
@
deprecation
.
attribute_renamed
(
old_name
=
"old"
,
new_name
=
"new"
)
@
deprecation
.
attribute_renamed
(
old_name
=
"old"
,
new_name
=
"new"
)
class
SomeClass
:
class
SomeClass
:
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment