"""Collection of tools that are useful for repo administration such as:
- deprecation warnings
- renames / backwards compatibility
- etc
"""
import datetime
import functools
import inspect
import types
import warnings
from typing import Union, List
COPYRIGHT_ATTR = '__copyright__'
COPYRIGHT_PATTERN = """Copyright (C) {start_year:d}--{end_year:d} {authors}
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
"""
DEPRECATION_PATTERN = '{kind} {name} is deprecated{reason}'
[docs]def add_copyright(authors: List[str], start_year: int, end_year: int = None):
"""Add copyright stub to module under __copyright__ attribute
Args:
authors:
List[str], list of author names
start_year:
int, starting year
end_year:
int, default None, ending year. If not specified uses current year
Returns:
None
"""
text = COPYRIGHT_PATTERN.format(authors=', '.join(authors),
start_year=start_year,
end_year=datetime.datetime.today().year if end_year is None else end_year)
# Get module that called this function
frm = inspect.stack()[1]
mod = inspect.getmodule(frm[0])
# Set copyright on module
setattr(mod, COPYRIGHT_ATTR, text)
[docs]def deprecated(reason: str = None):
"""Deprecation decorator factory, can be used to decorate a class or function
Args:
reason:
str, string to display as part of deprecation warning
Returns:
Function, the decorator
"""
def deprecation_decorator(to_decorate: Union[types.FunctionType, type]):
if inspect.isclass(to_decorate):
kind = 'Class'
elif inspect.isfunction(to_decorate):
kind = 'Function'
else:
raise ValueError('Unable to decorate object of type: {}'.format(type(to_decorate)))
@functools.wraps(to_decorate)
def decorated(*args, **kwargs):
with warnings.catch_warnings():
warnings.simplefilter('always', DeprecationWarning)
warnings.warn(
DEPRECATION_PATTERN.format(name=to_decorate.__name__,
kind=kind,
reason=': ' + reason if reason is not None else ''),
category=DeprecationWarning,
stacklevel=2
)
warnings.simplefilter('default', DeprecationWarning)
return to_decorate(*args, **kwargs)
return decorated
return deprecation_decorator