Coverage for backpack/config/serde.py: 74%
54 statements
« prev ^ index » next coverage.py v7.2.2, created at 2023-03-30 23:12 +0000
« prev ^ index » next coverage.py v7.2.2, created at 2023-03-30 23:12 +0000
1''' Serializers/Deserializers (SerDe) convert between configuration strings (or numbers) and
2different Python structures.
4You should subclass :class:`ConfigSerDeBase` and override the following static fields:
6- ``name``: the description of the structure this serde can convert, for example "Comma-separated
7 list of integers". This text will be used in the documentation generated by the ConfigBase CLI.
8- ``serialize``: Take the Python structure and returns a string representation.
9- ``deserialize``: Take a string representation of the value and return a Python structure.
10'''
12from typing import Any, List, Sequence, Mapping
13from abc import ABC, abstractmethod
14import json
15import datetime
17class ConfigSerDeBase(ABC):
18 ''' Defines a serializer / deserializer interface. '''
20 description : str = 'The base serde encodes and decodes strings to themselves.'
21 ''' A textual description how the object is encoded in the string. Will be used in docs. '''
23 example : str = 'abcdefgh'
24 ''' Provide a textual example of the encoded string. Will be used in docs. '''
26 @staticmethod
27 @abstractmethod
28 def serialize(value: Any, metadata: Mapping[str, Any]={}) -> str:
29 ''' Serializes a config value to a string.
31 Args:
32 value (Any): a Python object to be serialized.
33 metadata (Mapping[str, Any]): Additional metadata to be passed to SerDe implementations.
35 Returns:
36 The object serialized into a string.
37 '''
38 return str(value)
40 @staticmethod
41 @abstractmethod
42 def deserialize(value: str, metadata: Mapping[str, Any]={}) -> Any:
43 ''' Deserializes a string to a config value.
45 Args:
46 value (str): a Python object serialized into a string
47 metadata (Mapping[str, Any]): Additional metadata to be passed to SerDe implementations.
49 Returns:
50 The the restored Python object.
51 '''
52 return value
55class IntegerListSerDe(ConfigSerDeBase):
56 ''' De/serializes a string containing a comma-separated list of integers.'''
58 description : str = 'Comma-separated list of integers'
59 example: str = '0, 1, 2'
61 @staticmethod
62 def serialize(value: Sequence[int], metadata: Mapping[str, Any]={}) -> str:
63 ''' Serializes a list of integers into a string.
65 Args:
66 value (Sequence[int]): The list of integers.
68 Returns:
69 The list of integers serialized into a string.
70 '''
71 sep = metadata.get('separator', ', ')
72 return sep.join(str(e) for e in value)
74 @staticmethod
75 def deserialize(value: str, metadata: Mapping[str, Any]={}) -> List[int]:
76 '''Restores a list of integers from a string.
78 Args:
79 value (str): A string containing a serialized list of integers.
81 Returns:
82 The list of integers restored from the string.
84 Raises:
85 Exception: exceptions related to invalid string format.
86 '''
87 sep = metadata.get('separator', ',')
88 return [int(e) for e in value.split(sep)]
91class StringListSerDe(ConfigSerDeBase):
92 ''' De/serializes a string containing a comma-separated list of strings.'''
94 description : str = 'Comma-separated list of strings'
95 example: str = 'apple, pear, banana'
97 @staticmethod
98 def serialize(value: Sequence[str], metadata: Mapping[str, Any]={}) -> str:
99 ''' Serializes a list of strings into a string.
101 Args:
102 value (Sequence[str]): The list of strings.
104 Returns:
105 The list of strings serialized into a string.
106 '''
107 sep = metadata.get('separator', ', ')
108 return sep.join(str(e) for e in value)
110 @staticmethod
111 def deserialize(value: str, metadata: Mapping[str, Any]={}) -> List[str]:
112 '''Restores a list of strings from a string.
114 Args:
115 value (str): A string containing a serialized list of strings.
117 Returns:
118 The list of strings restored from the string.
120 Raises:
121 Exception: exceptions related to invalid string format.
122 '''
123 sep = metadata.get('separator', ',')
124 return [str(e).strip() for e in value.split(sep)]
127class JsonSerDe(ConfigSerDeBase):
128 ''' De/serializes a string containing a JSON-encoded object.'''
130 description : str = 'JSON-encoded object'
131 example: str = '{"foo": "bar", "list": [0, 1, 2]}'
133 @staticmethod
134 def serialize(value: Any, metadata: Mapping[str, Any]={}) -> str:
135 ''' Serializes a JSON object into a string.
137 Args:
138 value (Any): A JSON-serializable object.
140 Returns:
141 The JSON object serialized into a string.
142 '''
143 return json.dumps(value)
145 @staticmethod
146 def deserialize(value: str, metadata: Mapping[str, Any]={}) -> Any:
147 ''' Deserializes JSON object from a string.
149 Args:
150 value (str): A string containing a serialized JSON object.
152 Returns:
153 The JSON object restored from the string.
155 Raises:
156 Exception: exceptions related to invalid string format.
157 '''
158 return json.loads(value)
161class TimeDeltaSecondsSerDe(ConfigSerDeBase):
162 ''' De/serializes a timedelta instance into a float number.
164 The time interval is expressed in seconds.
165 '''
167 name : str = 'float32 value interpreted as seconds'
169 @staticmethod
170 def serialize(value: datetime.timedelta, metadata: Mapping[str, Any]={}) -> float:
171 ''' Serializes a timedelta instance as a float number.
173 The time interval is expressed in seconds. '''
174 return value.total_seconds()
177 @staticmethod
178 def deserialize(value: float, metadata: Mapping[str, Any]={}) -> datetime.timedelta:
179 ''' Deserializes a float value into a time interval.
181 The value is interpreted in seconds.
182 '''
183 return datetime.timedelta(seconds=value)