Commit e0b1a5ce authored by Patrick Wieschollek's avatar Patrick Wieschollek Committed by Yuxin Wu

Add helper function/decorator for deprecation warning (#145)

* Add helper function/decorator for deprecation warning

This logs warnings about deprecated functions and also shows the
filename as well as the linenumber.

* enhance documentation

* try to fix python3 (blindly)

* deprecation: use one function to log and one function as decorator

* fix linting
parent 076a728f
...@@ -142,7 +142,7 @@ class ClassificationError(Inferencer): ...@@ -142,7 +142,7 @@ class ClassificationError(Inferencer):
def _datapoint(self, outputs): def _datapoint(self, outputs):
vec = outputs[0] vec = outputs[0]
if vec.ndim == 0: if vec.ndim == 0:
logger.error("[DEPRECATED] use a 'wrong vector' for ClassificationError instead of nr_wrong") logger.error("[DEPRECATED] use a 'wrong vector' for ClassificationError instead of nr_wrong. Exiting..")
sys.exit(1) sys.exit(1)
else: else:
# TODO put shape assertion into inferencerrunner # TODO put shape assertion into inferencerrunner
......
...@@ -8,9 +8,10 @@ import tensorflow as tf ...@@ -8,9 +8,10 @@ import tensorflow as tf
import pickle import pickle
import six import six
from ..utils import logger, INPUTS_KEY from ..utils import logger, INPUTS_KEY, deprecated, log_deprecated
from ..utils.argtools import memoized from ..utils.argtools import memoized
from ..tfutils.modelutils import apply_slim_collections from ..tfutils.modelutils import apply_slim_collections
from ..tfutils.gradproc import CheckGradient from ..tfutils.gradproc import CheckGradient
__all__ = ['InputDesc', 'InputVar', 'ModelDesc', 'ModelFromMetaGraph'] __all__ = ['InputDesc', 'InputVar', 'ModelDesc', 'ModelFromMetaGraph']
...@@ -62,9 +63,9 @@ class ModelDesc(object): ...@@ -62,9 +63,9 @@ class ModelDesc(object):
""" """
return self.build_placeholders() return self.build_placeholders()
@deprecated("Use get_reused_placehdrs() instead.", "2017-04-11")
def get_input_vars(self): def get_input_vars(self):
# this wasn't a public API anyway # this wasn't a public API anyway
logger.warn("[Deprecated] get_input_vars() was renamed to get_reused_placehdrs()!")
return self.get_reused_placehdrs() return self.get_reused_placehdrs()
def build_placeholders(self, prefix=''): def build_placeholders(self, prefix=''):
...@@ -97,8 +98,7 @@ class ModelDesc(object): ...@@ -97,8 +98,7 @@ class ModelDesc(object):
""" """
:returns: a list of InputDesc :returns: a list of InputDesc
""" """
# TODO deprecate @ Apr 11 log_deprecated("", "_get_input_vars() was renamed to _get_inputs().", "2017-04-11")
logger.warn("[Deprecated] _get_input_vars() is renamed to _get_inputs()")
return self._get_input_vars() return self._get_input_vars()
def _get_input_vars(self): # keep backward compatibility def _get_input_vars(self): # keep backward compatibility
......
...@@ -6,7 +6,7 @@ import six ...@@ -6,7 +6,7 @@ import six
import tensorflow as tf import tensorflow as tf
import re import re
from ..utils import logger from ..utils import log_deprecated
from ..utils.naming import MOVING_SUMMARY_VARS_KEY from ..utils.naming import MOVING_SUMMARY_VARS_KEY
from .tower import get_current_tower_context from .tower import get_current_tower_context
from .symbolic_functions import rms from .symbolic_functions import rms
...@@ -61,7 +61,7 @@ def add_param_summary(*summary_lists): ...@@ -61,7 +61,7 @@ def add_param_summary(*summary_lists):
if ctx is not None and not ctx.is_main_training_tower: if ctx is not None and not ctx.is_main_training_tower:
return return
if len(summary_lists) == 1 and isinstance(summary_lists[0], list): if len(summary_lists) == 1 and isinstance(summary_lists[0], list):
logger.warn("[Deprecated] Use positional args to call add_param_summary() instead of a list.") log_deprecated(text="Use positional args to call add_param_summary() instead of a list.")
summary_lists = summary_lists[0] summary_lists = summary_lists[0]
def perform(var, action): def perform(var, action):
......
...@@ -10,7 +10,7 @@ from ..callbacks import ( ...@@ -10,7 +10,7 @@ from ..callbacks import (
MaintainStepCounter) MaintainStepCounter)
from ..dataflow.base import DataFlow from ..dataflow.base import DataFlow
from ..models import ModelDesc from ..models import ModelDesc
from ..utils import logger from ..utils import logger, log_deprecated
from ..tfutils import (JustCurrentSession, from ..tfutils import (JustCurrentSession,
get_default_sess_config, SessionInit) get_default_sess_config, SessionInit)
from .input_data import InputData from .input_data import InputData
...@@ -62,7 +62,7 @@ class TrainConfig(object): ...@@ -62,7 +62,7 @@ class TrainConfig(object):
# process data # process data
if 'dataset' in kwargs: if 'dataset' in kwargs:
dataflow = kwargs.pop('dataset') dataflow = kwargs.pop('dataset')
logger.warn("[Deprecated] TrainConfig.dataset has been deprecated. Use TrainConfig.dataflow instead.") log_deprecated("TrainConfig.dataset", "Use TrainConfig.dataflow instead.")
if dataflow is not None: if dataflow is not None:
assert data is None, "dataflow and data cannot be both presented in TrainConfig!" assert data is None, "dataflow and data cannot be both presented in TrainConfig!"
self.dataflow = dataflow self.dataflow = dataflow
...@@ -75,9 +75,10 @@ class TrainConfig(object): ...@@ -75,9 +75,10 @@ class TrainConfig(object):
if isinstance(callbacks, Callbacks): if isinstance(callbacks, Callbacks):
# keep quiet now because I haven't determined the final API yet. # keep quiet now because I haven't determined the final API yet.
logger.warn("[Deprecated] API of TrainConfig(callbacks=) has changed!") log_deprecated(
logger.warn("[Deprecated] Please change the argument 'callbacks=' to a *list* of " "TrainConfig(callbacks=Callbacks([...]))",
"callbacks without StatPrinter().") "Change the argument 'callbacks=' to a *list* of callbacks without StatPrinter().")
callbacks = callbacks.cbs[:-1] # the last one is StatPrinter() callbacks = callbacks.cbs[:-1] # the last one is StatPrinter()
assert_type(callbacks, list) assert_type(callbacks, list)
if extra_callbacks is None: if extra_callbacks is None:
...@@ -102,8 +103,7 @@ class TrainConfig(object): ...@@ -102,8 +103,7 @@ class TrainConfig(object):
if steps_per_epoch is None: if steps_per_epoch is None:
steps_per_epoch = kwargs.pop('step_per_epoch', None) steps_per_epoch = kwargs.pop('step_per_epoch', None)
if steps_per_epoch is not None: if steps_per_epoch is not None:
# TODO deprecate @Mar.27 log_deprecated("step_per_epoch", "Use steps_per_epoch instead!", "2017-03-27")
logger.warn("[Deprecated] Use steps_per_epoch instead of step_per_epoch!")
if steps_per_epoch is None: if steps_per_epoch is None:
try: try:
if dataflow is not None: if dataflow is not None:
...@@ -138,9 +138,7 @@ class TrainConfig(object): ...@@ -138,9 +138,7 @@ class TrainConfig(object):
assert len(kwargs) == 0, 'Unknown arguments: {}'.format(str(kwargs.keys())) assert len(kwargs) == 0, 'Unknown arguments: {}'.format(str(kwargs.keys()))
def set_tower(self, nr_tower=None, tower=None): def set_tower(self, nr_tower=None, tower=None):
# this is a deprecated function log_deprecated("config.set_tower", "Set config.tower or config.nr_tower directly.", "2017-03-15")
# TODO Deprecate @ Mar 15
logger.warn("config.set_tower is deprecated. set config.tower or config.nr_tower directly")
assert nr_tower is None or tower is None, "Cannot set both nr_tower and tower!" assert nr_tower is None or tower is None, "Cannot set both nr_tower and tower!"
if nr_tower: if nr_tower:
tower = list(range(nr_tower)) tower = list(range(nr_tower))
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
import tensorflow as tf import tensorflow as tf
from ..utils import logger from ..utils import log_deprecated
from ..tfutils.tower import TowerContext from ..tfutils.tower import TowerContext
from ..tfutils.gradproc import apply_grad_processors from ..tfutils.gradproc import apply_grad_processors
from .input_data import QueueInput, FeedfreeInput from .input_data import QueueInput, FeedfreeInput
...@@ -118,8 +118,7 @@ def QueueInputTrainer(config, input_queue=None, predict_tower=None): ...@@ -118,8 +118,7 @@ def QueueInputTrainer(config, input_queue=None, predict_tower=None):
""" """
config.data = QueueInput(config.dataflow, input_queue) config.data = QueueInput(config.dataflow, input_queue)
if predict_tower is not None: if predict_tower is not None:
logger.warn("[Deprecated] Argument `predict_tower` is deprecated for trainer. " log_deprecated("Argument `predict_tower` in trainer", "Use TrainConfig(predict_tower=...) instead!")
"Use TrainConfig(predict_tower=...) instead!")
config.predict_tower = predict_tower config.predict_tower = predict_tower
assert len(config.tower) == 1, \ assert len(config.tower) == 1, \
"QueueInputTrainer doesn't support multigpu! Use Sync/AsyncMultiGPUTrainer instead." "QueueInputTrainer doesn't support multigpu! Use Sync/AsyncMultiGPUTrainer instead."
......
...@@ -8,7 +8,7 @@ import itertools ...@@ -8,7 +8,7 @@ import itertools
import re import re
from six.moves import zip, range from six.moves import zip, range
from ..utils import logger from ..utils import logger, log_deprecated
from ..utils.naming import SUMMARY_BACKUP_KEYS from ..utils.naming import SUMMARY_BACKUP_KEYS
from ..utils.concurrency import LoopThread from ..utils.concurrency import LoopThread
from ..tfutils.tower import TowerContext from ..tfutils.tower import TowerContext
...@@ -93,8 +93,7 @@ class SyncMultiGPUTrainer(MultiGPUTrainer, ...@@ -93,8 +93,7 @@ class SyncMultiGPUTrainer(MultiGPUTrainer,
assert isinstance(self._input_method, QueueInput) assert isinstance(self._input_method, QueueInput)
if predict_tower is not None: if predict_tower is not None:
logger.warn("[Deprecated] Argument `predict_tower` is deprecated for trainer. " log_deprecated("Argument `predict_tower` in trainer", "Use TrainConfig(predict_tower=...) instead!")
"Use TrainConfig.predict_tower instead!")
config.predict_tower = predict_tower config.predict_tower = predict_tower
super(SyncMultiGPUTrainer, self).__init__(config) super(SyncMultiGPUTrainer, self).__init__(config)
...@@ -188,8 +187,7 @@ class AsyncMultiGPUTrainer(MultiGPUTrainer, ...@@ -188,8 +187,7 @@ class AsyncMultiGPUTrainer(MultiGPUTrainer,
super(AsyncMultiGPUTrainer, self).__init__(config) super(AsyncMultiGPUTrainer, self).__init__(config)
if predict_tower is not None: if predict_tower is not None:
logger.warn("[Deprecated] Argument `predict_tower` is deprecated for trainer. " log_deprecated("Argument `predict_tower` in trainer", "Use TrainConfig.predict_tower instead!")
"Use TrainConfig.predict_tower instead!")
config.predict_tower = predict_tower config.predict_tower = predict_tower
self._setup_predictor_factory() self._setup_predictor_factory()
......
...@@ -9,6 +9,8 @@ import inspect ...@@ -9,6 +9,8 @@ import inspect
from datetime import datetime from datetime import datetime
from tqdm import tqdm from tqdm import tqdm
import numpy as np import numpy as np
import functools
from . import logger
__all__ = ['change_env', __all__ = ['change_env',
...@@ -17,6 +19,8 @@ __all__ = ['change_env', ...@@ -17,6 +19,8 @@ __all__ = ['change_env',
'get_tqdm', 'get_tqdm',
'execute_only_once', 'execute_only_once',
'building_rtfd', 'building_rtfd',
'log_deprecated',
'deprecated'
] ]
...@@ -62,8 +66,7 @@ def execute_only_once(): ...@@ -62,8 +66,7 @@ def execute_only_once():
first time and False afterwards. first time and False afterwards.
Returns: Returns:
bool: whether this is the first time this function gets called from bool: whether this is the first time this function gets called from this line of code.
this line of code.
Example: Example:
.. code-block:: python .. code-block:: python
...@@ -116,3 +119,64 @@ def building_rtfd(): ...@@ -116,3 +119,64 @@ def building_rtfd():
""" """
return os.environ.get('READTHEDOCS') == 'True' \ return os.environ.get('READTHEDOCS') == 'True' \
or os.environ.get('TENSORPACK_DOC_BUILDING') or os.environ.get('TENSORPACK_DOC_BUILDING')
def log_deprecated(name="", text="", eos=""):
"""
Log deprecation warning.
Args:
name (str): name of the deprecated item.
text (str, optional): information about the deprecation.
eos (str, optional): end of service date such as "YYYY-MM-DD".
"""
assert name or text
if eos:
eos = "after " + datetime(*map(int, eos.split("-"))).strftime("%d %b")
if name:
if eos:
warn_msg = "%s will be deprecated on %s. %s" % (name, eos, text)
else:
warn_msg = "%s was deprecated. %s" % (name, text)
else:
warn_msg = text
if eos:
warn_msg += " Legacy period ends %s" % eos
logger.warn("[Deprecated] " + warn_msg)
def deprecated(text="", eos=""):
"""
Args:
text, eos: same as :func:`log_deprecated`.
Returns:
a decorator which deprecates the function.
Example:
.. code-block:: python
@deprecated("Explanation of what to do instead.", "2017-11-4")
def foo(...):
pass
"""
def get_location():
import inspect
frame = inspect.currentframe()
if frame:
callstack = inspect.getouterframes(frame)[-1]
return '%s:%i' % (callstack[1], callstack[2])
else:
stack = inspect.stack(0)
entry = stack[2]
return '%s:%i' % (entry[1], entry[2])
def deprecated_inner(func):
@functools.wraps(func)
def new_func(*args, **kwargs):
name = "{} [{}]".format(func.__name__, get_location())
log_deprecated(name, text, eos)
return func(*args, **kwargs)
return new_func
return deprecated_inner
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment