Skip to content

Commit feedab7

Browse files
author
Andrei Bratu
committed
fix more tests
1 parent 49b1078 commit feedab7

File tree

7 files changed

+79
-13
lines changed

7 files changed

+79
-13
lines changed

.fernignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ src/humanloop/decorators
1515
src/humanloop/otel
1616
src/humanloop/sync
1717
src/humanloop/cli
18+
pytest.ini
1819

1920
## Tests
2021

poetry.lock

Lines changed: 38 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ replicate = "^1.0.3"
8080
ruff = "^0.5.6"
8181
types-jsonschema = "^4.23.0.20240813"
8282
types-protobuf = "^5.29.1.20250208"
83+
pytest-xdist = "^3.6.1"
8384

8485
[tool.pytest.ini_options]
8586
testpaths = [ "tests" ]

pytest.ini

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[pytest]
2+
addopts = -n auto

src/humanloop/overload.py

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from collections import defaultdict
12
import inspect
23
import logging
34
import types
@@ -99,10 +100,13 @@ def _overload_log(
99100

100101

101102
def overload_call(client: PromptsClient) -> PromptsClient:
102-
client._call = client.call # type: ignore [attr-defined]
103+
if not hasattr(client, "_overloads"):
104+
client._overloads = defaultdict(list) # type: ignore [attr-defined]
105+
if len(client._overloads["call"]) == 0: # type: ignore [attr-defined]
106+
client._overloads["call"].append(client.call) # type: ignore [attr-defined]
103107

104108
def _overload_call(self, **kwargs) -> PromptCallResponse:
105-
# None if not logging inside a decorator
109+
# trace_id is None if logging outside a decorator
106110
trace_id = get_trace_id()
107111
if trace_id is not None:
108112
if "trace_parent_id" in kwargs:
@@ -116,14 +120,13 @@ def _overload_call(self, **kwargs) -> PromptCallResponse:
116120
}
117121

118122
try:
119-
response = self._call(**kwargs)
123+
response = client._overloads["call"][0](**kwargs) # type: ignore [attr-defined]
120124
except Exception as e:
121125
# Re-raising as HumanloopRuntimeError so the decorators don't catch it
122126
raise HumanloopRuntimeError from e
123127

124128
return response
125129

126-
# Replace the original log method with the overloaded one
127130
client.call = types.MethodType(_overload_call, client) # type: ignore [assignment]
128131
return client
129132

@@ -168,13 +171,34 @@ def overload_with_local_files(
168171
Raises:
169172
HumanloopRuntimeError: If use_local_files is True and local file cannot be accessed
170173
"""
171-
original_call = client._call if hasattr(client, "_call") else client.call
172-
original_log = client._log if hasattr(client, "_log") else client.log
174+
if not hasattr(client, "_overloads"):
175+
client._overloads = defaultdict(list) # type: ignore [union-attr]
176+
# If the method has been overloaded, don't re-add the method
177+
if isinstance(client, PromptsClient):
178+
if len(client._overloads["call"]) == 1: # type: ignore [attr-defined]
179+
client._overloads["call"].append(client.call) # type: ignore [attr-defined]
180+
else:
181+
raise RuntimeError(f"Unexpected overload order of operations for {client}.call")
182+
elif isinstance(client, AgentsClient):
183+
if len(client._overloads["call"]) == 0:
184+
client._overloads["call"].append(client.call)
185+
else:
186+
raise RuntimeError(f"Unexpected overload order of operations for {client}.call")
187+
else:
188+
raise NotImplementedError(f"Unsupported client type: {type(client)}")
189+
if len(client._overloads["log"]) == 0:
190+
client._overloads["log"].append(client.log)
191+
else:
192+
raise RuntimeError(f"Unexpected overload order of operations for {client}.log")
193+
173194
file_type = _get_file_type_from_client(client)
174195

175196
def _overload(self, function_name: str, **kwargs) -> PromptCallResponse:
176197
if "id" in kwargs and "path" in kwargs:
177-
raise HumanloopRuntimeError(f"Can only specify one of `id` or `path` when {function_name}ing a {file_type}")
198+
raise HumanloopRuntimeError(
199+
"Can only specify one of `id` or `path` when "
200+
f"{'logging' if function_name == 'log' else 'calling'} a {file_type}"
201+
)
178202
# Handle local files if enabled
179203
if use_local_files and "path" in kwargs:
180204
# Check if version_id or environment is specified
@@ -204,9 +228,9 @@ def _overload(self, function_name: str, **kwargs) -> PromptCallResponse:
204228

205229
try:
206230
if function_name == "call":
207-
return original_call(**kwargs)
231+
return client._overloads["call"][1](**kwargs) # type: ignore [attr-defined, union-attr]
208232
elif function_name == "log":
209-
return original_log(**kwargs)
233+
return client._overloads["log"][0](**kwargs) # type: ignore [attr-defined, union-attr]
210234
else:
211235
raise ValueError(f"Unsupported function name: {function_name}")
212236
except Exception as e:

tests/custom/integration/conftest.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,10 @@ def humanloop_test_client() -> Humanloop:
4141
dotenv.load_dotenv()
4242
if not os.getenv("HUMANLOOP_API_KEY"):
4343
pytest.fail("HUMANLOOP_API_KEY is not set for integration tests")
44-
return Humanloop(api_key=os.getenv("HUMANLOOP_API_KEY"))
44+
return Humanloop(
45+
api_key=os.getenv("HUMANLOOP_API_KEY"),
46+
base_url="http://0.0.0.0:80/v5",
47+
)
4548

4649

4750
@pytest.fixture(scope="function")

tests/custom/integration/test_decorators.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33

44
from openai import OpenAI
55
from humanloop.client import Humanloop
6-
from humanloop.types.chat_message import ChatMessage
76

87

98
def test_prompt_decorator(

0 commit comments

Comments
 (0)