Skip to content

Commit

Permalink
feat(trait.ipython#99): impl Trait-level metadata[ENV-VAR]
Browse files Browse the repository at this point in the history
+ When getting trait-value, try 1st env-var, then fallback to defaults.
  • Loading branch information
ankostis committed Aug 12, 2017
1 parent 62183d9 commit 88be1d9
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 11 deletions.
24 changes: 21 additions & 3 deletions traitlets/tests/test_traitlets.py
Original file line number Diff line number Diff line change
Expand Up @@ -2548,7 +2548,7 @@ class C(HasTraits):
a = Unicode('hard default')
def _a_default(self):
return 'default method'

C._a_default = lambda self: 'overridden'
c = C()
assert c.a == 'overridden'
Expand All @@ -2559,7 +2559,7 @@ class C(HasTraits):
@default('a')
def _a_default(self):
return 'default method'

C._a_default = lambda self: 'overridden'
c = C()
assert c.a == 'overridden'
Expand All @@ -2570,8 +2570,26 @@ class C(HasTraits):
@default('a')
def _a_default(self):
return 'default method'

c = C()
c._a_default = lambda self: 'overridden'
assert c.a == 'overridden'

def test_envvar_override_default(monkeypatch):
class A(HasTraits):
b = CInt(allow_none=True).tag(config=True, envvar='MY_ENVVAR')

a = A()
assert a.b == 0

monkeypatch.setenv('MY_ENVVAR', '1')

a = A()
assert a.b == 1
a = A(a=2)
assert a.b == 1

a.b = 3
assert a.b == 3 # Direct assignments override env-var.
a.b = None
assert a.b == None
31 changes: 23 additions & 8 deletions traitlets/traitlets.py
Original file line number Diff line number Diff line change
Expand Up @@ -499,18 +499,33 @@ def init_default_value(self, obj):
obj._trait_values[self.name] = value
return value

def get_env_value(self):
"""
Gets the value of any environment-variable named as `env` metadata.
:return:
the textual value of the environment variable, or None, meaning
that no `envvar` metadata is defined.
"""
env_var = self.metadata.get('envvar')
return env_var and os.environ.get(env_var)

def get(self, obj, cls=None):
## Value origin precendance: assigned-by-code, env-var, defaults.
try:
value = obj._trait_values[self.name]
except KeyError:
# Check for a dynamic initializer.
default = obj.trait_defaults(self.name)
if default is Undefined:
raise TraitError("No default value found for "
"the '%s' trait named '%s' of %r" % (
type(self).__name__, self.name, obj))
except KeyError as ex:
value = self.get_env_value()
if value is None:
# Check for a dynamic initializer.
value = obj.trait_defaults(self.name)
if value is Undefined:
raise TraitError("No default value found for "
"the '%s' trait named '%s' of %r" % (
type(self).__name__, self.name, obj))

with obj.cross_validation_lock:
value = self._validate(obj, default)
value = self._validate(obj, value)
obj._trait_values[self.name] = value
obj._notify_observers(Bunch(
name=self.name,
Expand Down

0 comments on commit 88be1d9

Please sign in to comment.