Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
open-source
logilab-common
Commits
126a77ff9f57
Commit
bb81242f
authored
May 29, 2020
by
Noé Gaumont
🐙
Browse files
refactor(logilab.common.deprecation): add types
parent
ff3479ad6c95
Pipeline
#8736
passed with stages
in 3 minutes and 43 seconds
Changes
3
Pipelines
2
Hide whitespace changes
Inline
Side-by-side
logilab/common/deprecation.py
View file @
126a77ff
...
...
@@ -23,9 +23,11 @@ import os
import
sys
from
warnings
import
warn
from
functools
import
WRAPPER_ASSIGNMENTS
,
WRAPPER_UPDATES
from
typing
import
Any
,
Callable
,
Dict
,
Optional
,
Iterable
from
typing_extensions
import
Protocol
def
lazy_wraps
(
wrapped
)
:
def
lazy_wraps
(
wrapped
:
Callable
)
->
Callable
:
"""
This is the equivalent of the @wraps decorator of functools except it won't
try to grabs attributes of the targeted function on decoration but on access.
...
...
@@ -44,19 +46,19 @@ def lazy_wraps(wrapped):
>>> def wrapper(*args, **kwargs): ...
"""
def
update_wrapper_attributes
(
wrapper
)
:
def
__getattribute__
(
self
,
attribute
)
:
def
update_wrapper_attributes
(
wrapper
:
Callable
)
->
Callable
:
def
__getattribute__
(
self
,
attribute
:
str
)
->
Any
:
if
attribute
in
WRAPPER_ASSIGNMENTS
:
return
getattr
(
wrapped
,
attribute
)
return
super
(
self
.
__class__
,
self
).
__getattribute__
(
attribute
)
wrapper
.
__getattribute__
=
__getattribute__
wrapper
.
__getattribute__
=
__getattribute__
# type: ignore
for
attribute
in
WRAPPER_UPDATES
:
getattr
(
wrapper
,
attribute
).
update
(
getattr
(
wrapped
,
attribute
,
{}))
wrapper
.
__wrapped__
=
wrapped
wrapper
.
__wrapped__
=
wrapped
# type: ignore
return
wrapper
...
...
@@ -67,16 +69,16 @@ class DeprecationWrapper(object):
"""proxy to print a warning on access to any attribute of the wrapped object
"""
def
__init__
(
self
,
proxied
,
msg
=
None
,
version
=
None
)
:
def
__init__
(
self
,
proxied
,
msg
:
Optional
[
str
]
=
None
,
version
:
Optional
[
str
]
=
None
)
->
None
:
self
.
_proxied
=
proxied
self
.
_msg
=
msg
self
.
version
=
version
self
.
_msg
:
str
=
msg
if
msg
else
""
self
.
version
:
Optional
[
str
]
=
version
def
__getattr__
(
self
,
attr
)
:
def
__getattr__
(
self
,
attr
:
str
)
->
Any
:
send_warning
(
self
.
_msg
,
stacklevel
=
3
,
version
=
self
.
version
)
return
getattr
(
self
.
_proxied
,
attr
)
def
__setattr__
(
self
,
attr
,
value
)
:
def
__setattr__
(
self
,
attr
:
str
,
value
:
Any
)
->
None
:
if
attr
in
(
"_proxied"
,
"_msg"
):
self
.
__dict__
[
attr
]
=
value
else
:
...
...
@@ -84,7 +86,7 @@ class DeprecationWrapper(object):
setattr
(
self
.
_proxied
,
attr
,
value
)
def
_get_module_name
(
number
=
1
)
:
def
_get_module_name
(
number
:
int
=
1
)
->
str
:
"""
automagically try to determine the package name from which the warning has
been triggered by loop other calling frames.
...
...
@@ -111,7 +113,12 @@ def _get_module_name(number=1):
return
file_name
def
send_warning
(
reason
,
version
=
None
,
stacklevel
=
2
,
module_name
=
None
):
def
send_warning
(
reason
:
str
,
version
:
Optional
[
str
]
=
None
,
stacklevel
:
int
=
2
,
module_name
:
Optional
[
str
]
=
None
,
)
->
None
:
"""Display a deprecation message only if the version is older than the
compatible version.
"""
...
...
@@ -125,7 +132,9 @@ def send_warning(reason, version=None, stacklevel=2, module_name=None):
warn
(
reason
,
DeprecationWarning
,
stacklevel
=
stacklevel
)
def
callable_renamed
(
old_name
,
new_function
,
version
=
None
):
def
callable_renamed
(
old_name
:
str
,
new_function
:
Callable
,
version
:
Optional
[
str
]
=
None
)
->
Callable
:
"""use to tell that a callable has been renamed.
It returns a callable wrapper, so that when its called a warning is printed
...
...
@@ -154,10 +163,12 @@ def callable_renamed(old_name, new_function, version=None):
return
wrapped
renamed
=
callable_renamed
(
old_name
=
"renamed"
,
new_function
=
callable_renamed
)
renamed
:
Callable
[[
str
,
Callable
,
Optional
[
str
]],
Callable
]
=
callable_renamed
(
old_name
=
"renamed"
,
new_function
=
callable_renamed
)
def
argument_removed
(
old_argument_name
,
version
=
None
)
:
def
argument_removed
(
old_argument_name
:
str
,
version
:
Optional
[
str
]
=
None
)
->
Callable
:
"""
callable decorator to allow getting backward compatibility for renamed keyword arguments.
...
...
@@ -170,7 +181,7 @@ def argument_removed(old_argument_name, version=None):
42
"""
def
_wrap
(
func
)
:
def
_wrap
(
func
:
Callable
)
->
Callable
:
@
lazy_wraps
(
func
)
def
check_kwargs
(
*
args
,
**
kwargs
):
if
old_argument_name
in
kwargs
:
...
...
@@ -192,15 +203,17 @@ def argument_removed(old_argument_name, version=None):
@
argument_removed
(
"name"
)
@
argument_removed
(
"doc"
)
def
callable_deprecated
(
reason
=
None
,
version
=
None
,
stacklevel
=
2
):
def
callable_deprecated
(
reason
:
Optional
[
str
]
=
None
,
version
:
Optional
[
str
]
=
None
,
stacklevel
:
int
=
2
)
->
Callable
:
"""Display a deprecation message only if the version is older than the
compatible version.
"""
def
decorator
(
func
)
:
def
decorator
(
func
:
Callable
)
->
Callable
:
@
lazy_wraps
(
func
)
def
wrapped
(
*
args
,
**
kwargs
):
message
=
reason
or
'The function "%s" is deprecated'
def
wrapped
(
*
args
,
**
kwargs
)
->
Callable
:
message
:
str
=
reason
or
'The function "%s" is deprecated'
if
"%s"
in
message
:
message
%=
func
.
__name__
...
...
@@ -212,13 +225,24 @@ def callable_deprecated(reason=None, version=None, stacklevel=2):
return
decorator
deprecated
=
callable_renamed
(
old_name
=
"deprecated"
,
new_function
=
callable_deprecated
)
class
CallableDeprecatedCallable
(
Protocol
):
def
__call__
(
self
,
reason
:
Optional
[
str
]
=
None
,
version
:
Optional
[
str
]
=
None
,
stacklevel
:
int
=
2
)
->
Callable
:
...
def
class_deprecated
(
old_name
,
parent
,
class_dict
):
class
DeprecatedClass
(
*
parent
):
deprecated
:
CallableDeprecatedCallable
=
callable_renamed
(
old_name
=
"deprecated"
,
new_function
=
callable_deprecated
)
def
class_deprecated
(
old_name
:
str
,
parent
:
Iterable
[
type
],
class_dict
:
Dict
[
str
,
Any
])
->
type
:
class
DeprecatedClass
(
*
parent
):
# type: ignore
def
__init__
(
self
,
*
args
,
**
kwargs
):
msg
=
class_dict
.
get
(
"__deprecation_warning__"
,
f
"
{
old_name
}
is deprecated"
)
msg
:
str
=
class_dict
.
get
(
"__deprecation_warning__"
,
f
"
{
old_name
}
is deprecated"
)
# type: ignore
send_warning
(
msg
,
stacklevel
=
class_dict
.
get
(
"__deprecation_warning_stacklevel__"
,
3
),
...
...
@@ -234,7 +258,7 @@ def class_deprecated(old_name, parent, class_dict):
return
DeprecatedClass
def
attribute_renamed
(
old_name
,
new_name
,
version
=
None
)
:
def
attribute_renamed
(
old_name
:
str
,
new_name
:
str
,
version
:
Optional
[
str
]
=
None
)
->
Callable
:
"""
class decorator to allow getting backward compatibility for renamed attributes.
...
...
@@ -257,21 +281,21 @@ def attribute_renamed(old_name, new_name, version=None):
True
"""
def
_class_wrap
(
klass
)
:
def
_class_wrap
(
klass
:
type
)
->
type
:
reason
=
(
f
"
{
klass
.
__name__
}
.
{
old_name
}
has been renamed and is deprecated, use "
f
"
{
klass
.
__name__
}
.
{
new_name
}
instead"
)
def
_get_old
(
self
):
def
_get_old
(
self
)
->
Any
:
send_warning
(
reason
,
stacklevel
=
3
,
version
=
version
,
module_name
=
klass
.
__module__
)
return
getattr
(
self
,
new_name
)
def
_set_old
(
self
,
value
)
:
def
_set_old
(
self
,
value
:
Any
)
->
None
:
send_warning
(
reason
,
stacklevel
=
3
,
version
=
version
,
module_name
=
klass
.
__module__
)
setattr
(
self
,
new_name
,
value
)
def
_del_old
(
self
):
def
_del_old
(
self
)
->
None
:
send_warning
(
reason
,
stacklevel
=
3
,
version
=
version
,
module_name
=
klass
.
__module__
)
delattr
(
self
,
new_name
)
...
...
@@ -282,7 +306,7 @@ def attribute_renamed(old_name, new_name, version=None):
return
_class_wrap
def
argument_renamed
(
old_name
,
new_name
,
version
=
None
)
:
def
argument_renamed
(
old_name
:
str
,
new_name
:
str
,
version
:
Optional
[
str
]
=
None
)
->
Callable
:
"""
callable decorator to allow getting backward compatibility for renamed keyword arguments.
...
...
@@ -296,9 +320,9 @@ def argument_renamed(old_name, new_name, version=None):
42
"""
def
_wrap
(
func
)
:
def
_wrap
(
func
:
Callable
)
->
Callable
:
@
lazy_wraps
(
func
)
def
check_kwargs
(
*
args
,
**
kwargs
):
def
check_kwargs
(
*
args
,
**
kwargs
)
->
Callable
:
if
old_name
in
kwargs
and
new_name
in
kwargs
:
raise
ValueError
(
f
"argument
{
old_name
}
of callable
{
func
.
__name__
}
has been "
...
...
@@ -326,7 +350,9 @@ def argument_renamed(old_name, new_name, version=None):
@
argument_renamed
(
old_name
=
"modpath"
,
new_name
=
"module_path"
)
@
argument_renamed
(
old_name
=
"objname"
,
new_name
=
"object_name"
)
def
callable_moved
(
module_name
,
object_name
,
version
=
None
,
stacklevel
=
2
):
def
callable_moved
(
module_name
:
str
,
object_name
:
str
,
version
:
Optional
[
str
]
=
None
,
stacklevel
:
int
=
2
)
->
Callable
:
"""use to tell that a callable has been moved to a new module.
It returns a callable wrapper, so that when its called a warning is printed
...
...
@@ -352,10 +378,18 @@ def callable_moved(module_name, object_name, version=None, stacklevel=2):
return
callnew
moved
=
callable_renamed
(
old_name
=
"moved"
,
new_function
=
callable_moved
)
moved
:
Callable
[[
Optional
[
str
],
Optional
[
str
],
int
],
Callable
]
=
callable_renamed
(
old_name
=
"moved"
,
new_function
=
callable_moved
)
def
class_renamed
(
old_name
,
new_class
,
message
=
None
,
version
=
None
,
module_name
=
None
):
def
class_renamed
(
old_name
:
str
,
new_class
:
type
,
message
:
Optional
[
str
]
=
None
,
version
:
Optional
[
str
]
=
None
,
module_name
:
Optional
[
str
]
=
None
,
)
->
type
:
"""automatically creates a class which fires a DeprecationWarning
when instantiated.
...
...
@@ -365,7 +399,7 @@ def class_renamed(old_name, new_class, message=None, version=None, module_name=N
s = Set()
>>>
"""
class_dict
=
{}
class_dict
:
Dict
[
str
,
Any
]
=
{}
if
message
is
None
:
message
=
"%s is deprecated, use %s instead"
%
(
old_name
,
new_class
.
__name__
)
...
...
@@ -381,7 +415,12 @@ def class_renamed(old_name, new_class, message=None, version=None, module_name=N
return
class_deprecated
(
old_name
,
(
new_class
,),
class_dict
)
def
class_moved
(
new_class
,
old_name
=
None
,
message
=
None
,
version
=
None
):
def
class_moved
(
new_class
:
type
,
old_name
:
Optional
[
str
]
=
None
,
message
:
Optional
[
str
]
=
None
,
version
:
Optional
[
str
]
=
None
,
)
->
type
:
"""nice wrapper around class_renamed when a class has been moved into
another module
"""
...
...
logilab/common/pytest.py
View file @
126a77ff
...
...
@@ -100,7 +100,7 @@ import re
import
sys
import
os.path
as
osp
from
time
import
process_time
,
time
from
re
import
Match
from
re
import
Match
# type: ignore
import
warnings
import
types
import
inspect
...
...
logilab/common/textutils.py
View file @
126a77ff
...
...
@@ -46,7 +46,7 @@ __docformat__ = "restructuredtext en"
import
sys
import
re
import
os.path
as
osp
from
re
import
Pattern
,
Match
from
re
import
Pattern
,
Match
# type: ignore
from
warnings
import
warn
from
unicodedata
import
normalize
as
_uninormalize
from
typing
import
Any
,
Optional
,
Tuple
,
List
,
Callable
,
Dict
,
Union
...
...
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