litellm/tests/integration/_support/generation.py
Yuneng Jiang 3b0fbc426d
fix(tests): resolve the integration support package without run.py's PYTHONPATH
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.
2026-09-15 21:10:08 -07:00

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")