Skip to content
Draft
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
6 changes: 6 additions & 0 deletions tests/config/test_configurable.py
Original file line number Diff line number Diff line change
Expand Up @@ -969,3 +969,9 @@ def test_logger_adapter(caplog, capsys):
app.log.info("test message")

assert "adapted test message" in capsys.readouterr().err


def test_get_log_handler_deprecated():
app = Application(log=logging.getLogger("test_get_log_handler_deprecated"))
with pytest.deprecated_call(match="_get_log_handler has been deprecated"):
app._get_log_handler()
8 changes: 8 additions & 0 deletions tests/config/test_loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,14 @@ def test_auto_section(self):
del c.A
self.assertEqual(c.A, Config())

def test_has_key_deprecated(self):
c = Config()
c.a = 10
with pytest.deprecated_call(match="Config.has_key has been deprecated"):
assert c.has_key("a")
with pytest.deprecated_call(match="Config.has_key has been deprecated"):
assert not c.has_key("b")

def test_merge_doesnt_exist(self):
c1 = Config()
c2 = Config()
Expand Down
11 changes: 11 additions & 0 deletions tests/test_traitlets.py
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,17 @@ def test_trait_types_dict_deprecated(self):
class C(HasTraits):
t = Dict(Int)

def test_no_default_specified_deprecated(self):
import traitlets.traitlets as tt

with expected_warnings(["NoDefaultSpecified is deprecated"]):
value = tt.NoDefaultSpecified
assert value is tt.Undefined
# still discoverable
assert "NoDefaultSpecified" in dir(tt)
with pytest.raises(AttributeError):
tt.this_does_not_exist

def test_long_deprecated_aliases(self):
for cls, replacement in [(Long, "Integer"), (CLong, "CInt")]:
with expected_warnings([f"`{cls.__name__}` trait is deprecated"]):
Expand Down
12 changes: 10 additions & 2 deletions traitlets/config/configurable.py
Original file line number Diff line number Diff line change
Expand Up @@ -506,9 +506,17 @@ def _get_log_handler(self) -> logging.Handler | None:

Returns None if none can be found

Deprecated, this now returns the first log handler which may or may
not be the default one.
.. deprecated:: 5.2

This now returns the first log handler, which may or may not be
the default one. Use ``self.log.handlers`` directly instead.
"""
warnings.warn(
"Configurable._get_log_handler has been deprecated since traitlets 5.2 - 2022,"
" use the `.handlers` attribute of the logger directly.",
DeprecationWarning,
stacklevel=2,
)
if not self.log:
return None
logger: logging.Logger = (
Expand Down
11 changes: 9 additions & 2 deletions traitlets/config/loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -304,8 +304,15 @@ def __contains__(self, key: t.Any) -> bool:

return super().__contains__(key)

# .has_key is deprecated for dictionaries.
has_key = __contains__
def has_key(self, key: t.Any) -> bool:
"""Deprecated since traitlets 4.0 - 2015, use ``key in config`` instead."""
warnings.warn(
"Config.has_key has been deprecated since traitlets 4.0 - 2015,"
" use `key in config` instead.",
DeprecationWarning,
stacklevel=2,
)
return self.__contains__(key)

def _has_section(self, key: str) -> bool:
return _is_section_key(key) and key in self
Expand Down
27 changes: 25 additions & 2 deletions traitlets/traitlets.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,8 +155,31 @@
""",
)

# Deprecated alias
NoDefaultSpecified = Undefined
# Deprecated aliases, kept accessible through the module-level ``__getattr__``
# below so that reaching for them emits a DeprecationWarning (PEP 562).
_deprecated_module_attrs = {
# name: (current name, message)
"NoDefaultSpecified": (
"Undefined",
(
"traitlets.traitlets.NoDefaultSpecified is deprecated since traitlets 4.0 - 2015,"
" use traitlets.Undefined instead."
),
),
}


def __getattr__(name: str) -> t.Any:
try:
target, msg = _deprecated_module_attrs[name]
except KeyError:
raise AttributeError(f"module {__name__!r} has no attribute {name!r}") from None
warn(msg, DeprecationWarning, stacklevel=2)
return globals()[target]


def __dir__() -> list[str]:
return sorted([*globals(), *_deprecated_module_attrs])


class TraitError(Exception):
Expand Down
Loading