def from_yaml_to_current(yaml_str: str) -> current.RunDescriber: """ Deserialize a YAML string into a RunDescriber of the current version """ yaml = YAML() # yaml.load returns an OrderedDict, but we need a dict ser = cast(RunDescriberDicts, dict(yaml.load(yaml_str))) return from_dict_to_current(ser)
def from_yaml(cls, yaml_str: str) -> 'RunDescriber': """ Parse a yaml string (the return of `to_yaml`) into a RunDescriber object """ yaml = YAML() # yaml.load returns an OrderedDict, but we need a dict ser = dict(yaml.load(yaml_str)) return cls.deserialize(ser)
def to_yaml(self) -> str: """ Output the run description as a yaml string """ yaml = YAML() with io.StringIO() as stream: yaml.dump(self.serialize(), stream=stream) output = stream.getvalue() return output
def to_yaml_for_storage(desc: current.RunDescriber) -> str: """ Serialize the given RunDescriber to YAML as a RunDescriber of the version for storage """ yaml = YAML() with io.StringIO() as stream: yaml.dump(to_dict_for_storage(desc), stream=stream) output = stream.getvalue() return output
def test_yaml_creation_and_loading(some_paramspecs): yaml = YAML() for group in some_paramspecs.values(): paramspecs = group.values() idp = InterDependencies(*paramspecs) desc = RunDescriber(interdeps=idp) yaml_str = desc.to_yaml() assert isinstance(yaml_str, str) ydict = dict(yaml.load(yaml_str)) assert list(ydict.keys()) == ['interdependencies'] new_desc = RunDescriber.from_yaml(yaml_str) assert new_desc == desc
def test_yaml_creation_and_loading(some_interdeps): yaml = YAML() for idps in some_interdeps: desc = RunDescriber(interdeps=idps) yaml_str = serial.to_yaml_for_storage(desc) assert isinstance(yaml_str, str) ydict = dict(yaml.load(yaml_str)) assert list(ydict.keys()) == ['version', 'interdependencies'] assert ydict['version'] == serial.STORAGE_VERSION new_desc = serial.from_yaml_to_current(yaml_str) assert new_desc == desc
def load_config(self, config: Union[str, IO[AnyStr]]) -> None: """ Loads a configuration from a supplied string or file/stream handle. The string or file/stream is expected to be YAML formatted Loading of a configuration will update the snapshot of the station and make the instruments described in the config file available for instantiation with the :meth:`load_instrument` method. Additionally the shortcut methods ``load_<instrument_name>`` will be updated. """ def update_station_configuration_snapshot() -> None: self.config = StationConfig(self._config) def update_load_instrument_methods() -> None: # create shortcut methods to instantiate instruments via # `load_<instrument_name>()` so that autocompletion can be used # first remove methods that have been added by a previous # :meth:`load_config_file` call while len(self._added_methods): delattr(self, self._added_methods.pop()) # add shortcut methods for instrument_name in self._instrument_config.keys(): method_name = f'load_{instrument_name}' if method_name.isidentifier(): setattr( self, method_name, partial(self.load_instrument, identifier=instrument_name)) self._added_methods.append(method_name) else: log.warning(f'Invalid identifier: ' f'for the instrument {instrument_name} no ' f'lazy loading method {method_name} could ' 'be created in the Station.') # Load template schema, and thereby don't fail on instruments that are # not included in the user schema. yaml = YAML().load(config) with open(SCHEMA_TEMPLATE_PATH) as f: schema = json.load(f) try: jsonschema.validate(yaml, schema) except jsonschema.exceptions.ValidationError as e: message = e.message + '\n config:\n' if isinstance(config, str): message += config else: config.seek(0) message += config.read() warnings.warn(message, ValidationWarning) self._config = yaml self._instrument_config = self._config['instruments'] update_station_configuration_snapshot() update_load_instrument_methods()
def test_station_config_can_be_loaded_from_snapshot(example_station): assert station_config_has_been_loaded(example_station) # ensure that we can correctly dump config which is a subclass of UserDict configdump = json.dumps(example_station.config, cls=NumpyJSONEncoder) # as this is now a regular dict we can load it back loaded_config = json.loads(configdump) # now lets ensure that we can recreate the # station from the loaded config # first we need to get a yaml repr of the data yaml = YAML() with StringIO() as output: yaml.dump(loaded_config, output) yaml_repr = output.getvalue() # which we can then reload into the station new_station = Station(default=False) new_station.load_config(yaml_repr) assert example_station.config == new_station.config
def load_config(self, config: Union[str, IO[AnyStr]]) -> None: """ Loads a configuration from a supplied string or file/stream handle. Loading of a configuration will update the snapshot of the station and make the instruments described in the config file available for instantiation with the :meth:`load_instrument` method. Additionally the shortcut methods ``load_<instrument_name>`` will be updated. """ def update_station_configuration_snapshot(): class StationConfig(UserDict): def snapshot(self, update=True): return self self.components['config'] = StationConfig(self._config) def update_load_instrument_methods(): # create shortcut methods to instantiate instruments via # `load_<instrument_name>()` so that autocompletion can be used # first remove methods that have been added by a previous # :meth:`load_config_file` call while len(self._added_methods): delattr(self, self._added_methods.pop()) # add shortcut methods for instrument_name in self._instrument_config.keys(): method_name = f'load_{instrument_name}' if method_name.isidentifier(): setattr( self, method_name, partial(self.load_instrument, identifier=instrument_name)) self._added_methods.append(method_name) else: log.warning(f'Invalid identifier: ' + f'for the instrument {instrument_name} no ' + f'lazy loading method {method_name} could ' + 'be created in the Station.') self._config = YAML().load(config) self._instrument_config = self._config['instruments'] update_station_configuration_snapshot() update_load_instrument_methods()