def __deepcopy__(self, memo): cls = type(self) obj = object.__new__(cls) obj.model = self.model for field in get_class_fields(cls): setattr(obj, field.name, getattr(self, field.name)) return obj
def __new__(mcs, name, bases, namespace, **kwargs): if kwargs.get('__base_definition__', False): kwargs.pop('__base_definition__') mcs.__root__ = super().__new__(mcs, name, bases, namespace, **kwargs) return mcs.__root__ __type__ = namespace.pop('__type__', None) if __type__ is None or not isinstance(__type__, type): raise ValueError(f'__type__ field is be set to type for {name}') fields = get_class_fields(__type__) include = set(namespace.pop('__include__', set(f.name for f in fields))) exclude = set(namespace.pop('__exclude__', set())) force_required = set(namespace.pop('__force_required__', set())) autogen_nested = namespace.pop('__autogen_nested__', False) allow_polymorphism = namespace.pop('__allow_polymorphism__', False) subtype_models: Dict[str, Type[BaseModel]] = namespace.pop( '__subtype_models__', {}) annotations = namespace.get('__annotations__', {}) for field in fields: name = field.name if name in exclude or name not in include: continue if field.has_default and name not in namespace: namespace[name] = field.default if name not in annotations: field_type = field.type if autogen_nested: field_type = _substitute_nested_type( field_type, allow_polymorphism) annotations[name] = field_type if name in force_required: del namespace[name] annotations[name] = _make_not_optional(annotations[name]) if allow_polymorphism and is_hierarchy_root(__type__): field_type_field = getattr(__type__, TYPE_FIELD_NAME_FIELD_NAME) annotations[field_type_field] = str def validate(cls: Type[BaseModel], value): if isinstance(value, dict) and field_type_field in value: _subtype_name = value.pop(field_type_field) _subtype = __type__._subtypes[_subtype_name] if _subtype_name not in subtype_models: subtype_models[_subtype_name] = _new_model( _subtype, nested=autogen_nested, polymorphism=allow_polymorphism) child_model = subtype_models[_subtype_name] return child_model.validate(value) return super(cls).validate(value) namespace['validate'] = classmethod(validate) namespace['__annotations__'] = annotations new = super().__new__(mcs, name, bases, namespace, **kwargs) new.__type__ = __type__ return new
def update(self, other: 'DockerBuildArgs'): for field in get_class_fields(DockerBuildArgs): if field.name == 'templates_dir': self._templates_dir += other._templates_dir else: value = getattr(other, f'_{field.name}') if value is not None: setattr(self, f'_{field.name}', value)
def __deepcopy__(self, memo): cls = type(self) obj = object.__new__(cls) obj.io = self.io obj.model = self.model obj.methods = self.methods obj.requirements = self.requirements for field in get_class_fields(cls): setattr(obj, field.name, getattr(self, field.name)) return obj
def assert_objects_equal_except_fields(o1, o2, *, excepted_fields: List[str] = None): excepted_fields = excepted_fields or [] excepted_fields = set(excepted_fields) assert type(o1) == type(o2) fields1 = [f.name for f in get_class_fields(type(o1))] fields2 = [f.name for f in get_class_fields(type(o2))] assert fields1 == fields2 for field1, field2 in zip(fields1, fields2): assert field1 == field2 v1 = getattr(o1, field1) v2 = getattr(o2, field2) if field1 in excepted_fields: assert v1 != v2 else: assert v1 == v2
def test_get_class_fields(): class AClass: def __init__(self, field1: str, field2: int = 0): pass fields = get_class_fields(AClass) assert fields == [ Field('field1', str, False), Field('field2', int, True, 0) ]
def test_field_repr(): class AClass: def __init__(self, field1: str, field2: Union[str, int], field3: List[str] = []): pass f1, f2, f3 = get_class_fields(AClass) assert str(f1) == 'field1: str' assert str(f2) == 'field2: Union[str, int]' assert str(f3) == 'field3: List[str] = []'
def _serialize_to_list(cls, obj): result = [] fields = get_class_fields(cls) for f in fields: name = f.name field = getattr(obj, name) if field is not None: result.append(serialize(field)) if type_field_position_is(cls, Position.INSIDE): type_field_name = get_type_field_name(cls) result = [getattr(cls, type_field_name)] + result return result
def type_to_schema(field_type, has_default=False, default=None): """ Facade method converting arbitrary type to OpenAPI schema definitions. Has special support for builtins, collections and instances of :class:`.TypeWithSpec` subclasses. :param field_type: type to generate schema for :param has_default: specifies whether given type has default value :param default: specifies default value for given type :return: dict with OpenAPI schema definition """ if field_type in BUILTIN_TYPES: result = {'type': BUILTIN_TYPES[field_type]} if has_default: result['default'] = default return result elif is_generic(field_type): if is_collection(field_type): return make_array(get_collection_internal_type(field_type), has_default=has_default, default=default) elif is_mapping(field_type): kt, vt = get_mapping_types(field_type) if kt != str: raise ValueError('Only string keys supported') return make_object(arbitrary_properties_type=vt, has_default=has_default, default=default) elif issubclass(field_type, TypeWithSpec): if issubclass(field_type, PrimitiveDatasetType): return type_to_schema(field_type.to_type, has_default, default) # noinspection PyArgumentList spec = field_type.get_spec() # noinspection PyArgumentList is_list = field_type.is_list() # noinspection PyArgumentList list_size = field_type.list_size() if is_list: item_types = set(a.type for a in spec) if len(item_types) > 1: raise ValueError( 'All items must be of same type for {}'.format(field_type)) item_type = next(iter(item_types)) return make_array(item_type, list_size, list_size) else: return make_object(spec) # return schema_from_typespec(field) else: return make_object(get_class_fields(field_type))
def create_configurable(cls: Type[Configurable], kind): kind = cls.KNOWN.get(kind, kind) args = {"type": kind} clazz = resolve_subtype(cls, args) for field in get_class_fields(clazz): try: cast = field.type.__args__[0] if is_union( field.type) else field.type args[field.name] = cast( click.prompt(f"{field.name} value?", default=field.default)) except ValueError: raise NotImplementedError( f"Not yet implemented for type {field.type}") return deserialize(args, cls)
def update_object_fields(o, *, excepted_fields: List[str] = None): excepted_fields = excepted_fields or [] excepted_fields = set(excepted_fields) for field in [f.name for f in get_class_fields(type(o))]: additional_value = 2 if field not in excepted_fields: v = getattr(o, field) if isinstance(v, str): additional_value = str(additional_value) if isinstance(v, datetime.datetime): additional_value = datetime.timedelta(additional_value) setattr(o, field, v + additional_value) return o
def _construct_from_list(obj, as_class): args = [] if type_field_position_is(as_class, Position.INSIDE): obj = obj[1:] for i, f in enumerate(get_class_fields(as_class)): field_type = _get_field_type(f, obj) if i >= len(obj): if f.has_default: continue else: raise ValueError( "Too few arguments for type {} ".format(as_class)) else: args.append(deserialize(obj[i], field_type)) return as_class(*args)
def _construct_from_dict(obj, as_class): kwargs = {} for f in get_class_fields(as_class): name = f.name field_type = _get_field_type(f, obj) if hasattr(as_class, FIELD_MAPPING_NAME_FIELD): name = getattr(as_class, FIELD_MAPPING_NAME_FIELD).get(name, name) if name not in obj: if f.has_default: continue else: raise ValueError("Type {} has required argument {}".format( as_class, name)) else: kwargs[f.name] = deserialize(obj[name], field_type) return as_class(**kwargs)
def _serialize_to_dict(cls, obj): result = {} fields = get_class_fields(cls) for f in fields: name = f.name field = getattr(obj, name) if field is not None: if hasattr(cls, FIELD_MAPPING_NAME_FIELD): name = getattr(cls, FIELD_MAPPING_NAME_FIELD).get(name, name) result[name] = serialize(field, f.type) if type_field_position_is(cls, Position.INSIDE): type_field_name = get_type_field_name(cls) if type_field_name in result: raise SerializationError( 'Type field name {} conflicts with field name in {}'.format( type_field_name, cls)) result[type_field_name] = getattr(cls, type_field_name) return result