Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Work on deprecation warnings #151

Merged
merged 3 commits into from
Dec 18, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 14 additions & 11 deletions traitlets/config/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
)

from traitlets.traitlets import (
Unicode, List, Enum, Dict, Instance, TraitError
Unicode, List, Enum, Dict, Instance, TraitError, observe, default
)
from ipython_genutils.importstring import import_item
from ipython_genutils.text import indent, wrap_paragraphs, dedent
Expand Down Expand Up @@ -177,7 +177,7 @@ def _log_format_changed(self, name, old, new):
_log_formatter = self._log_formatter_cls(fmt=new, datefmt=self.log_datefmt)
_log_handler.setFormatter(_log_formatter)


@default('log')
def _log_default(self):
"""Start logging for this application.

Expand Down Expand Up @@ -215,12 +215,14 @@ def _log_default(self):
# this must be a dict of two-tuples, the first element being the Config/dict
# and the second being the help string for the flag
flags = Dict()
def _flags_changed(self, name, old, new):
@observe('flags')
def _flags_changed(self, change):
"""ensure flags dict is valid"""
for key,value in iteritems(new):
assert len(value) == 2, "Bad flag: %r:%s"%(key,value)
assert isinstance(value[0], (dict, Config)), "Bad flag: %r:%s"%(key,value)
assert isinstance(value[1], string_types), "Bad flag: %r:%s"%(key,value)
new = change['new']
for key, value in new.items():
assert len(value) == 2, "Bad flag: %r:%s" % (key, value)
assert isinstance(value[0], (dict, Config)), "Bad flag: %r:%s" % (key, value)
assert isinstance(value[1], string_types), "Bad flag: %r:%s" % (key, value)


# subcommands for launching other applications
Expand All @@ -242,11 +244,12 @@ def __init__(self, **kwargs):
# options and config files.
if self.__class__ not in self.classes:
self.classes.insert(0, self.__class__)

def _config_changed(self, name, old, new):
SingletonConfigurable._config_changed(self, name, old, new)

@observe('config')
def _config_changed(self, change):
super(Application, self)._config_changed(change)
self.log.debug('Config changed:')
self.log.debug(repr(new))
self.log.debug(repr(change['new']))

@catch_config_error
def initialize(self, argv=None):
Expand Down
10 changes: 5 additions & 5 deletions traitlets/config/configurable.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,10 @@

from __future__ import print_function

import logging
from copy import deepcopy

from .loader import Config, LazyConfigValue
from traitlets.traitlets import HasTraits, Instance
from traitlets.traitlets import HasTraits, Instance, observe, default
from ipython_genutils.text import indent, dedent, wrap_paragraphs
from ipython_genutils.py3compat import iteritems

Expand Down Expand Up @@ -162,8 +161,8 @@ def _load_config(self, cfg, section_names=None, traits=None):
self.log.warning(u"Config option `{option}` not recognized by `{klass}`, do you mean one of : `{matches}`"
.format(option=name, klass=type(self).__name__, matches=' ,'.join(matches)))


def _config_changed(self, name, old, new):
@observe('config')
def _config_changed(self, change):
"""Update all the class traits having ``config=True`` in metadata.

For any class trait with a ``config`` metadata attribute that is
Expand All @@ -177,7 +176,7 @@ def _config_changed(self, name, old, new):
# classes that are Configurable subclasses. This starts with Configurable
# and works down the mro loading the config for each section.
section_names = self.section_names()
self._load_config(new, traits=traits, section_names=section_names)
self._load_config(change['new'], traits=traits, section_names=section_names)

def update_config(self, config):
"""Update config and trigger reload of config via trait events"""
Expand Down Expand Up @@ -329,6 +328,7 @@ class LoggingConfigurable(Configurable):
"""

log = Instance('logging.Logger')
@default('log')
def _log_default(self):
from traitlets import log
return log.get_logger()
Expand Down
59 changes: 45 additions & 14 deletions traitlets/traitlets.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
ClassTypes = (ClassType, type)
except:
ClassTypes = (type,)
from warnings import warn
from warnings import warn, warn_explicit

from ipython_genutils import py3compat
from ipython_genutils.py3compat import iteritems, string_types
Expand Down Expand Up @@ -90,6 +90,29 @@ class TraitError(Exception):
#-----------------------------------------------------------------------------


def _deprecated_method(method, cls, method_name, msg):
"""Show deprecation warning about a magic method definition.

Uses warn_explicit to bind warning to method definition instead of triggering code,
which isn't relevant.
"""
warn_msg = "{classname}.{method_name} is deprecated: {msg}".format(
classname=cls.__name__, method_name=method_name, msg=msg
)

for parent in inspect.getmro(cls):
if method_name in parent.__dict__:
cls = parent
break
try:
fname = inspect.getsourcefile(method) or "<unknown>"
lineno = inspect.getsourcelines(method)[1] or 0
except TypeError as e:
# Failed to inspect for some reason
warn(warn_msg + ('\n(inspection failed)' % e), DeprecationWarning)
else:
warn_explicit(warn_msg, DeprecationWarning, fname, lineno)

def class_of(object):
""" Returns a string containing the class name of an object with the
correct indefinite article ('a' or 'an') preceding it (e.g., 'an Image',
Expand Down Expand Up @@ -387,8 +410,15 @@ def __init__(self, default_value=Undefined, allow_none=None, read_only=None, hel
)

if len(metadata) > 0:
warn("metadata %s was set from the constructor. Metadata should be set using the .tag() method, e.g., Int().tag(key1='value1', key2='value2')"%(metadata,),
DeprecationWarning, stacklevel=2)
stacklevel = 1
f = inspect.currentframe()
# count supers to determine stacklevel for warning
while f.f_code.co_name == '__init__':
stacklevel += 1
f = f.f_back

warn("metadata %s was set from the constructor. Metadata should be set using the .tag() method, e.g., Int().tag(key1='value1', key2='value2')" % (metadata,),
DeprecationWarning, stacklevel=stacklevel)
if len(self.metadata) > 0:
self.metadata = self.metadata.copy()
self.metadata.update(metadata)
Expand Down Expand Up @@ -451,9 +481,9 @@ def _dynamic_default_callable(self, obj):
meth_name = '_%s_default' % self.name
for cls in mro[:mro.index(self.this_class) + 1]:
if meth_name in cls.__dict__:
warn("_[traitname]_default handlers are deprecated: use default"
" decorator instead", DeprecationWarning, stacklevel=2)
return getattr(obj, meth_name)
method = getattr(obj, meth_name)
_deprecated_method(method, cls, meth_name, "use @default decorator instead.")
return method

return getattr(self, 'make_dynamic_default', None)

Expand Down Expand Up @@ -538,9 +568,10 @@ def _cross_validate(self, obj, value):
proposal = {'trait': self, 'value': value, 'owner': obj}
value = obj._trait_validators[self.name](obj, proposal)
elif hasattr(obj, '_%s_validate' % self.name):
warn("_[traitname]_validate handlers are deprecated: use validate"
" decorator instead", DeprecationWarning, stacklevel=2)
cross_validate = getattr(obj, '_%s_validate' % self.name)
meth_name = '_%s_validate' % self.name
cross_validate = getattr(obj, meth_name)
_deprecated_method(cross_validate, obj.__class__, meth_name,
"use @validate decorator instead.")
value = cross_validate(value, self)
return value

Expand Down Expand Up @@ -995,9 +1026,9 @@ def notify_change(self, change):
if hasattr(self, magic_name):
class_value = getattr(self.__class__, magic_name)
if not isinstance(class_value, ObserveHandler):
warn("_[traitname]_changed handlers are deprecated: use observe"
" and unobserve instead", DeprecationWarning, stacklevel=2)
cb = getattr(self, '_%s_changed' % name)
_deprecated_method(class_value, self.__class__, magic_name,
"use @observe and @unobserve instead.")
cb = getattr(self, magic_name)
# Only append the magic method if it was not manually registered
if cb not in callables:
callables.append(_callback_wrapper(cb))
Expand Down Expand Up @@ -1174,8 +1205,8 @@ def _register_validator(self, handler, names):
if hasattr(self, magic_name):
class_value = getattr(self.__class__, magic_name)
if not isinstance(class_value, ValidateHandler):
warn("_[traitname]_validate handlers are deprecated: use validate"
" decorator instead", DeprecationWarning, stacklevel=2)
_deprecated_method(class_value, self.__class, magic_name,
"use @validate decorator instead.")
for name in names:
self._trait_validators[name] = handler

Expand Down