Skip to content

Commit

Permalink
[Py]Better mock handling in serialization (#1063)
Browse files Browse the repository at this point in the history
Avoid recursion
And rm locks
  • Loading branch information
hinthornw authored Oct 3, 2024
1 parent 92d8e66 commit da3c1bb
Show file tree
Hide file tree
Showing 5 changed files with 23 additions and 19 deletions.
11 changes: 7 additions & 4 deletions python/langsmith/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -227,10 +227,10 @@ def _simple_default(obj):
return obj.pattern
elif isinstance(obj, (bytes, bytearray)):
return base64.b64encode(obj).decode()
return repr(obj)
return str(obj)
except BaseException as e:
logger.debug(f"Failed to serialize {type(obj)} to JSON: {e}")
return repr(obj)
return str(obj)


def _serialize_json(obj: Any) -> Any:
Expand All @@ -250,9 +250,12 @@ def _serialize_json(obj: Any) -> Any:
if hasattr(obj, attr) and callable(getattr(obj, attr)):
try:
method = getattr(obj, attr)
return (
response = (
method(exclude_none=exclude_none) if exclude_none else method()
)
if not isinstance(response, dict):
return str(response)
return response
except Exception as e:
logger.error(
f"Failed to use {attr} to serialize {type(obj)} to"
Expand All @@ -262,7 +265,7 @@ def _serialize_json(obj: Any) -> Any:
return _simple_default(obj)
except BaseException as e:
logger.debug(f"Failed to serialize {type(obj)} to JSON: {e}")
return repr(obj)
return str(obj)


def _elide_surrogates(s: bytes) -> bytes:
Expand Down
9 changes: 4 additions & 5 deletions python/langsmith/run_trees.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
LANGSMITH_PREFIX = "langsmith-"
LANGSMITH_DOTTED_ORDER = f"{LANGSMITH_PREFIX}trace"
_CLIENT: Optional[Client] = None
_LOCK = threading.Lock()
_LOCK = threading.Lock() # Keeping around for a while for backwards compat


# Note, this is called directly by langchain. Do not remove.
Expand All @@ -37,9 +37,8 @@
def get_cached_client(**init_kwargs: Any) -> Client:
global _CLIENT
if _CLIENT is None:
with _LOCK:
if _CLIENT is None:
_CLIENT = Client(**init_kwargs)
if _CLIENT is None:
_CLIENT = Client(**init_kwargs)
return _CLIENT


Expand Down Expand Up @@ -163,7 +162,7 @@ def add_metadata(self, metadata: Dict[str, Any]) -> None:
"""Add metadata to the run."""
if self.extra is None:
self.extra = {}
metadata_: dict = self.extra.setdefault("metadata", {})
metadata_: dict = cast(dict, self.extra).setdefault("metadata", {})
metadata_.update(metadata)

def add_outputs(self, outputs: Dict[str, Any]) -> None:
Expand Down
17 changes: 8 additions & 9 deletions python/langsmith/schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

from __future__ import annotations

import threading
from datetime import datetime, timedelta, timezone
from decimal import Decimal
from enum import Enum
Expand Down Expand Up @@ -201,6 +200,10 @@ class DatasetVersion(BaseModel):
as_of: datetime


def _default_extra():
return {"metadata": {}}


class RunBase(BaseModel):
"""Base Run schema.
Expand All @@ -226,7 +229,7 @@ class RunBase(BaseModel):
end_time: Optional[datetime] = None
"""End time of the run, if applicable."""

extra: Optional[dict] = None
extra: Optional[dict] = Field(default_factory=_default_extra)
"""Additional metadata or settings related to the run."""

error: Optional[str] = None
Expand Down Expand Up @@ -258,16 +261,12 @@ class RunBase(BaseModel):
"""Attachments associated with the run.
Each entry is a tuple of (mime_type, bytes)."""

_lock: threading.Lock = PrivateAttr(default_factory=threading.Lock)

@property
def metadata(self) -> dict[str, Any]:
"""Retrieve the metadata (if any)."""
with self._lock:
if self.extra is None:
self.extra = {}
metadata = self.extra.setdefault("metadata", {})
return metadata
if self.extra is None:
self.extra = {}
return self.extra.setdefault("metadata", {})

@property
def revision_id(self) -> Optional[UUID]:
Expand Down
2 changes: 1 addition & 1 deletion python/pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "langsmith"
version = "0.1.130"
version = "0.1.131"
description = "Client library to connect to the LangSmith LLM Tracing and Evaluation Platform."
authors = ["LangChain <support@langchain.dev>"]
license = "MIT"
Expand Down
3 changes: 3 additions & 0 deletions python/tests/unit_tests/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -828,8 +828,10 @@ class MyNamedTuple(NamedTuple):
"fake_json": ClassWithFakeDict(),
"some_set": set("a"),
"set_with_class": set([MyClass(1)]),
"my_mock": MagicMock(text="Hello, world"),
}
res = orjson.loads(_dumps_json(to_serialize))

expected = {
"uid": str(uid),
"time": current_time.isoformat(),
Expand All @@ -848,6 +850,7 @@ class MyNamedTuple(NamedTuple):
"fake_json": {"foo": "bar"},
"some_set": ["a"],
"set_with_class": ["I fell back"],
"my_mock": lambda x: "Mock" in x,
}
assert set(expected) == set(res)
for k, v in expected.items():
Expand Down

0 comments on commit da3c1bb

Please sign in to comment.