mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-21 00:21:49 +00:00
tests/integration/conftest.py imported the bare `integration` package. Because tests/__init__.py and tests/integration/__init__.py both exist, pytest's default prepend import mode puts only the repo root on sys.path, so that name resolved only under the PYTHONPATH that tests/integration/run.py injects. Every other invocation died at conftest import with ModuleNotFoundError: No module named 'integration' and exit 4, including the command test_oci_integration.py documents in its own docstring. The imports now use the tests.integration._support path that pytest actually resolves, matching the 120 other `from tests.` imports in the suite. run.py's PYTHONPATH still works because it already puts the repo root on the path. tests/code_coverage_tests/test_integration_suite_imports.py collects every file under tests/integration with PYTHONPATH scrubbed and asserts a non-zero collection count, so an unresolvable import fails the code-quality job instead of only the developers who run these files by hand. CI runs the three pre-existing files through the allowlist rather than executing them, which is why nothing caught this.
52 lines
1.4 KiB
Python
52 lines
1.4 KiB
Python
from typing import Final
|
|
from dataclasses import dataclass
|
|
from collections.abc import Iterator, Sequence
|
|
from contextlib import contextmanager
|
|
|
|
import httpx
|
|
from hypothesis import Phase, settings
|
|
|
|
from tests.integration._support.client import Gateway
|
|
|
|
LIFECYCLE_SETTINGS: Final = settings(
|
|
max_examples=20,
|
|
stateful_step_count=8,
|
|
deadline=None,
|
|
database=None,
|
|
phases=(Phase.generate, Phase.shrink),
|
|
print_blob=True,
|
|
)
|
|
|
|
|
|
@dataclass(slots=True)
|
|
class RequestBudget:
|
|
limit: int
|
|
requests: int = 0
|
|
cleaning: bool = False
|
|
|
|
def observe(self, _request: httpx.Request) -> None:
|
|
if self.cleaning:
|
|
return
|
|
self.requests += 1
|
|
assert self.requests <= self.limit, f"Generated HTTP operation budget exceeded: {self.limit}"
|
|
|
|
@contextmanager
|
|
def cleanup(self) -> Iterator[None]:
|
|
self.cleaning = True
|
|
try:
|
|
yield
|
|
finally:
|
|
self.cleaning = False
|
|
|
|
|
|
@contextmanager
|
|
def bounded_http_requests(gateways: Sequence[Gateway], limit: int) -> Iterator[RequestBudget]:
|
|
budget: Final = RequestBudget(limit)
|
|
for gateway in gateways:
|
|
gateway.client.event_hooks["request"].append(budget.observe)
|
|
try:
|
|
yield budget
|
|
finally:
|
|
for gateway in gateways:
|
|
gateway.client.event_hooks["request"].remove(budget.observe)
|
|
print(f"Generated HTTP operations: {budget.requests}/{budget.limit}; cleanup excluded")
|