예제 #1
0
def _unflatten_params_cls(cls: type(Params),
                          parsed_params: dict,
                          prefix: Optional[str] = None,
                          params_to_omit: Optional[Set[str]] = None,
                          params_to_hide: Optional[Set[str]] = None) -> Params:
    """
    Recursively construct a Params class or subclass (handles nested Params classes) using values
    parsed from the command line, and apply units.

    :param cls: The Params class to create an instance of
    :param parsed_params: The params parsed from the command line
    :param prefix: The prefix for all param names
    :param params_to_omit: Params to set to None when de-serializing the parsed params dictionary
    :return: An instance of cls with params set from the parsed params dictionary
    """
    cls_specific_params = {}
    for k, v in cls.__dict__.items():
        if isinstance(v, BaseDescriptor):
            if params_to_omit is not None and k in params_to_omit:
                cls_specific_params[k] = None
                continue
            param_name = prefix + k if k not in parsed_params and prefix is not None else k
            if (params_to_hide is not None and param_name in params_to_hide) or \
                    param_name.startswith('_') or getattr(v, 'hide', False):
                continue
            if getattr(v, 'expand', False):
                unexpanded_param = _extract_expanded_param(
                    parsed_params, param_name, v, prefix)
                cls_specific_params.update({k: unexpanded_param})
            else:
                if isinstance(parsed_params[param_name], Iterable) and \
                        not isinstance(parsed_params[param_name], str):
                    cls_specific_params[k] = [
                        convert_to_si_units(p, getattr(v, 'unit', None))
                        for p in parsed_params[param_name]
                    ]
                else:
                    cls_specific_params[k] = convert_to_si_units(
                        parsed_params[param_name], getattr(v, 'unit', None))
        elif isinstance(v, Params):
            _params_to_omit = _get_omitted_params(v)
            next_prefix = _create_param_name_prefix(
                k, getattr(cls, '__nested_prefixes__', None))
            _prefix = prefix + next_prefix if prefix is not None else next_prefix
            cls_specific_params[k] = _unflatten_params_cls(
                type(v),
                parsed_params,
                prefix=_prefix,
                params_to_omit=_params_to_omit,
                params_to_hide=_get_hidden_params(cls))
    return cls(**cls_specific_params)
예제 #2
0
 def __get__(self, instance, owner) -> Optional[np.ndarray]:
     if self.required and self.name not in instance.__dict__:
         raise ValueError(f'{self.name} is a required argument and must be set first!')
     v = instance.__dict__.get(self.name, self.default)
     if not _check_numpy_fn_param_value(self.name, v, self.nargs):
         return v
     return convert_to_si_units(self._numpy_function(v), self.unit)
예제 #3
0
 def __get__(self, instance, owner) -> Optional[Set]:
     if self.required and self.name not in instance.__dict__:
         raise ValueError(f'{self.name} is a required argument and must be set first!')
     if instance.__dict__.get(self.name, self.default) is None:
         return None
     return set(convert_to_si_units(v, self.unit)
                for v in instance.__dict__.get(self.name, self.default))
예제 #4
0
def _extract_expanded_param(parsed_values: dict, name: str,
                            param: BaseDescriptor,
                            prefix: Optional[str]) -> Optional[List]:
    """
    Convert [start, stop, num] or [start, stop, step], etc. from expanded form back into a list to
    be easily fed into the un-expanded param

    :param parsed_values: The parsed values from the command line as a dictionary (comes directly
        from the namespace)
    :param name: Original name of the param that was expanded (may have a prefix)
    :param param: The param that was expanded
    :param prefix: If the param is a nested param, there's a chance we had to append
        the enclosing class name as a prefix to deconflict arguments with the same name. See
        _create_param_name_prefix docstring for more info.
    """
    old_arg_names = [
        prefix + n if prefix is not None else n
        for n in _expand_param_name(param)
    ]
    assert parsed_values.get(name) is None, f'param {name} was expanded! ' \
                                            f'Please provide {old_arg_names} instead'
    start_stop_x_list = [parsed_values[n] for n in old_arg_names]
    if all([x is None for x in start_stop_x_list]):
        return None
    units = _expand_param_units(param)
    si_unit_start_stop_x = [
        convert_to_si_units(p, u) for p, u in zip(start_stop_x_list, units)
    ]
    return si_unit_start_stop_x
예제 #5
0
 def __get__(self, instance, owner) -> Optional[np.ndarray]:
     if self.required and self.name not in instance.__dict__:
         raise ValueError(f'{self.name} is a required argument and must be set first!')
     v = instance.__dict__.get(self.name, self.default)
     if v is None or any([i is None for i in v]):
         return v
     return convert_to_si_units(np.linspace(*instance.__dict__.get(self.name, self.default)),
                                self.unit)
예제 #6
0
 def __get__(self, instance, owner):
     if self.required and self.name not in instance.__dict__:
         raise ValueError(f'{self.name} is a required argument and must be set first!')
     v = instance.__dict__.get(self.name, self.default)
     if v is None or any([i is None for i in v]):
         return v
     center, width, step = instance.__dict__.get(self.name, self.default)
     return convert_to_si_units(np.arange(center - 0.5 * width, center + 0.5 * width, step),
                                self.unit)
예제 #7
0
    def unit_set(self, param_name: str, value: Union[float, int,
                                                     Iterable]) -> None:
        """
        Set the parameter from a value that's in the param units specified in the Params class
        definition

        Ex.
        ```
        class A(Params):
            f = FloatParam(help='float', unit='ns')

        a = A()
        a.unit_set('a', 5)
        print(a.f)  # prints 5e-9
        ```

        :param param_name: The parameter name to set
        :param value: The new value in SI units
        """
        param = type(self).__dict__.get(param_name)
        expanded_units = _expand_param_units(param)
        if expanded_units is not None:
            values = [
                convert_to_si_units(v, u)
                for v, u in zip(value, expanded_units)
            ]
            setattr(self, param_name, values)
        else:
            unit = get_param_unit(type(self), param_name)
            if not isinstance(value, Iterable):
                setattr(self, param_name, convert_to_si_units(value, unit))
            else:
                # need to keep parameter type
                val_type = type(value)
                setattr(
                    self, param_name,
                    val_type([convert_to_si_units(v, unit) for v in value]))