def assert_proper_col_class(obj, obj_tuple): # Iterate over all attributes, and if they are lists or mappings # in the original, assert they are the same class in the dumped. for index, field in enumerate(fields(obj.__class__)): field_val = getattr(obj, field.name) if has(field_val.__class__): # This field holds a class, recurse the assertions. assert_proper_col_class(field_val, obj_tuple[index]) elif isinstance(field_val, (list, tuple)): # This field holds a sequence of something. expected_type = type(obj_tuple[index]) assert type(field_val) is expected_type # noqa: E721 for obj_e, obj_tuple_e in zip(field_val, obj_tuple[index]): if has(obj_e.__class__): assert_proper_col_class(obj_e, obj_tuple_e) elif isinstance(field_val, dict): orig = field_val tupled = obj_tuple[index] assert type(orig) is type(tupled) # noqa: E721 for obj_e, obj_tuple_e in zip(orig.items(), tupled.items()): if has(obj_e[0].__class__): # Dict key assert_proper_col_class(obj_e[0], obj_tuple_e[0]) if has(obj_e[1].__class__): # Dict value assert_proper_col_class(obj_e[1], obj_tuple_e[1])
def assert_proper_tuple_class(obj, obj_tuple): assert isinstance(obj_tuple, tuple_class) for index, field in enumerate(fields(obj.__class__)): field_val = getattr(obj, field.name) if has(field_val.__class__): # This field holds a class, recurse the assertions. assert_proper_tuple_class(field_val, obj_tuple[index])
def assert_proper_dict_class(obj, obj_dict): assert isinstance(obj_dict, dict_class) for field in fields(obj.__class__): field_val = getattr(obj, field.name) if has(field_val.__class__): # This field holds a class, recurse the assertions. assert_proper_dict_class(field_val, obj_dict[field.name]) elif isinstance(field_val, Sequence): dict_val = obj_dict[field.name] for item, item_dict in zip(field_val, dict_val): if has(item.__class__): assert_proper_dict_class(item, item_dict) elif isinstance(field_val, Mapping): # This field holds a dictionary. assert isinstance(obj_dict[field.name], dict_class) for key, val in field_val.items(): if has(val.__class__): assert_proper_dict_class(val, obj_dict[key])
def test_positive_empty(self): """ Returns `True` on decorated classes even if there are no attributes. """ @attributes class D(object): pass assert has(D)
def test_negative(self): """ Returns `False` on non-decorated classes. """ assert not has(object)
def test_positive(self, C): """ Returns `True` on decorated classes. """ assert has(C)
def asjsonld( inst, recurse=True, filter=None, dict_factory=dict, retain_collection_types=False, export_context=True, basedir=None, ): """Dump a JSON-LD class to the JSON with generated ``@context`` field.""" jsonld_fields = inst.__class__._jsonld_fields attrs = tuple(field for field in fields(inst.__class__) if field.name in jsonld_fields) rv = dict_factory() def convert_value(v): """Convert special types.""" if isinstance(v, Path): v = str(v) return os.path.relpath(v, str(basedir)) if basedir else v return v for a in attrs: v = getattr(inst, a.name) # skip proxies if isinstance(v, weakref.ReferenceType): continue # do not export context for containers ec = export_context and KEY_CLS not in a.metadata if filter is not None and not filter(a, v): continue if recurse is True: if has(v.__class__): rv[a.name] = asjsonld( v, recurse=True, filter=filter, dict_factory=dict_factory, basedir=basedir, ) elif isinstance(v, (tuple, list, set)): cf = v.__class__ if retain_collection_types is True else list rv[a.name] = cf([ asjsonld( i, recurse=True, filter=filter, dict_factory=dict_factory, export_context=ec, basedir=basedir, ) if has(i.__class__) else i for i in v ]) elif isinstance(v, dict): df = dict_factory rv[a.name] = df((asjsonld( kk, dict_factory=df, basedir=basedir, ) if has(kk.__class__) else convert_value(kk), asjsonld( vv, dict_factory=df, export_context=ec, basedir=basedir, ) if has(vv.__class__) else vv) for kk, vv in iteritems(v)) else: rv[a.name] = convert_value(v) else: rv[a.name] = convert_value(v) inst_cls = type(inst) if export_context: rv['@context'] = deepcopy(inst_cls._jsonld_context) if inst_cls._jsonld_type: rv['@type'] = inst_cls._jsonld_type return rv
def ascwl( inst, recurse=True, filter=None, dict_factory=dict, retain_collection_types=False, basedir=None, ): """Return the ``attrs`` attribute values of *inst* as a dict. Support ``jsonldPredicate`` in a field metadata for generating mappings from lists. Adapted from ``attr._funcs``. """ attrs = fields(inst.__class__) rv = dict_factory() def convert_value(v): """Convert special types.""" if isinstance(v, Path): v = str(v) return os.path.relpath(v, str(basedir)) if basedir else v return v for a in attrs: if a.name.startswith('__'): continue a_name = a.name.rstrip('_') v = getattr(inst, a.name) if filter is not None and not filter(a, v): continue if recurse is True: if has(v.__class__): rv[a_name] = ascwl( v, recurse=True, filter=filter, dict_factory=dict_factory, basedir=basedir, ) elif isinstance(v, (tuple, list, set)): cf = v.__class__ if retain_collection_types is True else list rv[a_name] = cf([ ascwl( i, recurse=True, filter=filter, dict_factory=dict_factory, basedir=basedir, ) if has(i.__class__) else i for i in v ]) if 'jsonldPredicate' in a.metadata: k = a.metadata['jsonldPredicate'].get('mapSubject') if k: vv = dict_factory() for i in rv[a_name]: kk = i.pop(k) vv[kk] = i rv[a_name] = vv elif isinstance(v, dict): df = dict_factory rv[a_name] = df((ascwl( kk, dict_factory=df, basedir=basedir, ) if has(kk.__class__) else convert_value(kk), ascwl( vv, dict_factory=df, basedir=basedir, ) if has(vv.__class__) else vv) for kk, vv in iteritems(v)) else: rv[a_name] = convert_value(v) else: rv[a_name] = convert_value(v) if isinstance(inst, CWLClass): rv['class'] = inst.__class__.__name__ return rv
def asjsonld( inst, recurse=True, filter=None, dict_factory=dict, retain_collection_types=False, export_context=True, ): """Dump a JSON-LD class to the JSON with generated ``@context`` field.""" attrs = fields(inst.__class__) rv = dict_factory() def convert_value(v): """Convert special types.""" if isinstance(v, Path): return str(v) return v for a in attrs: v = getattr(inst, a.name) # do not export context for containers ec = export_context and KEY_CLS not in a.metadata if filter is not None and not filter(a, v): continue if recurse is True: if has(v.__class__): rv[a.name] = asjsonld(v, recurse=True, filter=filter, dict_factory=dict_factory) elif isinstance(v, (tuple, list, set)): cf = v.__class__ if retain_collection_types is True else list rv[a.name] = cf([ asjsonld( i, recurse=True, filter=filter, dict_factory=dict_factory, export_context=ec, ) if has(i.__class__) else i for i in v ]) elif isinstance(v, dict): df = dict_factory rv[a.name] = df(( asjsonld(kk, dict_factory=df) if has(kk.__class__) else kk, asjsonld(vv, dict_factory=df, export_context=ec ) if has(vv.__class__) else vv) for kk, vv in iteritems(v)) else: rv[a.name] = convert_value(v) else: rv[a.name] = convert_value(v) inst_cls = type(inst) if export_context: rv['@context'] = deepcopy(inst_cls._jsonld_context) if inst_cls._jsonld_type: rv['@type'] = inst_cls._jsonld_type return rv
def asjsonld( inst, recurse=True, filter=None, dict_factory=dict, retain_collection_types=False, add_context=True, use_scoped_type_form=False, basedir=None, ): """Dump a JSON-LD class to the JSON with generated ``@context`` field.""" jsonld_fields = inst.__class__._jsonld_fields attrs = tuple( field for field in fields(inst.__class__) if field.name in jsonld_fields ) rv = dict_factory() def convert_value(value): """Convert non-serializable types.""" if isinstance(value, Path): result = str(value) if basedir: result = os.path.relpath(result, str(basedir)) return result if isinstance(value, datetime): if not value.tzinfo: # set timezone to local timezone tz = datetime.now(timezone.utc).astimezone().tzinfo value = value.replace(tzinfo=tz) return value.isoformat() return value inst_cls = type(inst) for a in attrs: v = getattr(inst, a.name) scoped = a.name in inst_cls._scoped_properties # skip proxies if isinstance(v, weakref.ReferenceType): continue if filter is not None and not filter(a, v): continue if recurse is True: if has(v.__class__): rv[a.name] = asjsonld( v, recurse=True, filter=filter, dict_factory=dict_factory, add_context=False, use_scoped_type_form=scoped, basedir=basedir, ) elif isinstance(v, (tuple, list, set)): cf = v.__class__ if retain_collection_types is True else list rv[a.name] = cf([ asjsonld( i, recurse=True, filter=filter, dict_factory=dict_factory, add_context=False, use_scoped_type_form=scoped, basedir=basedir, ) if has(i.__class__) else i for i in v ]) elif isinstance(v, dict): df = dict_factory rv[a.name] = df(( asjsonld( kk, dict_factory=df, add_context=False, basedir=basedir, ) if has(kk.__class__) else convert_value(kk), asjsonld( vv, dict_factory=df, add_context=False, basedir=basedir, ) if has(vv.__class__) else vv ) for kk, vv in iteritems(v)) else: rv[a.name] = convert_value(v) else: rv[a.name] = convert_value(v) if add_context: rv['@context'] = deepcopy(inst_cls._jsonld_context) rv_type = [] if inst_cls._jsonld_type: if isinstance(inst_cls._jsonld_type, (list, tuple, set)): rv_type.extend(inst_cls._jsonld_type) else: rv_type.append(inst_cls._jsonld_type) if use_scoped_type_form: rv_type = [ '{}_{}'.format(inst_cls._renku_type, t) for t in rv_type ] rv['@type'] = rv_type[0] if len(rv_type) == 1 else rv_type return rv