Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
def _validate_context_lookups(
path: Path,
lookups: Iterable[str],
feed_names: List[str],
) -> None:
# Changing this? Also change context lookups in
# `routemaster.context.Context`
VALID_TOP_LEVEL = ('feeds', 'history', 'metadata')
for lookup in lookups:
location, *rest = lookup.split('.')
if location not in VALID_TOP_LEVEL:
valid_top_level = join_comma_or(f"'{x}'" for x in VALID_TOP_LEVEL)
raise ConfigError(
f"Invalid context lookup at {'.'.join(path)}: key {lookup} "
f"must start with one of {valid_top_level}.",
)
if location == 'feeds':
feed_name = rest[0]
if feed_name not in feed_names:
valid_names = join_comma_or(f"'{x}'" for x in feed_names)
raise ConfigError(
f"Invalid feed name at {'.'.join(path)}: key {lookup} "
f"references unknown feed '{feed_name}' (configured "
def _load_trigger(path: Path, yaml_trigger: Yaml) -> Trigger:
if len(yaml_trigger.keys()) > 1: # pragma: no branch
raise ConfigError( # pragma: no cover
f"Trigger at path {'.'.join(path)} cannot be of multiple types.",
)
if 'time' in yaml_trigger:
return _load_time_trigger(path, yaml_trigger)
elif 'metadata' in yaml_trigger:
return _load_metadata_trigger(path, yaml_trigger)
elif 'interval' in yaml_trigger: # pragma: no branch
return _load_interval_trigger(path, yaml_trigger)
elif yaml_trigger.get('event') == 'entry':
return OnEntryTrigger()
else:
raise ConfigError( # pragma: no cover
f"Trigger at path {'.'.join(path)} must be a time, interval, or "
f"metadata trigger.",
def _schema_validate(config: Yaml) -> None:
# Load schema from package resources
schema_raw = pkg_resources.resource_string(
'routemaster.config',
'schema.yaml',
).decode('utf-8')
schema_yaml = yaml.load(schema_raw)
try:
jsonschema.validate(config, schema_yaml)
except jsonschema.exceptions.ValidationError:
raise ConfigError("Could not validate config file against schema.")
def _load_state(path: Path, yaml_state: Yaml, feed_names: List[str]) -> State:
if 'action' in yaml_state and 'gate' in yaml_state: # pragma: no branch
raise ConfigError( # pragma: no cover
f"State at path {'.'.join(path)} cannot be both a gate and an "
f"action.",
)
if 'action' in yaml_state:
return _load_action(path, yaml_state, feed_names)
elif 'gate' in yaml_state: # pragma: no branch
return _load_gate(path, yaml_state, feed_names)
else:
raise ConfigError( # pragma: no cover
f"State at path {'.'.join(path)} must be either a gate or an "
f"action.",
def _load_time_trigger(path: Path, yaml_trigger: Yaml) -> TimeTrigger:
format_ = '%Hh%Mm'
try:
dt = datetime.datetime.strptime(str(yaml_trigger['time']), format_)
trigger = dt.time()
except ValueError: # pragma: no cover
raise ConfigError(
f"Time trigger '{yaml_trigger['time']}' at path {'.'.join(path)} "
f"does not meet expected format: {format_}.",
) from None
return TimeTrigger(time=trigger)
def load_database_config() -> DatabaseConfig:
"""Load the database config from the environment."""
port_string = os.environ.get('DB_PORT', 5432)
try:
port = int(port_string)
except ValueError:
raise ConfigError(
f"Could not parse DB_PORT as an integer: '{port_string}'.",
)
return DatabaseConfig(
host=os.environ.get('DB_HOST', 'localhost'),
port=port,
name=os.environ.get('DB_NAME', 'routemaster'),
username=os.environ.get('DB_USER', 'routemaster'),
password=os.environ.get('DB_PASS', ''),
)
def load_config(yaml: Yaml) -> Config:
"""Unpack a parsed YAML file into a `Config` object."""
_schema_validate(yaml)
try:
yaml_state_machines = yaml['state_machines']
except KeyError: # pragma: no cover
raise ConfigError(
"No top-level state_machines key defined.",
) from None
yaml_logging_plugins = yaml.get('plugins', {}).get('logging', [])
return Config(
state_machines={
name: _load_state_machine(
['state_machines', name],
name,
yaml_state_machine,
)
for name, yaml_state_machine in yaml_state_machines.items()
},
database=load_database_config(),
logging_plugins=_load_logging_plugins(yaml_logging_plugins),
def _load_state(path: Path, yaml_state: Yaml, feed_names: List[str]) -> State:
if 'action' in yaml_state and 'gate' in yaml_state: # pragma: no branch
raise ConfigError( # pragma: no cover
f"State at path {'.'.join(path)} cannot be both a gate and an "
f"action.",
)
if 'action' in yaml_state:
return _load_action(path, yaml_state, feed_names)
elif 'gate' in yaml_state: # pragma: no branch
return _load_gate(path, yaml_state, feed_names)
else:
raise ConfigError( # pragma: no cover
f"State at path {'.'.join(path)} must be either a gate or an "
f"action.",