Skip to content

Commit 1d2e337

Browse files
authored
LangChain integration (#260)
* Adjust numpy dependency to work with langchain * Add utility methods to JSONSerializer
1 parent 2d4eeaa commit 1d2e337

File tree

2 files changed

+35
-13
lines changed

2 files changed

+35
-13
lines changed

pyproject.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,10 @@ pymitter = ">=0.4,<1.1"
3030
typing-extensions = ">=4.11,<4.15"
3131
types-protobuf = "6.30.2.20250516"
3232
pympler = "1.1"
33-
numpy = "2.0.2"
33+
numpy = [
34+
{version = ">=1.26.4", python = "<3.13"},
35+
{version = ">=2.1.0", python = ">=3.13"}
36+
]
3437

3538
[tool.poetry.dev-dependencies]
3639
pytest = "~8.4"

src/coherence/serialization.py

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
# Copyright (c) 2022, 2023, Oracle and/or its affiliates.
1+
# Copyright (c) 2022, 2025, Oracle and/or its affiliates.
22
# Licensed under the Universal Permissive License v 1.0 as shown at
33
# https://oss.oracle.com/licenses/upl.
44

55
from __future__ import annotations
66

77
import collections
8+
import json
89
from abc import ABC, abstractmethod
910
from decimal import Decimal
1011
from typing import Any, Callable, Dict, Final, Optional, Type, TypeVar, cast
@@ -29,16 +30,16 @@
2930

3031
MAGIC_BYTE: Final[bytes] = b"\x15"
3132

32-
_type_to_alias: Final[Dict[Type[Any], str]] = dict()
33+
_type_to_alias: Final[Dict[Type[Any], str]] = {}
3334
"""A mapping of proxied Python types to their alias."""
3435

35-
_alias_to_type: Final[Dict[str, Type[Any]]] = dict()
36+
_alias_to_type: Final[Dict[str, Type[Any]]] = {}
3637
"""A mapping of aliases to their proxied Python type."""
3738

38-
_attribute_mappings: Final[Dict[Type[Any], Dict[str, str]]] = dict()
39+
_attribute_mappings: Final[Dict[Type[Any], Dict[str, str]]] = {}
3940
"""A mapping of object attributes that require a different name when serialized/deserialized."""
4041

41-
_attribute_mappings_rev: Final[Dict[Type[Any], Dict[str, str]]] = dict()
42+
_attribute_mappings_rev: Final[Dict[Type[Any], Dict[str, str]]] = {}
4243
"""The same mapping as _attribute_mappings, but in reverse for deserialization."""
4344

4445

@@ -70,25 +71,43 @@ def __init__(self) -> None:
7071
self._pickler = JavaProxyPickler()
7172
self._unpickler = JavaProxyUnpickler()
7273

74+
def _to_json_from_object(self, obj: object) -> str:
75+
jsn = jsonpickle.encode(obj, context=self._pickler)
76+
return jsn
77+
7378
def serialize(self, obj: object) -> bytes:
74-
jsn: str = jsonpickle.encode(obj, context=self._pickler)
79+
jsn: str = self._to_json_from_object(obj)
7580
b: bytes = MAGIC_BYTE + jsn.encode()
7681
return b
7782

83+
def _to_object_from_json(self, json_str: str) -> T: # type: ignore
84+
o = jsonpickle.decode(json_str, context=self._unpickler)
85+
return o
86+
7887
def deserialize(self, value: bytes) -> T: # type: ignore
7988
if isinstance(value, bytes):
8089
s = value.decode()
8190
if value.__len__() == 0: # empty string
8291
return cast(T, None)
8392
else:
8493
if ord(s[0]) == ord(MAGIC_BYTE):
85-
r = jsonpickle.decode(s[1:], context=self._unpickler)
94+
r: T = self._to_object_from_json(s[1:])
8695
return r
8796
else:
8897
raise ValueError("Invalid JSON serialization format")
8998
else:
9099
return cast(T, value)
91100

101+
def flatten_to_dict(self, o: object) -> dict[Any, Any]:
102+
jsn = self._to_json_from_object(o)
103+
d = json.loads(jsn)
104+
return d
105+
106+
def restore_to_object(self, the_dict: dict[Any, Any]) -> T: # type: ignore
107+
jsn = json.dumps(the_dict)
108+
o: T = self._to_object_from_json(jsn)
109+
return o
110+
92111

93112
class SerializerRegistry:
94113
_singleton: SerializerRegistry
@@ -146,7 +165,7 @@ def _flatten_obj(self, obj: Any) -> dict[str, str | dict[str, list[dict[str, Any
146165
if alias is not None:
147166
marker = result.get(_JSON_PICKLE_OBJ, None)
148167
if marker is not None:
149-
actual: dict[str, Any] = dict()
168+
actual: dict[str, Any] = {}
150169
actual[_META_CLASS] = alias
151170
for key, value in result.items():
152171
# ignore jsonpickle specific content as well as protected keys
@@ -171,11 +190,11 @@ def _flatten_obj(self, obj: Any) -> dict[str, str | dict[str, list[dict[str, Any
171190
and _META_VERSION not in value_
172191
and _META_ENUM not in value_
173192
):
174-
entries = list()
193+
entries = []
175194
for key_inner, value_inner in value.items():
176195
entries.append({_JSON_KEY: key_inner, _JSON_VALUE: value_inner})
177196

178-
padding: dict[str, Any] = dict()
197+
padding: dict[str, Any] = {}
179198
padding["entries"] = entries
180199
value_ = padding
181200

@@ -211,7 +230,7 @@ def _restore(self, obj: Any) -> Any:
211230
metadata: Any = obj.get(_META_CLASS, None)
212231
if metadata is not None:
213232
type_: Optional[Type[Any]] = _type_for(metadata)
214-
actual: dict[Any, Any] = dict()
233+
actual: dict[Any, Any] = {}
215234
if type_ is None:
216235
if "map" in metadata.lower():
217236
for entry in obj[_JSON_ENTRIES]:
@@ -245,7 +264,7 @@ def _restore(self, obj: Any) -> Any:
245264
if len(obj) == 1:
246265
entries = obj.get(_JSON_ENTRIES, None)
247266
if entries is not None:
248-
actual = dict()
267+
actual = {}
249268
for entry in obj[_JSON_ENTRIES]:
250269
actual[entry[_JSON_KEY]] = entry[_JSON_VALUE]
251270
return super().restore(actual, reset=False)

0 commit comments

Comments
 (0)