Skip to content
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
20 changes: 15 additions & 5 deletions traitlets/config/configurable.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,17 @@ def __init__(self, config=None):

# load kwarg traits, other than config
super(Configurable, self).__init__(**kwargs)

# record traits set by config
config_override_names = set()
def notice_config_override(change):
"""Record traits set by both config and kwargs.

They will need to be overridden again after loading config.
"""
if change.name in kwargs:
config_override_names.add(change.name)
self.observe(notice_config_override)

# load config
if config is not None:
Expand All @@ -93,12 +104,11 @@ def __init__(self, config=None):
else:
# allow _config_default to return something
self._load_config(self.config)
self.unobserve(notice_config_override)

for name in config_override_names:
setattr(self, name, kwargs[name])

# Ensure explicit kwargs are applied after loading config.
# This is usually redundant, but ensures config doesn't override
# explicitly assigned values.
for key, value in kwargs.items():
setattr(self, key, value)

#-------------------------------------------------------------------------
# Static trait notifiations
Expand Down
29 changes: 28 additions & 1 deletion traitlets/config/tests/test_configurable.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import logging
import sys
import warnings
from unittest import TestCase

from pytest import mark
Expand All @@ -18,7 +19,7 @@

from traitlets.traitlets import (
Integer, Float, Unicode, List, Dict, Set, Enum,
_deprecations_shown,
_deprecations_shown, validate,
)

from traitlets.config.loader import Config
Expand Down Expand Up @@ -498,6 +499,32 @@ def _config_default(self):
d2 = DefaultConfigurable()
self.assertIs(d2.config, single.config)
self.assertEqual(d2.a, 5)

def test_kwarg_config_priority(self):
# a, c set in kwargs
# a, b set in config
# verify that:
# - kwargs are set before config
# - kwargs have priority over config
class A(Configurable):
a = Unicode('default', config=True)
b = Unicode('default', config=True)
c = Unicode('default', config=True)
c_during_config = Unicode('never')
@validate('b')
def _record_c(self, proposal):
# setting b from config records c's value at the time
self.c_during_config = self.c
return proposal.value

cfg = Config()
cfg.A.a = 'a-config'
cfg.A.b = 'b-config'
obj = A(a='a-kwarg', c='c-kwarg', config=cfg)
assert obj.a == 'a-kwarg'
assert obj.b == 'b-config'
assert obj.c == 'c-kwarg'
assert obj.c_during_config == 'c-kwarg'


class TestLogger(TestCase):
Expand Down