def apply_from_argparse(args, traits=None, target: HasTraits = None) -> dict: """ Applies arguments added via add_traits_to_argparse to a target object which implements HasTraits. If a target is not known, a dict of traits may be passed instead. Will throw TraitError if validation fails. :param args: Parsed args from argparse :param traits: Dictionary of traits (optional) :param target: Target object (optional) :return: Dict of the arguments which actually changed """ # apply the traits to an empty object, which will run # the validators on the client if isinstance(traits, HasTraits): traits = traits.traits() traits = traits.copy() for k, v in traits.items(): if not isinstance(v, TraitType): if isinstance(v, dict): k[v] = dict_as_trait(v) else: raise TypeError("A dict or trait object must be supplied") if target is None: if traits is None: raise ValueError("Either traits or target must be specified") target = HasTraits() target.add_traits(**traits) # determine what should actually be changed argkeys = [k for k, v in vars(args).items() if v is not None] intersect = set(target.traits().keys()).intersection(set(argkeys)) # apply the argparse flags to the target object for key in intersect: if target.traits()[key].get_metadata('config') is not True: raise ValueError("Trait is not marked as configurable: %s" % key) setattr(target, key, getattr(args, key)) # if all validators passed, return a dict of the changed args changed = {} for key in intersect: changed[key] = target._trait_values[key] return changed
def class_traits_as_dict(obj: HasTraits, values: dict = None) -> dict: """ Create a dict which represents all traits of the given object. This dict itself can be inspected in a generic API, or it may be converted back to a (stub) instance of HasTraits. This facilitates the sending of configurable object properties over an interface such as D-Bus. :param obj: an instance of HasTraits :param value: optional dict of trait values (pulled from obj by default) :return: dict representing all traits in obj """ cls_dt = {} if isinstance(obj, type) and hasattr(obj, 'class_traits'): traits = obj.class_traits() elif isinstance(obj, dict): traits = obj elif isinstance(obj, HasTraits): traits = obj.traits() values = obj._trait_values else: raise TypeError("Object does not support traits") for k, v in traits.items(): dt = trait_as_dict(v) if dt is None: continue if values is not None and k in values: dt['__value__'] = values[k] cls_dt[k] = dt return cls_dt
def add_traits_to_argparse(obj: HasTraits, parser: ArgumentParser, prefix: str = None): """ Add all traits from the given object to the argparse context. :param obj: an instance of HasTraits :param parser: argparse parser :param prefix: string to prefix keys with """ for key, trait in obj.traits().items(): if trait.get_metadata('config') is not True: continue argname = '--%s' % key if prefix is not None: argname = '--%s.%s' % (prefix, key) if isinstance(trait, Container): parser.add_argument(argname, nargs='+', help=trait.info_text) elif isinstance(trait, Enum): parser.add_argument(argname, type=str.lower, choices=[x.lower() for x in trait.values], help=trait.info_text) else: argtype = str if hasattr(trait, 'default_value'): argtype = type(trait.default_value) parser.add_argument(argname, type=argtype, help=trait.info_text)
def get_args_dict(obj: HasTraits, incl_all=False): """ Return a dict of user-configurable traits for an object :param obj: an instance of HasTraits :param incl_all: If all items should be included, regardless of RO status :return: dict of arguments """ argsdict = ArgsDict() for k in sorted(obj._trait_values.keys()): v = obj._trait_values[k] trait = obj.traits()[k] if incl_all or (not trait.get_metadata('hidden') and is_trait_writable(trait)): argsdict[k] = v return argsdict