|
1 | 1 | import dataclasses |
2 | 2 | import pickle |
| 3 | +import warnings |
3 | 4 | from typing import Optional, TYPE_CHECKING, Type, Dict, Any |
4 | 5 | import base64 |
5 | 6 |
|
|
11 | 12 |
|
12 | 13 | class PortingMixin: |
13 | 14 | @classmethod |
14 | | - def from_dict(cls: Type['T'], obj: Dict) -> 'T': |
15 | | - from google.protobuf import json_format |
16 | | - from ...proto.docarray_pb2 import DocumentProto |
| 15 | + def from_dict( |
| 16 | + cls: Type['T'], obj: Dict, protocol: str = 'jsonschema', **kwargs |
| 17 | + ) -> 'T': |
| 18 | + """Convert a dict object into a Document. |
| 19 | +
|
| 20 | + :param obj: a Python dict object |
| 21 | + :param protocol: `jsonschema` or `protobuf` |
| 22 | + :param kwargs: extra key-value args pass to pydantic and protobuf parser. |
| 23 | + :return: the parsed Document object |
| 24 | + """ |
| 25 | + if protocol == 'jsonschema': |
| 26 | + from ..pydantic_model import PydanticDocument |
| 27 | + |
| 28 | + return cls.from_pydantic_model(PydanticDocument.parse_obj(obj, **kwargs)) |
| 29 | + elif protocol == 'protobuf': |
| 30 | + from google.protobuf import json_format |
| 31 | + from ...proto.docarray_pb2 import DocumentProto |
17 | 32 |
|
18 | | - pb_msg = DocumentProto() |
19 | | - json_format.ParseDict(obj, pb_msg) |
20 | | - return cls.from_protobuf(pb_msg) |
| 33 | + pb_msg = DocumentProto() |
| 34 | + json_format.ParseDict(obj, pb_msg, **kwargs) |
| 35 | + return cls.from_protobuf(pb_msg) |
| 36 | + else: |
| 37 | + raise ValueError(f'protocol=`{protocol}` is not supported') |
21 | 38 |
|
22 | 39 | @classmethod |
23 | | - def from_json(cls: Type['T'], obj: str) -> 'T': |
24 | | - from google.protobuf import json_format |
25 | | - from ...proto.docarray_pb2 import DocumentProto |
| 40 | + def from_json( |
| 41 | + cls: Type['T'], obj: str, protocol: str = 'jsonschema', **kwargs |
| 42 | + ) -> 'T': |
| 43 | + """Convert a JSON string into a Document. |
| 44 | +
|
| 45 | + :param obj: a valid JSON string |
| 46 | + :param protocol: `jsonschema` or `protobuf` |
| 47 | + :param kwargs: extra key-value args pass to pydantic and protobuf parser. |
| 48 | + :return: the parsed Document object |
| 49 | + """ |
| 50 | + if protocol == 'jsonschema': |
| 51 | + from ..pydantic_model import PydanticDocument |
| 52 | + |
| 53 | + return cls.from_pydantic_model(PydanticDocument.parse_raw(obj, **kwargs)) |
| 54 | + elif protocol == 'protobuf': |
| 55 | + from google.protobuf import json_format |
| 56 | + from ...proto.docarray_pb2 import DocumentProto |
| 57 | + |
| 58 | + pb_msg = DocumentProto() |
| 59 | + json_format.Parse(obj, pb_msg, **kwargs) |
| 60 | + return cls.from_protobuf(pb_msg) |
| 61 | + else: |
| 62 | + raise ValueError(f'protocol=`{protocol}` is not supported') |
26 | 63 |
|
27 | | - pb_msg = DocumentProto() |
28 | | - json_format.Parse(obj, pb_msg) |
29 | | - return cls.from_protobuf(pb_msg) |
| 64 | + def to_dict(self, protocol: str = 'jsonschema', **kwargs) -> Dict[str, Any]: |
| 65 | + """Convert itself into a Python dict object. |
30 | 66 |
|
31 | | - def to_dict(self, strict: bool = True) -> Dict[str, Any]: |
32 | | - if strict: |
| 67 | + :param protocol: `jsonschema` or `protobuf` |
| 68 | + :param kwargs: extra key-value args pass to pydantic and protobuf dumper. |
| 69 | + :return: the dumped Document as a dict object |
| 70 | + """ |
| 71 | + if protocol == 'jsonschema': |
| 72 | + return self.to_pydantic_model().dict(**kwargs) |
| 73 | + elif protocol == 'protobuf': |
33 | 74 | from google.protobuf.json_format import MessageToDict |
34 | 75 |
|
35 | 76 | return MessageToDict( |
36 | 77 | self.to_protobuf(), |
37 | | - preserving_proto_field_name=True, |
| 78 | + **kwargs, |
38 | 79 | ) |
39 | 80 | else: |
| 81 | + warnings.warn( |
| 82 | + f'protocol=`{protocol}` is not supported, ' |
| 83 | + f'the result dict is a Python dynamic typing dict without any promise on the schema.' |
| 84 | + ) |
40 | 85 | return dataclasses.asdict(self._data) |
41 | 86 |
|
42 | 87 | def to_bytes( |
@@ -68,25 +113,33 @@ def from_bytes( |
68 | 113 | """ |
69 | 114 | bstr = decompress_bytes(data, algorithm=compress) |
70 | 115 | if protocol == 'pickle': |
71 | | - d = pickle.loads(bstr) |
| 116 | + return pickle.loads(bstr) |
72 | 117 | elif protocol == 'protobuf': |
73 | 118 | from ...proto.docarray_pb2 import DocumentProto |
74 | 119 |
|
75 | 120 | pb_msg = DocumentProto() |
76 | 121 | pb_msg.ParseFromString(bstr) |
77 | | - d = cls.from_protobuf(pb_msg) |
| 122 | + return cls.from_protobuf(pb_msg) |
78 | 123 | else: |
79 | 124 | raise ValueError( |
80 | 125 | f'protocol={protocol} is not supported. Can be only `protobuf` or pickle protocols 0-5.' |
81 | 126 | ) |
82 | | - return d |
83 | 127 |
|
84 | | - def to_json(self) -> str: |
85 | | - from google.protobuf.json_format import MessageToJson |
| 128 | + def to_json(self, protocol: str = 'jsonschema', **kwargs) -> str: |
| 129 | + """Convert itself into a JSON string. |
| 130 | +
|
| 131 | + :param protocol: `jsonschema` or `protobuf` |
| 132 | + :param kwargs: extra key-value args pass to pydantic and protobuf dumper. |
| 133 | + :return: the dumped JSON string |
| 134 | + """ |
| 135 | + if protocol == 'jsonschema': |
| 136 | + return self.to_pydantic_model().json(**kwargs) |
| 137 | + elif protocol == 'protobuf': |
| 138 | + from google.protobuf.json_format import MessageToJson |
86 | 139 |
|
87 | | - return MessageToJson( |
88 | | - self.to_protobuf(), preserving_proto_field_name=True, sort_keys=True |
89 | | - ) |
| 140 | + return MessageToJson(self.to_protobuf(), **kwargs) |
| 141 | + else: |
| 142 | + raise ValueError(f'protocol={protocol} is not supported.') |
90 | 143 |
|
91 | 144 | def to_base64( |
92 | 145 | self, protocol: str = 'pickle', compress: Optional[str] = None |
|
0 commit comments