Last active
December 28, 2021 13:14
-
-
Save kchawla-pi/6c7d733858a7e30e27c28df40ef46a4b to your computer and use it in GitHub Desktop.
Code snippets used in article "Code. Changing it without breaking it, using a Decorator."
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import warnings | |
def view_connectome(adjacency_matrix, | |
node_coords, | |
edge_threshold=None, | |
edge_cmap=cm.cyan_orange, | |
symmetric_cmap=True, | |
linewidth=6., | |
node_size=3., | |
# placing old params here to preserve old keyworded args. | |
coords=None, threshold=None, cmap=None, marker_size=None, | |
): | |
# code for the deprecation | |
param_deprecation_msg_template = ('The param {} is being deprecated and will be | |
replaced by the param {} in future. Please use {}.') | |
if marker_size: | |
node_size = marker_size | |
warnings.warn(param_deprecation_msg_template.format('marker_size', | |
'node_size', | |
'node_size', | |
) | |
if threshold is not None: # numpy arrays don't have unambiguous truthiness. | |
edge_threshold = threshold | |
warnings.warn(param_deprecation_msg_template.format('threshold', | |
'edge_threshold', | |
'edge_threshold', | |
) | |
if cmap is not None: # numpy arrays don't have unambiguous truthiness. | |
edge_cmap = cmap | |
warnings.warn(param_deprecation_msg_template.format('cmap', | |
'edge_cmap', | |
'edge_cmap', | |
) | |
if coords is not None: # numpy arrays don't have unambiguous truthiness. | |
node_coords = coords | |
warnings.warn(param_deprecation_msg_template.format('coords', | |
'node_coords', | |
'node_coords', | |
) | |
# original functionality of the function, | |
connectome_info = _get_connectome(adjacency_matrix, | |
node_coords, | |
edge_threshold=threshold, | |
cmap=edge_cmap, | |
symmetric_cmap=symmetric_cmap, | |
) | |
connectome_info["line_width"] = linewidth | |
connectome_info["marker_size"] = node_size | |
return _make_connectome_html(connectome_info) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def replace_parameters(replacement_params, | |
end_version='future', | |
lib_name='Nilearn', | |
): | |
""" | |
Decorator to deprecate & replace specified parameters | |
in the decorated functions and methods | |
without changing function definition or signature. | |
Parameters | |
---------- | |
replacement_params : Dict[string, string] | |
Dict where the key-value pairs represent the old parameters | |
and their corresponding new parameters. | |
Example: {old_param1: new_param1, old_param2: new_param2,...} | |
end_version : str (optional) {'future' (default) | 'next' | <version>} | |
Version when using the deprecated parameters will raise an error. | |
For informational purpose in the warning text. | |
lib_name: str (optional) (Default: 'Nilearn') | |
Name of the library to which the decoratee belongs. | |
For informational purpose in the warning text. | |
""" | |
def _replace_params(func): | |
@functools.wraps(func) | |
def wrapper(*args, **kwargs): | |
_warn_deprecated_params(replacement_params, end_version, lib_name, | |
kwargs | |
) | |
kwargs = _transfer_deprecated_param_vals(replacement_params, | |
kwargs | |
) | |
return func(*args, **kwargs) | |
return wrapper | |
return _replace_params | |
def _warn_deprecated_params(replacement_params, end_version, lib_name, kwargs): | |
""" For the decorator replace_parameters(), | |
raises warnings about deprecated parameters. | |
Parameters | |
---------- | |
replacement_params: Dict[str, str] | |
Dictionary of old_parameters as keys with replacement parameters | |
as their corresponding values. | |
end_version: str | |
The version where use of the deprecated parameters will raise an error. | |
For informational purpose in the warning text. | |
lib_name: str | |
Name of the library. For informational purpose in the warning text. | |
kwargs: Dict[str, any] | |
Dictionary of all the keyword args passed on the decorated function. | |
""" | |
used_deprecated_params = set(kwargs).intersection(replacement_params) | |
for deprecated_param_ in used_deprecated_params: | |
replacement_param = replacement_params[deprecated_param_] | |
param_deprecation_msg = ( | |
'The parameter "{}" will be removed in {} release of {}. ' | |
'Please use the parameter "{}" instead.'.format(deprecated_param_, | |
end_version, | |
lib_name, | |
replacement_param, | |
) | |
) | |
warnings.filterwarnings('always', message=param_deprecation_msg) | |
warnings.warn(category=DeprecationWarning, | |
message=param_deprecation_msg, | |
stacklevel=3) | |
def _transfer_deprecated_param_vals(replacement_params, kwargs): | |
""" For the decorator replace_parameters(), reassigns new parameters | |
the values passed to their corresponding deprecated parameters. | |
Parameters | |
---------- | |
replacement_params: Dict[str, str] | |
Dictionary of old_parameters as keys with replacement parameters | |
as their corresponding values. | |
kwargs: Dict[str, any] | |
Dictionary of all the keyword args passed on the decorated function. | |
Returns | |
------- | |
kwargs: Dict[str, any] | |
Dictionary of all the keyword args to be passed on | |
to the decorated function, with old parameter names | |
replaced by new parameters, with their values intact. | |
""" | |
for old_param, new_param in replacement_params.items(): | |
old_param_val = kwargs.setdefault(old_param, None) | |
if old_param_val is not None: | |
kwargs[new_param] = old_param_val | |
kwargs.pop(old_param) | |
return kwargs |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def _replacement_params_view_connectome(): | |
""" Returns a dict containing deprecated & replacement parameters | |
as key-value pair for view_connectome(). | |
Avoids cluttering the global namespace. | |
""" | |
return { | |
'coords': 'node_coords', | |
'threshold': 'edge_threshold', | |
'cmap': 'edge_cmap', | |
'marker_size': 'node_size', | |
} | |
@replace_parameters(replacement_params=_replacement_params_view_connectome(), | |
end_version='0.6.0', | |
lib_name='Nilearn', | |
) | |
def view_connectome(adjacency_matrix, node_coords, edge_threshold=None, | |
edge_cmap=cm.bwr, symmetric_cmap=True, | |
linewidth=6., node_size=3., | |
): | |
connectome_info = _get_connectome( | |
adjacency_matrix, node_coords, threshold=edge_threshold, cmap=edge_cmap, | |
symmetric_cmap=symmetric_cmap, marker_size=node_size) | |
return _make_connectome_html(connectome_info) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from nilearn._utils.helpers import replace_parameters | |
def _mock_args_for_testing_replace_parameter(): | |
""" | |
:return: Creates mock deprecated & replacement parameters for use with | |
testing functions related to replace_parameters(). | |
""" | |
mock_kwargs_with_deprecated_params_used = { | |
'unchanged_param_0': 'unchanged_param_0_val', | |
'deprecated_param_0': 'deprecated_param_0_val', | |
'deprecated_param_1': 'deprecated_param_1_val', | |
'unchanged_param_1': 'unchanged_param_1_val', | |
} | |
replacement_params = { | |
'deprecated_param_0': 'replacement_param_0', | |
'deprecated_param_1': 'replacement_param_1', | |
} | |
return mock_kwargs_with_deprecated_params_used, replacement_params | |
def test_replace_parameters(): | |
""" Integration tests that deprecates mock parameters in a mock function | |
and checks that the deprecated parameters transfer their values correctly | |
to replacement parameters and all deprecation warning are raised as | |
expected. | |
""" | |
mock_input, replacement_params = _mock_args_for_testing_replace_parameter() | |
expected_output = ('dp0', 'dp1', 'up0', 'up1') | |
expected_warnings = [ | |
('The parameter "deprecated_param_0" will be removed in 0.6.1rc ' | |
'release of other_lib. Please use the parameter "replacement_param_0"' | |
' instead.' | |
), | |
('The parameter "deprecated_param_1" will be removed in 0.6.1rc ' | |
'release of other_lib. Please use the parameter "replacement_param_1"' | |
' instead.' | |
), | |
] | |
@replace_parameters(replacement_params, '0.6.1rc', 'other_lib', ) | |
def mock_function(replacement_param_0, replacement_param_1, | |
unchanged_param_0, unchanged_param_1): | |
return (replacement_param_0, replacement_param_1, unchanged_param_0, | |
unchanged_param_1 | |
) | |
with warnings.catch_warnings(record=True) as raised_warnings: | |
actual_output = mock_function(deprecated_param_0='dp0', | |
deprecated_param_1='dp1', | |
unchanged_param_0='up0', | |
unchanged_param_1='up1', | |
) | |
assert actual_output == expected_output | |
expected_warnings.sort() | |
raised_warnings.sort(key=lambda mem: str(mem.message)) | |
for raised_warning_, expected_warning_ in zip(raised_warnings, | |
expected_warnings): | |
assert str(raised_warning_.message) == expected_warning_ | |
def test_transfer_deprecated_param_vals(): | |
""" Unit test to check that values assigned to deprecated parameters are | |
correctly reassigned to the replacement parameters. | |
""" | |
mock_input, replacement_params = _mock_args_for_testing_replace_parameter() | |
expected_output = { | |
'unchanged_param_0': 'unchanged_param_0_val', | |
'replacement_param_0': 'deprecated_param_0_val', | |
'replacement_param_1': 'deprecated_param_1_val', | |
'unchanged_param_1': 'unchanged_param_1_val', | |
} | |
actual_ouput = helpers._transfer_deprecated_param_vals( | |
replacement_params, | |
mock_input, | |
) | |
assert actual_ouput == expected_output | |
def test_future_warn_deprecated_params(): | |
""" Unit test to check that the correct warning is displayed. | |
""" | |
mock_input, replacement_params = _mock_args_for_testing_replace_parameter() | |
expected_warnings = [ | |
('The parameter "deprecated_param_0" will be removed in sometime ' | |
'release of somelib. Please use the parameter "replacement_param_0" ' | |
'instead.' | |
), | |
('The parameter "deprecated_param_1" will be removed in sometime ' | |
'release of somelib. Please use the parameter "replacement_param_1" ' | |
'instead.' | |
), | |
] | |
with warnings.catch_warnings(record=True) as raised_warnings: | |
helpers._warn_deprecated_params( | |
replacement_params, | |
end_version='sometime', | |
lib_name='somelib', | |
kwargs=mock_input, | |
) | |
expected_warnings.sort() | |
raised_warnings.sort(key=lambda mem: str(mem.message)) | |
for raised_warning_, expected_warning_ in zip(raised_warnings, | |
expected_warnings | |
): | |
assert str(raised_warning_.message) == expected_warning_ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def view_connectome(adjacency_matrix, | |
coords, | |
threshold=None, | |
cmap=cm.cyan_orange, | |
symmetric_cmap=True, | |
linewidth=6., | |
marker_size=3., | |
): | |
connectome_info = _get_connectome( | |
adjacency_matrix, coords, threshold=threshold, cmap=cmap, | |
symmetric_cmap=symmetric_cmap) | |
connectome_info["line_width"] = linewidth | |
connectome_info["marker_size"] = marker_size | |
return _make_connectome_html(connectome_info) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def view_connectome(adjacency_matrix, | |
node_coords, | |
edge_threshold=None, | |
edge_cmap=cm.cyan_orange, | |
symmetric_cmap=True, | |
linewidth=6., | |
node_size=3., | |
**kwargs, | |
): | |
# generate the deprecation warnings | |
kwargs = _param_deprecation_view_connectome(kwargs) | |
# handover the args from old params to new ones. | |
if kwargs['marker_size']: | |
node_size = marker_size | |
if kwargs['threshold'] is not None: | |
edge_threshold = threshold | |
if kwargs['cmap'] is not None: | |
edge_cmap = cmap | |
if kwargs['coords'] is not None: | |
node_coords = coords | |
connectome_info = _get_connectome( | |
adjacency_matrix, node_coords, threshold=edge_threshold, cmap=edge_cmap, | |
symmetric_cmap=symmetric_cmap) | |
connectome_info["line_width"] = linewidth | |
connectome_info["marker_size"] = node_size | |
return _make_connectome_html(connectome_info) | |
def _param_deprecation_view_connectome(kwargs): | |
kwargs.setdefault('marker_size', None) | |
kwargs.setdefault('threshold', None) | |
kwargs.setdefault('cmap', None) | |
kwargs.setdefault('coords', None) | |
param_deprecation_msg_template = ('The param {} is being deprecated and will be | |
replaced by the param {} in future. Please | |
use {}.') | |
if kwargs['marker_size']: | |
warnings.warn(param_deprecation_msg_template.format('marker_size', | |
'node_size', | |
'node_size', | |
) | |
if kwargs['threshold'] is not None: # numpy arrays don't have unambiguous truthiness. | |
warnings.warn(param_deprecation_msg_template.format('threshold', | |
'edge_threshold', | |
'edge_threshold', | |
) | |
if kwargs['cmap'] is not None: # numpy arrays don't have unambiguous truthiness. | |
warnings.warn(param_deprecation_msg_template.format('cmap', | |
'edge_cmap', | |
'edge_cmap', | |
) | |
if kwargs['coords'] is not None: # numpy arrays don't have unambiguous truthiness. | |
warnings.warn(param_deprecation_msg_template.format('coords', | |
'node_coords', | |
'node_coords', | |
) | |
return kwargs |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def view_connectome(adjacency_matrix, | |
node_coords, | |
edge_threshold=None, | |
edge_cmap=cm.cyan_orange, | |
symmetric_cmap=True, | |
linewidth=6., | |
node_size=3., | |
**kwargs, | |
): | |
# generate the deprecation warnings | |
kwargs = _param_deprecation_view_connectome(kwargs) | |
# handover the args from old params to new ones. | |
if kwargs['marker_size']: | |
node_size = marker_size | |
if kwargs['threshold'] is not None: | |
edge_threshold = threshold | |
if kwargs['cmap'] is not None: | |
edge_cmap = cmap | |
if kwargs['coords'] is not None: | |
node_coords = coords | |
connectome_info = _get_connectome( | |
adjacency_matrix, node_coords, threshold=edge_threshold, cmap=edge_cmap, | |
symmetric_cmap=symmetric_cmap) | |
connectome_info["line_width"] = linewidth | |
connectome_info["marker_size"] = node_size | |
return _make_connectome_html(connectome_info) | |
def _param_deprecation_view_connectome(kwargs): | |
kwargs.setdefault('marker_size', None) | |
kwargs.setdefault('threshold', None) | |
kwargs.setdefault('cmap', None) | |
kwargs.setdefault('coords', None) | |
param_deprecation_msg_template = ('The param {} is being deprecated and will be | |
replaced by the param {} in future. Please | |
use {}.') | |
if kwargs['marker_size']: | |
warnings.warn(param_deprecation_msg_template.format('marker_size', | |
'node_size', | |
'node_size', | |
) | |
if kwargs['threshold'] is not None: # numpy arrays don't have unambiguous truthiness. | |
warnings.warn(param_deprecation_msg_template.format('threshold', | |
'edge_threshold', | |
'edge_threshold', | |
) | |
if kwargs['cmap'] is not None: # numpy arrays don't have unambiguous truthiness. | |
warnings.warn(param_deprecation_msg_template.format('cmap', | |
'edge_cmap', | |
'edge_cmap', | |
) | |
if kwargs['coords'] is not None: # numpy arrays don't have unambiguous truthiness. | |
warnings.warn(param_deprecation_msg_template.format('coords', | |
'node_coords', | |
'node_coords', | |
) | |
return kwargs |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def _deprecate_params_view_connectome(func): | |
""" Decorator to deprecate specific parameters in view_connectome() | |
without modifying view_connectome(). | |
""" | |
@functools.wraps(func) | |
def wrapper(*args, **kwargs): | |
_warn_deprecated_params_view_connectome(kwargs) | |
kwargs = _transfer_deprecated_param_vals_view_connectome(kwargs) | |
return func(*args, **kwargs) | |
return wrapper | |
@_deprecate_params_view_connectome | |
def view_connectome(adjacency_matrix, node_coords, edge_threshold=None, | |
edge_cmap=cm.bwr, symmetric_cmap=True, | |
linewidth=6., node_size=3., | |
**kwargs): | |
connectome_info = _get_connectome( | |
adjacency_matrix, node_coords, threshold=edge_threshold, cmap=edge_cmap, | |
symmetric_cmap=symmetric_cmap) | |
connectome_info["line_width"] = linewidth | |
connectome_info["marker_size"] = node_size | |
return _make_connectome_html(connectome_info) | |
def _warn_deprecated_params_view_connectome(kwargs): | |
""" For view_connectome(), raises warnings about deprecated parameters. | |
""" | |
all_deprecated_params = {'coords': 'node_coords', | |
'threshold': 'edge_threshold', | |
'cmap': 'edge_cmap', | |
'marker_size': 'node_size', | |
} | |
used_deprecated_params = set(kwargs).intersection(all_deprecated_params) | |
for deprecated_param_ in used_deprecated_params: | |
replacement_param = all_deprecated_params[deprecated_param_] | |
param_deprecation_msg = ( | |
'The parameter "{}" will be removed in Nilearn version 0.6.0. ' | |
'Please use the parameter "{}" instead.'.format(deprecated_param_, | |
replacement_param, | |
) | |
) | |
warnings.filterwarnings('always', message=param_deprecation_msg) | |
warnings.warn(category=DeprecationWarning, | |
message=param_deprecation_msg, | |
stacklevel=3) | |
def _transfer_deprecated_param_vals_view_connectome(kwargs): | |
""" For view_connectome(), reassigns new parameters the values passed | |
to their corresponding deprecated parameters. | |
""" | |
coords = kwargs.get('coords', None) | |
threshold = kwargs.get('threshold', None) | |
cmap = kwargs.get('cmap', None) | |
marker_size = kwargs.get('marker_size', None) | |
if coords is not None: | |
kwargs['node_coords'] = coords | |
if threshold: | |
kwargs['edge_threshold'] = threshold | |
if cmap: | |
kwargs['edge_cmap'] = cmap | |
if marker_size: | |
kwargs['node_size'] = marker_size | |
return kwargs |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def test_params_deprecation_view_connectome(): | |
deprecated_params = {'coords': 'node_coords', | |
'threshold': 'edge_threshold', | |
'cmap': 'edge_cmap', | |
'marker_size': 'node_size', | |
} | |
deprecation_msg = ( | |
'The parameter "{}" will be removed in Nilearn version 0.6.0. ' | |
'Please use the parameter "{}" instead.' | |
) | |
warning_msgs = {old_: deprecation_msg.format(old_, new_) | |
for old_, new_ in deprecated_params.items() | |
} | |
adj, coord = _make_connectome() | |
with warnings.catch_warnings(record=True) as raised_warnings: | |
html_connectome.view_connectome(adjacency_matrix=adj, | |
coords=coord, | |
edge_threshold='85.3%', | |
edge_cmap=cm.cyan_orange, | |
linewidth=8.5, node_size=4.2, | |
) | |
html_connectome.view_connectome(adjacency_matrix=adj, | |
node_coords=coord, | |
threshold='85.3%', | |
edge_cmap=cm.cyan_orange, | |
linewidth=8.5, | |
node_size=4.2, | |
) | |
html_connectome.view_connectome(adjacency_matrix=adj, | |
node_coords=coord, | |
edge_threshold='85.3%', | |
cmap=cm.cyan_orange, | |
linewidth=8.5, | |
node_size=4.2, | |
) | |
html_connectome.view_connectome(adjacency_matrix=adj, | |
node_coords=coord, | |
edge_threshold='85.3%', | |
edge_cmap=cm.cyan_orange, | |
linewidth=8.5, | |
marker_size=4.2, | |
) | |
html_connectome.view_connectome(adjacency_matrix=adj, | |
node_coords=coord, | |
edge_threshold='85.3%', | |
edge_cmap=cm.cyan_orange, | |
linewidth=8.5, | |
node_size=4.2, | |
) | |
html_connectome.view_connectome(adj, | |
coord, | |
'85.3%', | |
cm.cyan_orange, | |
8.5, | |
4.2, | |
) | |
old_params = ['coords', 'threshold', 'cmap', 'marker_size'] | |
assert len(raised_warnings) == 4 | |
for old_param_, raised_warning_ in zip(old_params, raised_warnings): | |
assert warning_msgs[old_param_] == str(raised_warning_.message) | |
assert raised_warning_.category is DeprecationWarning |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def view_connectome(adjacency_matrix, | |
node_coords, # change param name here, | |
edge_threshold=None, # here, | |
edge_cmap=cm.cyan_orange, # here, | |
symmetric_cmap=True, | |
linewidth=6., | |
node_size=3., # and here. | |
): | |
connectome_info = _get_connectome( | |
# rename the variables in this line, ... | |
adjacency_matrix, node_coords, threshold=edge_threshold, cmap=edge_cmap, | |
symmetric_cmap=symmetric_cmap) | |
connectome_info["line_width"] = linewidth | |
connectome_info["marker_size"] = node_size # ...and here. | |
return _make_connectome_html(connectome_info) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment