|
4 | 4 | :mod:`Quantulum` classes. |
5 | 5 | """ |
6 | 6 |
|
| 7 | +import json |
| 8 | +from abc import ABC, abstractmethod |
7 | 9 | from typing import Any, Dict, List, Optional, Tuple |
8 | 10 |
|
9 | 11 | from . import speak |
10 | 12 |
|
11 | 13 |
|
| 14 | +class JSONMIxin(ABC): |
| 15 | + @abstractmethod |
| 16 | + def to_dict(self): |
| 17 | + pass # pragma: no cover |
| 18 | + |
| 19 | + def to_json(self, *args, **kwargs) -> str: |
| 20 | + """ |
| 21 | + Create a JSON representation of this object. |
| 22 | +
|
| 23 | + :param args: Arguments to pass to the to_dict method |
| 24 | + :param kwargs: Keyword arguments to pass to the to_dict method |
| 25 | +
|
| 26 | + :return: JSON representation of this object |
| 27 | + """ |
| 28 | + return json.dumps(self.to_dict(*args, **kwargs)) |
| 29 | + |
| 30 | + @classmethod |
| 31 | + @abstractmethod |
| 32 | + def from_dict(cls, ddict: Dict): |
| 33 | + pass # pragma: no cover |
| 34 | + |
| 35 | + @classmethod |
| 36 | + def from_json(cls, json_str: str): |
| 37 | + """ |
| 38 | + Create an object from a JSON string. |
| 39 | +
|
| 40 | + :param json_str: JSON string to convert to an object |
| 41 | +
|
| 42 | + :return: Object created from the JSON string |
| 43 | + """ |
| 44 | + return cls.from_dict(json.loads(json_str)) |
| 45 | + |
| 46 | + |
12 | 47 | ############################################################################### |
13 | | -class Entity(object): |
| 48 | +class Entity(JSONMIxin, object): |
14 | 49 | """ |
15 | 50 | Class for an entity (e.g. "volume"). |
16 | 51 | """ |
@@ -42,9 +77,36 @@ def __ne__(self, other): |
42 | 77 | def __hash__(self): |
43 | 78 | return hash(repr(self)) |
44 | 79 |
|
| 80 | + def to_dict(self) -> Dict: |
| 81 | + """ |
| 82 | + Create a dictionary representation of this entity. |
| 83 | +
|
| 84 | + :return: Dictionary representation of this entity |
| 85 | + """ |
| 86 | + return { |
| 87 | + "name": self.name, |
| 88 | + "dimensions": self.dimensions, |
| 89 | + "uri": self.uri, |
| 90 | + } |
| 91 | + |
| 92 | + @classmethod |
| 93 | + def from_dict(cls, ddict: Dict) -> "Entity": |
| 94 | + """ |
| 95 | + Create an entity from a dictionary representation. |
| 96 | +
|
| 97 | + :param ddict: Dictionary representation of an entity (as produced by to_dict) |
| 98 | +
|
| 99 | + :return: Entity created from the dictionary representation |
| 100 | + """ |
| 101 | + return cls( |
| 102 | + name=ddict["name"], |
| 103 | + dimensions=ddict["dimensions"], |
| 104 | + uri=ddict["uri"], |
| 105 | + ) |
| 106 | + |
45 | 107 |
|
46 | 108 | ############################################################################### |
47 | | -class Unit(object): |
| 109 | +class Unit(JSONMIxin, object): |
48 | 110 | """ |
49 | 111 | Class for a unit (e.g. "gallon"). |
50 | 112 | """ |
@@ -111,11 +173,57 @@ def __ne__(self, other): |
111 | 173 | def __hash__(self): |
112 | 174 | return hash(repr(self)) |
113 | 175 |
|
| 176 | + def to_dict(self, include_entity_dict: bool = False) -> Dict: |
| 177 | + """ |
| 178 | + Create a dictionary representation of this unit. |
| 179 | +
|
| 180 | + :param include_entity: When False, just the name of the entity is included, when True the full entity is included. Default is False. |
| 181 | +
|
| 182 | + :return: Dictionary representation of this unit |
| 183 | + """ |
| 184 | + ddict = { |
| 185 | + "name": self.name, |
| 186 | + "surfaces": self.surfaces, |
| 187 | + "entity": self.entity.name, |
| 188 | + "uri": self.uri, |
| 189 | + "symbols": self.symbols, |
| 190 | + "dimensions": self.dimensions, |
| 191 | + "original_dimensions": self.original_dimensions, |
| 192 | + "currency_code": self.currency_code, |
| 193 | + "lang": self.lang, |
| 194 | + } |
| 195 | + |
| 196 | + if include_entity_dict: |
| 197 | + ddict["entity"] = self.entity.to_dict() |
| 198 | + |
| 199 | + return ddict |
| 200 | + |
| 201 | + @classmethod |
| 202 | + def from_dict(cls, ddict: Dict) -> "Unit": |
| 203 | + """ |
| 204 | + Create a unit from a dictionary representation. |
| 205 | +
|
| 206 | + :param ddict: Dictionary representation of a unit (as produced by to_dict) |
| 207 | +
|
| 208 | + :return: Unit created from the dictionary representation |
| 209 | + """ |
| 210 | + return cls( |
| 211 | + name=ddict["name"], |
| 212 | + surfaces=ddict["surfaces"], |
| 213 | + entity=Entity.from_dict(ddict["entity"]), |
| 214 | + uri=ddict["uri"], |
| 215 | + symbols=ddict["symbols"], |
| 216 | + dimensions=ddict["dimensions"], |
| 217 | + original_dimensions=ddict["original_dimensions"], |
| 218 | + currency_code=ddict["currency_code"], |
| 219 | + lang=ddict["lang"], |
| 220 | + ) |
| 221 | + |
114 | 222 |
|
115 | 223 | ############################################################################### |
116 | 224 |
|
117 | 225 |
|
118 | | -class Quantity(object): |
| 226 | +class Quantity(JSONMIxin, object): |
119 | 227 | """ |
120 | 228 | Class for a quantity (e.g. "4.2 gallons"). |
121 | 229 | """ |
@@ -183,3 +291,47 @@ def to_spoken(self, lang=None): |
183 | 291 | :return: Speakable version of this quantity |
184 | 292 | """ |
185 | 293 | return speak.quantity_to_spoken(self, lang or self.lang) |
| 294 | + |
| 295 | + def to_dict( |
| 296 | + self, include_unit_dict: bool = False, include_entity_dict: bool = False |
| 297 | + ) -> Dict: |
| 298 | + """ |
| 299 | + Create a dictionary representation of this quantity |
| 300 | +
|
| 301 | + :param include_unit: When False, just the name of the unit is included, when True, the full unit is included. Defaults to False |
| 302 | + :param include_entity: When False, just the name of the entity is included, when True, the full entity is included. Defaults to False. Only used when include_unit is True. |
| 303 | +
|
| 304 | + :return: Dictionary representation of this quantity |
| 305 | + """ |
| 306 | + ddict = { |
| 307 | + "value": self.value, |
| 308 | + "unit": self.unit.name, |
| 309 | + "entity": self.unit.entity.name, |
| 310 | + "surface": self.surface, |
| 311 | + "span": self.span, |
| 312 | + "uncertainty": self.uncertainty, |
| 313 | + "lang": self.lang, |
| 314 | + } |
| 315 | + |
| 316 | + if include_unit_dict: |
| 317 | + ddict["unit"] = self.unit.to_dict(include_entity_dict) |
| 318 | + |
| 319 | + return ddict |
| 320 | + |
| 321 | + @classmethod |
| 322 | + def from_dict(cls, ddict: Dict) -> "Quantity": |
| 323 | + """ |
| 324 | + Create a quantity from a dictionary representation. |
| 325 | +
|
| 326 | + :param ddict: Dictionary representation of a quantity (as produced by to_dict) |
| 327 | +
|
| 328 | + :return: Quantity created from the dictionary representation |
| 329 | + """ |
| 330 | + return cls( |
| 331 | + value=ddict["value"], |
| 332 | + unit=Unit.from_dict(ddict["unit"]), |
| 333 | + surface=ddict["surface"], |
| 334 | + span=tuple(ddict["span"]), |
| 335 | + uncertainty=ddict["uncertainty"], |
| 336 | + lang=ddict["lang"], |
| 337 | + ) |
0 commit comments