Utilities
API package path: mcdreforged.api.utils
- mcdreforged.utils.serializer.serialize(obj: Any) None | int | float | str | bool | list | dict[source]
A utility function to serialize any object into a json-like python object. Here, being json-like means that the return value can be passed to e.g.
json.dumps()directlySerialization rules:
Immutable object, including
None,int,float,strandbool, will be directly returnedlistandtuplewill be serialized into alistwill all the items serializeddictwill be converted into adictwill all the keys and values serializedre.Patternwill be converted to astr, with the value ofre.Pattern.pattern.Notes: if
re.Pattern.patternreturnsbytes, it will be decoded into a utf8str
uuid.UUIDwill be converted to astr, with the value ofstr(uuid_object)- Normal object will be converted to a
dictwith all of its public fields. The keys are the name of the fields and the values are the serialized field values
- Normal object will be converted to a
Added in version v2.8.0: If the object is a
Serializable, the value field order will follow the order in the annotationAdded in version v2.12.0: Added custom subclass of base classes and
re.PatternsupportAdded in version v2.14.0: Added
uuid.UUIDsupport- Parameters:
obj – The object to be serialized
- Returns:
The serialized result
Tip
For more complex serialization/deserialization requirements, take a look at the pydantic library
- mcdreforged.utils.serializer.deserialize(data: Any, cls: Type[T], *, error_at_missing: bool = False, error_at_redundancy: bool = False, missing_callback: Callable[[Any, Type, str], Any] | None = None, redundancy_callback: Callable[[Any, Type, str, Any], Any] | None = None) T[source]
A utility function to deserialize a json-like object into an object in given class
If the target class contains nested items / fields, corresponding detailed type annotations are required. The items / fields will be deserialized recursively
Supported target classes:
Immutable object:
None,bool,int,floatandstrStandard container:
list,dict. Type of its content should be type annotatedtyping.List,list: Target class needs to be e.g.List[int]orlist[int](python 3.9+)typing.Dict,dict: Target class needs to be e.g.Dict[str, bool]ordict[str, bool](python 3.9+)
Custom subclass of following base classes:
int,float,str,bool,listanddictTypes in the typing module:
typing.Union: Iterate through its available candidate classes, and return the first successful deserialization resulttyping.Optional: Actually it will be converted to atyping.Unionautomaticallytyping.Any: The input data will be directed returned as the resulttyping.Literal: The input data needs to be in parameter the ofLiteral, then the input data will be returned as the result
Regular expression pattern (
re.Pattern). The input data should be astr- Normal class: The class should have its fields type annotated. It’s constructor should accept 0 input parameter.
Example class:
class MyClass: some_str: str a_list: List[int]
The input data needs to be a dict. Keys and values in the dict correspond to the field names and serialized field values. Example dict:
{'some_str': 'foo', 'a_list': [1, 2, 3]}
Fields are set via
__setattr__, non-public fields will be ignored.
- Parameters:
data – The json-like object to be deserialized
cls – The target class of the generated object
- Keyword Arguments:
error_at_missing – A flag indicating if an exception should be risen if there are any not-assigned fields when deserializing an object. Default false
error_at_redundancy – A flag indicating if an exception should be risen if there are any unknown input attributes when deserializing an object. Default false
missing_callback – A callback function that will be invoked if there’s a not-assigned field when deserializing an object. The callback accepts 3 arguments: the data and the cls arguments from this function, and the name of the missing field
redundancy_callback – A callback function that will be invoked if there’s an unknown input attribute when deserializing an object. The callback accepts 4 arguments: the data and the cls arguments from this function, and the name and value of the redundancy key-value pair from the dict data
- Raises:
TypeError – If input data doesn’t match target class, or target class is unsupported
ValueError – If input data is invalid, including
Literalmismatch and those error flag in kwargs taking effect
- Returns:
An object in class
cls
Added in version v2.7.0: Added
typing.LiteralsupportAdded in version v2.12.0: Added custom subclass of base classes and
re.PatternsupportAdded in version v2.14.0: Added
uuid.UUIDsupportTip
For more complex serialization/deserialization requirements, take a look at the pydantic library
- class mcdreforged.utils.serializer.Serializable(**kwargs)[source]
An abstract class for easy serializing / deserializing
Inherit it and declare the fields of your class with type annotations, that’s all you need to do
Example:
>>> class MyData(Serializable): ... name: str ... values: List[int] >>> data = MyData.deserialize({'name': 'abc', 'values': [1, 2]}) >>> print(data.name, data.values) abc [1, 2] >>> data.serialize() {'name': 'abc', 'values': [1, 2]} >>> data = MyData(name='cde') >>> data.serialize() {'name': 'cde'}
Serializableclass nesting is also supported:class MyStorage(Serializable): id: str best: MyData data: Dict[str, MyData]
You can also declare default value when declaring type annotations, then during deserializing, if the value is missing, a
copy.copy()of the default value will be assigned>>> class MyArray(Serializable): ... array: List[int] = [0] >>> a = MyArray(array=[1]) >>> print(a.array) [1] >>> b, c = MyArray.deserialize({}), MyArray.deserialize({}) >>> print(b.array) [0] >>> b.array == c.array == MyArray.array True >>> b.array is not c.array is not MyArray.array True
Enum class will be serialized into its member name:
>>> class Gender(Enum): ... male = 'man' ... female = 'woman' >>> class Person(Serializable): ... name: str = 'zhang_san' ... gender: Gender = Gender.male >>> data = Person.get_default() >>> data.serialize() {'name': 'zhang_san', 'gender': 'male'} >>> data.gender = Gender.female >>> data.serialize() {'name': 'zhang_san', 'gender': 'female'} >>> Person.deserialize({'name': 'li_si', 'gender': 'female'}).gender == Gender.female True
Tip
For more complex serialization/deserialization requirements, take a look at the pydantic library
- __init__(**kwargs)[source]
Create a
Serializableobject with given field valuesUnspecified public fields with default value in the type annotation will be set to a copy (
copy.copy()) of the default value- Parameters:
kwargs – A dict storing to-be-set values of its fields. It’s keys are field names and values are field values
- classmethod get_field_annotations() Dict[str, Type][source]
A helper method to extract field annotations of the class
Only public fields will be extracted. Protected and private fields will be ignored
The return value will be cached for reuse
- Returns:
A dict of the field annotation of the class. The keys are the field name, and the values are the type annotation of the field
Added in version v2.8.0.
- serialize() dict[source]
Serialize itself into a dict via function
serialize()
- classmethod deserialize(data: dict, **kwargs: Unpack[_DeserializeKwargs]) Self[source]
Deserialize a dict into an object of this class via function
deserialize()When there are missing fields, automatically copy the class’s default value if possible. See
__init__()for more details
- classmethod get_default() Self[source]
Create an object of this class with default values
Actually it just invokes the constructor of the class with 0 argument
- merge_from(other: Self)[source]
Merge attributes from another instance into the current one
Note
It won’t create copies of the attribute values being merged
If you want the merged values to be independent, you can make a
deep copyof the other object first, and then merge from the copy- Parameters:
other – The other object to merge attributes from
Added in version v2.9.0.
- copy(*, deep: bool = True) Self[source]
Make a copy of the object. Only fields declared in the class annotation will be copied
By default, a deep copy will be made
- Keyword Arguments:
deep – If this operation make a deep copy. True: deep copy, False: shallow copy
Added in version v2.8.0.
Added in version v2.9.0: Added
deepkeyword argument
- validate_attribute(attr_name: str, attr_value: Any, **kwargs)[source]
A method that will be invoked before setting value to an attribute during the deserialization
You can validate the to-be-set attribute value in this method, and raise some
ValueErrorfor bad values- Parameters:
attr_name – The name of the attribute to be set
attr_value – The value of the attribute to be set
- Keyword Arguments:
kwargs – Placeholder
- Raises:
ValueError – If the validation failed
Added in version v2.8.0.