"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "skimage/_shared/utils.py" between
scikit-image-0.19.1.tar.gz and scikit-image-0.19.2.tar.gz

About: scikit-image is a collection of algorithms for image processing in Python.

utils.py  (scikit-image-0.19.1):utils.py  (scikit-image-0.19.2)
skipping to change at line 24 skipping to change at line 24
'safe_as_int', 'check_shape_equality', 'check_nD', 'warn', 'safe_as_int', 'check_shape_equality', 'check_nD', 'warn',
'reshape_nd', 'identity', 'slice_at_axis'] 'reshape_nd', 'identity', 'slice_at_axis']
class skimage_deprecation(Warning): class skimage_deprecation(Warning):
"""Create our own deprecation class, since Python >= 2.7 """Create our own deprecation class, since Python >= 2.7
silences deprecations by default. silences deprecations by default.
""" """
pass pass
class change_default_value: def _get_stack_rank(func):
"""Return function rank in the call stack."""
if _is_wrapped(func):
return 1 + _get_stack_rank(func.__wrapped__)
else:
return 0
def _is_wrapped(func):
return "__wrapped__" in dir(func)
def _get_stack_length(func):
"""Return function call stack length."""
return _get_stack_rank(func.__globals__.get(func.__name__, func))
class _DecoratorBaseClass:
"""Used to manage decorators' warnings stacklevel.
The `_stack_length` class variable is used to store the number of
times a function is wrapped by a decorator.
Let `stack_length` be the total number of times a decorated
function is wrapped, and `stack_rank` be the rank of the decorator
in the decorators stack. The stacklevel of a warning is then
`stacklevel = 1 + stack_length - stack_rank`.
"""
_stack_length = {}
def get_stack_length(self, func):
return self._stack_length.get(func.__name__,
_get_stack_length(func))
class change_default_value(_DecoratorBaseClass):
"""Decorator for changing the default value of an argument. """Decorator for changing the default value of an argument.
Parameters Parameters
---------- ----------
arg_name: str arg_name: str
The name of the argument to be updated. The name of the argument to be updated.
new_value: any new_value: any
The argument new value. The argument new value.
changed_version : str changed_version : str
The package version in which the change will be introduced. The package version in which the change will be introduced.
skipping to change at line 53 skipping to change at line 85
self.arg_name = arg_name self.arg_name = arg_name
self.new_value = new_value self.new_value = new_value
self.warning_msg = warning_msg self.warning_msg = warning_msg
self.changed_version = changed_version self.changed_version = changed_version
def __call__(self, func): def __call__(self, func):
parameters = inspect.signature(func).parameters parameters = inspect.signature(func).parameters
arg_idx = list(parameters.keys()).index(self.arg_name) arg_idx = list(parameters.keys()).index(self.arg_name)
old_value = parameters[self.arg_name].default old_value = parameters[self.arg_name].default
stack_rank = _get_stack_rank(func)
if self.warning_msg is None: if self.warning_msg is None:
self.warning_msg = ( self.warning_msg = (
f'The new recommended value for {self.arg_name} is ' f'The new recommended value for {self.arg_name} is '
f'{self.new_value}. Until version {self.changed_version}, ' f'{self.new_value}. Until version {self.changed_version}, '
f'the default {self.arg_name} value is {old_value}. ' f'the default {self.arg_name} value is {old_value}. '
f'From version {self.changed_version}, the {self.arg_name} ' f'From version {self.changed_version}, the {self.arg_name} '
f'default value will be {self.new_value}. To avoid ' f'default value will be {self.new_value}. To avoid '
f'this warning, please explicitly set {self.arg_name} value.') f'this warning, please explicitly set {self.arg_name} value.')
@functools.wraps(func) @functools.wraps(func)
def fixed_func(*args, **kwargs): def fixed_func(*args, **kwargs):
stacklevel = 1 + self.get_stack_length(func) - stack_rank
if len(args) < arg_idx + 1 and self.arg_name not in kwargs.keys(): if len(args) < arg_idx + 1 and self.arg_name not in kwargs.keys():
# warn that arg_name default value changed: # warn that arg_name default value changed:
warnings.warn(self.warning_msg, FutureWarning, stacklevel=2) warnings.warn(self.warning_msg, FutureWarning,
stacklevel=stacklevel)
return func(*args, **kwargs) return func(*args, **kwargs)
return fixed_func return fixed_func
class remove_arg: class remove_arg(_DecoratorBaseClass):
"""Decorator to remove an argument from function's signature. """Decorator to remove an argument from function's signature.
Parameters Parameters
---------- ----------
arg_name: str arg_name: str
The name of the argument to be removed. The name of the argument to be removed.
changed_version : str changed_version : str
The package version in which the warning will be replaced by The package version in which the warning will be replaced by
an error. an error.
help_msg: str help_msg: str
Optional message appended to the generic warning message. Optional message appended to the generic warning message.
""" """
def __init__(self, arg_name, *, changed_version, help_msg=None): def __init__(self, arg_name, *, changed_version, help_msg=None):
self.arg_name = arg_name self.arg_name = arg_name
self.help_msg = help_msg self.help_msg = help_msg
self.changed_version = changed_version self.changed_version = changed_version
def __call__(self, func): def __call__(self, func):
parameters = inspect.signature(func).parameters parameters = inspect.signature(func).parameters
arg_idx = list(parameters.keys()).index(self.arg_name) arg_idx = list(parameters.keys()).index(self.arg_name)
warning_msg = ( warning_msg = (
f'{self.arg_name} argument is deprecated and will be removed ' f'{self.arg_name} argument is deprecated and will be removed '
f'in version {self.changed_version}. To avoid this warning, ' f'in version {self.changed_version}. To avoid this warning, '
f'please do not use the {self.arg_name} argument. Please ' f'please do not use the {self.arg_name} argument. Please '
f'see {func.__name__} documentation for more details.') f'see {func.__name__} documentation for more details.')
if self.help_msg is not None: if self.help_msg is not None:
warning_msg += f' {self.help_msg}' warning_msg += f' {self.help_msg}'
stack_rank = _get_stack_rank(func)
@functools.wraps(func) @functools.wraps(func)
def fixed_func(*args, **kwargs): def fixed_func(*args, **kwargs):
stacklevel = 1 + self.get_stack_length(func) - stack_rank
if len(args) > arg_idx or self.arg_name in kwargs.keys(): if len(args) > arg_idx or self.arg_name in kwargs.keys():
# warn that arg_name is deprecated # warn that arg_name is deprecated
warnings.warn(warning_msg, FutureWarning, stacklevel=2) warnings.warn(warning_msg, FutureWarning,
stacklevel=stacklevel)
return func(*args, **kwargs) return func(*args, **kwargs)
return fixed_func return fixed_func
def docstring_add_deprecated(func, kwarg_mapping, deprecated_version): def docstring_add_deprecated(func, kwarg_mapping, deprecated_version):
"""Add deprecated kwarg(s) to the "Other Params" section of a docstring. """Add deprecated kwarg(s) to the "Other Params" section of a docstring.
Parameters Parameters
--------- ---------
func : function func : function
skipping to change at line 177 skipping to change at line 218
descr += '\n ' + no_header.pop(0) descr += '\n ' + no_header.pop(0)
descr += '\n\n' descr += '\n\n'
# '\n ' rather than '\n' here to restore the original indentation. # '\n ' rather than '\n' here to restore the original indentation.
final_docstring = descr + '\n '.join(no_header) final_docstring = descr + '\n '.join(no_header)
# strip any extra spaces from ends of lines # strip any extra spaces from ends of lines
final_docstring = '\n'.join( final_docstring = '\n'.join(
[line.rstrip() for line in final_docstring.split('\n')] [line.rstrip() for line in final_docstring.split('\n')]
) )
return final_docstring return final_docstring
class deprecate_kwarg: class deprecate_kwarg(_DecoratorBaseClass):
"""Decorator ensuring backward compatibility when argument names are """Decorator ensuring backward compatibility when argument names are
modified in a function definition. modified in a function definition.
Parameters Parameters
---------- ----------
kwarg_mapping: dict kwarg_mapping: dict
Mapping between the function's old argument names and the new Mapping between the function's old argument names and the new
ones. ones.
deprecated_version : str deprecated_version : str
The package version in which the argument was first deprecated. The package version in which the argument was first deprecated.
skipping to change at line 205 skipping to change at line 246
""" """
def __init__(self, kwarg_mapping, deprecated_version, warning_msg=None, def __init__(self, kwarg_mapping, deprecated_version, warning_msg=None,
removed_version=None): removed_version=None):
self.kwarg_mapping = kwarg_mapping self.kwarg_mapping = kwarg_mapping
if warning_msg is None: if warning_msg is None:
self.warning_msg = ("`{old_arg}` is a deprecated argument name " self.warning_msg = ("`{old_arg}` is a deprecated argument name "
"for `{func_name}`. ") "for `{func_name}`. ")
if removed_version is not None: if removed_version is not None:
self.warning_msg += (f'It will be removed in ' self.warning_msg += (f'It will be removed in '
f'version {removed_version}.') f'version {removed_version}. ')
self.warning_msg += "Please use `{new_arg}` instead." self.warning_msg += "Please use `{new_arg}` instead."
else: else:
self.warning_msg = warning_msg self.warning_msg = warning_msg
self.deprecated_version = deprecated_version self.deprecated_version = deprecated_version
def __call__(self, func): def __call__(self, func):
stack_rank = _get_stack_rank(func)
@functools.wraps(func) @functools.wraps(func)
def fixed_func(*args, **kwargs): def fixed_func(*args, **kwargs):
stacklevel = 1 + self.get_stack_length(func) - stack_rank
for old_arg, new_arg in self.kwarg_mapping.items(): for old_arg, new_arg in self.kwarg_mapping.items():
if old_arg in kwargs: if old_arg in kwargs:
# warn that the function interface has changed: # warn that the function interface has changed:
warnings.warn(self.warning_msg.format( warnings.warn(self.warning_msg.format(
old_arg=old_arg, func_name=func.__name__, old_arg=old_arg, func_name=func.__name__,
new_arg=new_arg), FutureWarning, stacklevel=2) new_arg=new_arg), FutureWarning,
stacklevel=stacklevel)
# Substitute new_arg to old_arg # Substitute new_arg to old_arg
kwargs[new_arg] = kwargs.pop(old_arg) kwargs[new_arg] = kwargs.pop(old_arg)
# Call the function with the fixed arguments # Call the function with the fixed arguments
return func(*args, **kwargs) return func(*args, **kwargs)
if func.__doc__ is not None: if func.__doc__ is not None:
newdoc = docstring_add_deprecated(func, self.kwarg_mapping, newdoc = docstring_add_deprecated(func, self.kwarg_mapping,
self.deprecated_version) self.deprecated_version)
fixed_func.__doc__ = newdoc fixed_func.__doc__ = newdoc
skipping to change at line 254 skipping to change at line 300
def __init__(self, removed_version='1.0', multichannel_position=None): def __init__(self, removed_version='1.0', multichannel_position=None):
super().__init__( super().__init__(
kwarg_mapping={'multichannel': 'channel_axis'}, kwarg_mapping={'multichannel': 'channel_axis'},
deprecated_version='0.19', deprecated_version='0.19',
warning_msg=None, warning_msg=None,
removed_version=removed_version) removed_version=removed_version)
self.position = multichannel_position self.position = multichannel_position
def __call__(self, func): def __call__(self, func):
stack_rank = _get_stack_rank(func)
@functools.wraps(func) @functools.wraps(func)
def fixed_func(*args, **kwargs): def fixed_func(*args, **kwargs):
stacklevel = 1 + self.get_stack_length(func) - stack_rank
if self.position is not None and len(args) > self.position: if self.position is not None and len(args) > self.position:
warning_msg = ( warning_msg = (
"Providing the `multichannel` argument positionally to " "Providing the `multichannel` argument positionally to "
"{func_name} is deprecated. Use the `channel_axis` kwarg " "{func_name} is deprecated. Use the `channel_axis` kwarg "
"instead." "instead."
) )
warnings.warn(warning_msg.format(func_name=func.__name__), warnings.warn(warning_msg.format(func_name=func.__name__),
FutureWarning, FutureWarning,
stacklevel=2) stacklevel=stacklevel)
if 'channel_axis' in kwargs: if 'channel_axis' in kwargs:
raise ValueError( raise ValueError(
"Cannot provide both a `channel_axis` kwarg and a " "Cannot provide both a `channel_axis` kwarg and a "
"positional `multichannel` value." "positional `multichannel` value."
) )
else: else:
channel_axis = -1 if args[self.position] else None channel_axis = -1 if args[self.position] else None
kwargs['channel_axis'] = channel_axis kwargs['channel_axis'] = channel_axis
if 'multichannel' in kwargs: if 'multichannel' in kwargs:
# warn that the function interface has changed: # warn that the function interface has changed:
warnings.warn(self.warning_msg.format( warnings.warn(self.warning_msg.format(
old_arg='multichannel', func_name=func.__name__, old_arg='multichannel', func_name=func.__name__,
new_arg='channel_axis'), FutureWarning, stacklevel=2) new_arg='channel_axis'), FutureWarning,
stacklevel=stacklevel)
# multichannel = True -> last axis corresponds to channels # multichannel = True -> last axis corresponds to channels
convert = {True: -1, False: None} convert = {True: -1, False: None}
kwargs['channel_axis'] = convert[kwargs.pop('multichannel')] kwargs['channel_axis'] = convert[kwargs.pop('multichannel')]
# Call the function with the fixed arguments # Call the function with the fixed arguments
return func(*args, **kwargs) return func(*args, **kwargs)
if func.__doc__ is not None: if func.__doc__ is not None:
newdoc = docstring_add_deprecated( newdoc = docstring_add_deprecated(
func, {'multichannel': 'channel_axis'}, '0.19') func, {'multichannel': 'channel_axis'}, '0.19')
fixed_func.__doc__ = newdoc fixed_func.__doc__ = newdoc
return fixed_func return fixed_func
class channel_as_last_axis(): class channel_as_last_axis:
"""Decorator for automatically making channels axis last for all arrays. """Decorator for automatically making channels axis last for all arrays.
This decorator reorders axes for compatibility with functions that only This decorator reorders axes for compatibility with functions that only
support channels along the last axis. After the function call is complete support channels along the last axis. After the function call is complete
the channels axis is restored back to its original position. the channels axis is restored back to its original position.
Parameters Parameters
---------- ----------
channel_arg_positions : tuple of int, optional channel_arg_positions : tuple of int, optional
Positional arguments at the positions specified in this tuple are Positional arguments at the positions specified in this tuple are
skipping to change at line 324 skipping to change at line 375
where some or all are multichannel. where some or all are multichannel.
""" """
def __init__(self, channel_arg_positions=(0,), channel_kwarg_names=(), def __init__(self, channel_arg_positions=(0,), channel_kwarg_names=(),
multichannel_output=True): multichannel_output=True):
self.arg_positions = set(channel_arg_positions) self.arg_positions = set(channel_arg_positions)
self.kwarg_names = set(channel_kwarg_names) self.kwarg_names = set(channel_kwarg_names)
self.multichannel_output = multichannel_output self.multichannel_output = multichannel_output
def __call__(self, func): def __call__(self, func):
@functools.wraps(func) @functools.wraps(func)
def fixed_func(*args, **kwargs): def fixed_func(*args, **kwargs):
channel_axis = kwargs.get('channel_axis', None) channel_axis = kwargs.get('channel_axis', None)
if channel_axis is None: if channel_axis is None:
return func(*args, **kwargs) return func(*args, **kwargs)
# TODO: convert scalars to a tuple in anticipation of eventually # TODO: convert scalars to a tuple in anticipation of eventually
# supporting a tuple of channel axes. Right now, only an # supporting a tuple of channel axes. Right now, only an
skipping to change at line 370 skipping to change at line 422
kwargs["channel_axis"] = -1 kwargs["channel_axis"] = -1
# Call the function with the fixed arguments # Call the function with the fixed arguments
out = func(*new_args, **kwargs) out = func(*new_args, **kwargs)
if self.multichannel_output: if self.multichannel_output:
out = np.moveaxis(out, -1, channel_axis[0]) out = np.moveaxis(out, -1, channel_axis[0])
return out return out
return fixed_func return fixed_func
class deprecated(object): class deprecated:
"""Decorator to mark deprecated functions with warning. """Decorator to mark deprecated functions with warning.
Adapted from <http://wiki.python.org/moin/PythonDecoratorLibrary>. Adapted from <http://wiki.python.org/moin/PythonDecoratorLibrary>.
Parameters Parameters
---------- ----------
alt_func : str alt_func : str
If given, tell user what function to use instead. If given, tell user what function to use instead.
behavior : {'warn', 'raise'} behavior : {'warn', 'raise'}
Behavior during call to deprecated function: 'warn' = warn user that Behavior during call to deprecated function: 'warn' = warn user that
 End of changes. 21 change blocks. 
11 lines changed or deleted 63 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)