def update_atom_members(old: Atom, new: Atom): """Update an atom member""" old_keys = old.members().keys() new_keys = new.members().keys() for key in old_keys: old_obj = getattr(old, key) try: new_obj = getattr(new, key) if old_obj == new_obj: continue except AttributeError: # Remove any obsolete members try: delattr(old, key) except (AttributeError, TypeError): pass continue try: #: Update any changed members #: TODO: We have to somehow know if this was changed by the user or the code! #: and ONLY update if it's due to the code changing! Without this, the entire concept #: is broken and useless... setattr(old, key, getattr(new, key)) except (AttributeError, TypeError): pass # skip non-writable attributes #: Add any new members for key in set(new_keys) - set(old_keys): try: setattr(old, key, getattr(new, key)) except (AttributeError, TypeError): pass # skip non-writable attributes
def tagged_members( obj: Atom, meta: Optional[str] = None, meta_value: Any = None ) -> Dict[str, Member]: """Utility function to retrieve tagged members from an object Parameters ---------- obj : Atom Object from which the tagged members should be retrieved. meta : str, optional The tag to look for, only member which has this tag will be returned meta_value : optional The value of the metadata used for filtering the members returned Returns ------- tagged_members : dict(str, Member) Dictionary of the members whose metadatas corresponds to the predicate """ members = obj.members() if meta is None and meta_value is None: return members elif meta_value is None: return { key: member for key, member in members.items() if member.metadata is not None and meta in member.metadata } else: return { key: member for key, member in members.items() if member.metadata is not None and meta in member.metadata and member.metadata[meta] == meta_value }