def run(configfile, unsafe: bool, loop: Optional[str], service: Optional[str]): # Read the configuration from the supplied YAML files config = {} # type: Dict[str, Any] for path in configfile: config_data = yaml.load(path, Loader=Loader) if unsafe else yaml.safe_load(path) assert isinstance(config_data, dict), 'the document root element must be a dictionary' config = merge_config(config, config_data) # Override the event loop policy if specified if loop: config['event_loop_policy'] = loop services = config.pop('services', {}) if not isinstance(services, dict): raise click.ClickException('The "services" key must be a dict, not {}'.format( qualified_name(services))) # If "component" was defined, use that as the default service if one has not been defined yet if 'component' in config: component = config.pop('component') services.setdefault('default', dict(component=component)) # Try to figure out which service to launch service = service or os.getenv('ASPHALT_SERVICE') if len(services) == 0: raise click.ClickException('No services have been defined') elif service: try: service_config = services[service] except KeyError: raise click.ClickException( 'Service {!r} has not been defined'.format(service)) from None elif len(services) == 1: service_config = next(iter(services.values())) elif 'default' in services: service_config = services['default'] else: raise click.ClickException( 'Multiple services present in configuration file but no default service has been ' 'defined and no service was explicitly selected with -s / --service') # Merge the service-level configuration with the top level one config = merge_config(config, service_config) # Start the application run_application(**config)
def run(configfile, unsafe: bool, loop: Optional[str], service: Optional[str]): # Read the configuration from the supplied YAML files config = {} # type: Dict[str, Any] for path in configfile: config_data = yaml.load(path, Loader=Loader if unsafe else SafeLoader) assert isinstance(config_data, dict), 'the document root element must be a dictionary' config = merge_config(config, config_data) # Override the event loop policy if specified if loop: config['event_loop_policy'] = loop services = config.pop('services', {}) if not isinstance(services, dict): raise click.ClickException('The "services" key must be a dict, not {}'.format( qualified_name(services))) # If "component" was defined, use that as the default service if one has not been defined yet if 'component' in config: component = config.pop('component') services.setdefault('default', dict(component=component)) # Try to figure out which service to launch service = service or os.getenv('ASPHALT_SERVICE') if len(services) == 0: raise click.ClickException('No services have been defined') elif service: try: service_config = services[service] except KeyError: raise click.ClickException( 'Service {!r} has not been defined'.format(service)) from None elif len(services) == 1: service_config = next(iter(services.values())) elif 'default' in services: service_config = services['default'] else: raise click.ClickException( 'Multiple services present in configuration file but no default service has been ' 'defined and no service was explicitly selected with -s / --service') # Merge the service-level configuration with the top level one config = merge_config(config, service_config) # Start the application run_application(**config)
def run(configfile, unsafe: bool, loop: Optional[str]): # Read the configuration from the supplied YAML files config = {} for path in configfile: config_data = yaml.load(path) if unsafe else yaml.safe_load(path) assert isinstance(config_data, dict), 'the document root element must be a dictionary' config = merge_config(config, config_data) # Override the event loop policy if specified if loop: config['event_loop_policy'] = loop # Start the application run_application(**config)
def test_merge_config(overrides): original = {'a': 1, 'b': {'x': 2, 'y': 3, 'z': {'r': [1, 2], 's': [3, 4]}}} expected = { 'a': 2, 'foo': 6, 'b': { 'x': 5, 'y': 3, 'z': { 'r': 'bar', 's': [6, 7] } } } assert merge_config(original, overrides) == expected
def add_component(self, alias: str, type: Union[str, type] = None, **config): """ Add a child component. This will instantiate a component class, as specified by the ``type`` argument. If the second argument is omitted, the value of ``alias`` is used as its value. The locally given configuration can be overridden by component configuration parameters supplied to the constructor (via the ``components`` argument). When configuration values are provided both as keyword arguments to this method and component configuration through the ``components`` constructor argument, the configurations are merged together using :func:`~asphalt.core.util.merge_config` in a way that the configuration values from the ``components`` argument override the keyword arguments to this method. :param alias: a name for the component instance, unique within this container :param type: entry point name or :class:`Component` subclass or a ``module:varname`` reference to one :param config: keyword arguments passed to the component's constructor """ assert check_argument_types() if not isinstance(alias, str) or not alias: raise TypeError('component_alias must be a nonempty string') if alias in self.child_components: raise ValueError( 'there is already a child component named "{}"'.format(alias)) # Allow the external configuration to override the constructor arguments override_config = self.component_configs.get(alias) or {} config = merge_config(config, override_config) component = component_types.create_object(type or alias, **config) self.child_components[alias] = component
def add_component(self, alias: str, type: Union[str, type] = None, **config): """ Add a child component. This will instantiate a component class, as specified by the ``type`` argument. If the second argument is omitted, the value of ``alias`` is used as its value. The locally given configuration can be overridden by component configuration parameters supplied to the constructor (via the ``components`` argument). When configuration values are provided both as keyword arguments to this method and component configuration through the ``components`` constructor argument, the configurations are merged together using :func:`~asphalt.core.util.merge_config` in a way that the configuration values from the ``components`` argument override the keyword arguments to this method. :param alias: a name for the component instance, unique within this container :param type: entry point name or :class:`Component` subclass or a ``module:varname`` reference to one :param config: keyword arguments passed to the component's constructor """ assert check_argument_types() if not isinstance(alias, str) or not alias: raise TypeError('component_alias must be a nonempty string') if alias in self.child_components: raise ValueError('there is already a child component named "{}"'.format(alias)) config['type'] = type or alias # Allow the external configuration to override the constructor arguments override_config = self.component_configs.get(alias) or {} config = merge_config(config, override_config) component = component_types.create_object(**config) self.child_components[alias] = component
def test_merge_config_none_args(original, overrides): assert merge_config(original, overrides) == {'a': 1}
def test_merge_config(overrides): original = {'a': 1, 'b': {'x': 2, 'y': 3, 'z': {'r': [1, 2], 's': [3, 4]}}} expected = {'a': 2, 'foo': 6, 'b': {'x': 5, 'y': 3, 'z': {'r': 'bar', 's': [6, 7]}}} assert merge_config(original, overrides) == expected