Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
"""Verify .with_options() restricts configuration"""
config = ConfigManager(
[ConfigDictEnv({"FOO_BAR": "a", "FOO_BAZ": "b", "BAR": "c", "BAZ": "d"})]
)
class SomeComponent(RequiredConfigMixin):
required_config = ConfigOptions()
required_config.add_option("baz", default="", doc="some help here", parser=str)
def __init__(self, config):
self.config = config.with_options(self)
# Create the component with regular config
comp = SomeComponent(config)
assert comp.config("baz") == "d"
with pytest.raises(ConfigurationError):
# This is not a valid option for this component
comp.config("bar")
# Create the component with config in the "foo" namespace
comp2 = SomeComponent(config.with_namespace("foo"))
assert comp2.config("baz") == "b"
with pytest.raises(ConfigurationError):
# This is not a valid option for this component
comp2.config("bar")
def test_with_namespace():
config = ConfigManager(
[ConfigDictEnv({"FOO_BAR": "foobaz", "BAR": "baz", "BAT": "bat"})]
)
# Verify the values first
assert config("bar", namespace=["foo"]) == "foobaz"
assert config("bar") == "baz"
assert config("bat") == "bat"
# Create the namespaced config
config_with_namespace = config.with_namespace("foo")
assert config_with_namespace("bar") == "foobaz"
# Verify 'bat' is not available because it's not in the namespace
with pytest.raises(ConfigurationError):
config_with_namespace("bat")
required_config.add_option("baz", default="", doc="some help here", parser=str)
def __init__(self, config):
self.config = config.with_options(self)
# Create the component with regular config
comp = SomeComponent(config)
assert comp.config("baz") == "d"
with pytest.raises(ConfigurationError):
# This is not a valid option for this component
comp.config("bar")
# Create the component with config in the "foo" namespace
comp2 = SomeComponent(config.with_namespace("foo"))
assert comp2.config("baz") == "b"
with pytest.raises(ConfigurationError):
# This is not a valid option for this component
comp2.config("bar")
def test_parse_env_file():
assert parse_env_file(["PLAN9=outerspace"]) == {"PLAN9": "outerspace"}
with pytest.raises(ConfigurationError) as exc_info:
parse_env_file(["3AMIGOS=infamous"])
assert str(exc_info.value) == 'Invalid variable name "3AMIGOS" in env file (line 1)'
with pytest.raises(ConfigurationError) as exc_info:
parse_env_file(["INVALID-CHAR=value"])
assert (
str(exc_info.value)
== 'Invalid variable name "INVALID-CHAR" in env file (line 1)'
)
with pytest.raises(ConfigurationError) as exc_info:
parse_env_file(["", "MISSING-equals"])
assert str(exc_info.value) == "Env file line missing = operator (line 2)"
def parse_env_file(envfile):
"""Parse the content of an iterable of lines as ``.env``.
Return a dict of config variables.
>>> parse_env_file(['DUDE=Abides'])
{'DUDE': 'Abides'}
"""
data = {}
for line_no, line in enumerate(envfile):
line = line.strip()
if not line or line.startswith("#"):
continue
if "=" not in line:
raise ConfigurationError(
"Env file line missing = operator (line %s)" % (line_no + 1)
)
k, v = line.split("=", 1)
k = k.strip()
if not ENV_KEY_RE.match(k):
raise ConfigurationError(
'Invalid variable name "%s" in env file (line %s)' % (k, (line_no + 1))
)
v = v.strip().strip("'\"")
data[k] = v
return data
def __contains__(self, key):
try:
self.cfg(key)
except ConfigurationError:
return False
return True
def traverse(namespace, d):
cfg = {}
for key, val in d.items():
if isinstance(val, dict):
cfg.update(traverse(namespace + [key], val))
elif isinstance(val, str):
cfg["_".join(namespace + [key]).upper()] = val
else:
# All values should be double-quoted strings so they
# parse as strings; anything else is a configuration
# error at parse-time
raise ConfigurationError(
"Invalid value %r in file %s: values must be double-quoted strings"
% (val, path)
)
return cfg
# older version of this software
PASSWORD = config('PASSWORD', alternate_keys=['SECRET'])
The default value should **always** be a string that is parseable by the
parser. This simplifies thinking about values since **all** values
are strings that are parsed by the parser rather than default values
do one thing and non-default values doa nother. Further, it simplifies
documentation for the user since the default value is an example value.
The parser can be any callable that takes a string value and returns a
parsed value.
"""
if not (default is NO_VALUE or isinstance(default, str)):
raise ConfigurationError("default value %r is not a string" % (default,))
if raw_value:
# If we're returning raw values, then we can just use str which is
# a no-op.
parser = str
else:
parser = get_parser(parser)
def build_msg(*pargs):
return "\n".join([item for item in pargs if item])
# Go through all possible keys
all_keys = [key]
if alternate_keys is not NO_VALUE:
all_keys = all_keys + alternate_keys