Files
wehub-resource-sync e9a2f726c9
CI / test (3.11) (push) Has been cancelled
CI / test (3.12) (push) Has been cancelled
CI / test (3.13) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:29:51 +08:00

180 lines
5.2 KiB
Python

# SPDX-License-Identifier: Apache-2.0
"""
Pytest configuration and fixtures for oMLX tests.
This module provides common fixtures used across test files.
"""
from pathlib import Path
from typing import Any, Dict, List, Optional
from unittest.mock import MagicMock
import pytest
# Install the torch stub before any test imports xgrammar (e.g. via @patch
# decorators that resolve the target at collection time). When real torch is
# present this is a no-op; in the DMG layout it satisfies xgrammar's
# import-time torch references so the package can load.
from omlx._torch_stub import install as _install_torch_stub
_install_torch_stub()
from omlx.request import Request, SamplingParams
class MockTokenizer:
"""Mock tokenizer for testing without loading real models."""
def __init__(self, vocab_size: int = 32000):
self.vocab_size = vocab_size
self.eos_token_id = 2
self.pad_token_id = 0
self.bos_token_id = 1
def encode(self, text: str, add_special_tokens: bool = True) -> List[int]:
"""Encode text to token ids (simple simulation)."""
# Simple simulation: each word becomes a token
tokens = []
if add_special_tokens:
tokens.append(self.bos_token_id)
# Simulate tokenization by splitting on spaces
for i, word in enumerate(text.split()):
# Use hash to get a consistent token id for each word
token_id = (hash(word) % (self.vocab_size - 10)) + 10
tokens.append(token_id)
return tokens
def decode(
self,
token_ids: List[int],
skip_special_tokens: bool = True,
) -> str:
"""Decode token ids to text (simple simulation)."""
if skip_special_tokens:
token_ids = [
t
for t in token_ids
if t not in (self.eos_token_id, self.pad_token_id, self.bos_token_id)
]
# Return a placeholder string representing the token count
return f"<decoded:{len(token_ids)} tokens>"
def __call__(
self,
text: str,
return_tensors: Optional[str] = None,
**kwargs: Any,
) -> Dict[str, Any]:
"""Tokenize text and return dict with input_ids."""
input_ids = self.encode(text)
return {"input_ids": input_ids}
class MockModelConfig:
"""Mock model configuration for testing."""
def __init__(
self,
hidden_size: int = 4096,
num_hidden_layers: int = 32,
num_attention_heads: int = 32,
vocab_size: int = 32000,
model_type: str = "llama",
):
self.hidden_size = hidden_size
self.num_hidden_layers = num_hidden_layers
self.num_attention_heads = num_attention_heads
self.vocab_size = vocab_size
self.model_type = model_type
class MockModel:
"""Mock model for testing without loading real models."""
def __init__(self, config: Optional[MockModelConfig] = None):
self.config = config or MockModelConfig()
self._parameters: Dict[str, Any] = {}
def __call__(self, input_ids: Any, **kwargs: Any) -> Any:
"""Forward pass (returns mock logits)."""
mock_output = MagicMock()
mock_output.shape = (1, len(input_ids) if hasattr(input_ids, "__len__") else 1, self.config.vocab_size)
return mock_output
def parameters(self) -> Dict[str, Any]:
"""Return model parameters."""
return self._parameters
@pytest.fixture
def mock_tokenizer() -> MockTokenizer:
"""Provide a mock tokenizer for tests."""
return MockTokenizer()
@pytest.fixture
def mock_model() -> MockModel:
"""Provide a mock model for tests."""
return MockModel()
@pytest.fixture
def mock_model_config() -> MockModelConfig:
"""Provide a mock model configuration for tests."""
return MockModelConfig()
@pytest.fixture
def tmp_cache_dir(tmp_path: Path) -> Path:
"""Provide a temporary cache directory for tests."""
cache_dir = tmp_path / "cache"
cache_dir.mkdir(parents=True, exist_ok=True)
return cache_dir
@pytest.fixture
def sample_request() -> Request:
"""Factory fixture for creating sample Request objects."""
return Request(
request_id="test-request-001",
prompt="Hello, world!",
sampling_params=SamplingParams(
max_tokens=100,
temperature=0.7,
top_p=0.9,
),
)
@pytest.fixture
def sample_request_factory():
"""Factory fixture for creating multiple Request objects."""
def _create_request(
request_id: str = "test-request-001",
prompt: str = "Hello, world!",
max_tokens: int = 100,
temperature: float = 0.7,
top_p: float = 0.9,
) -> Request:
return Request(
request_id=request_id,
prompt=prompt,
sampling_params=SamplingParams(
max_tokens=max_tokens,
temperature=temperature,
top_p=top_p,
),
)
return _create_request
@pytest.fixture
def real_model_dir() -> Path:
"""Return the path to real models directory.
Note: Tests using this fixture may require actual model files
and should be marked with @pytest.mark.slow.
"""
return Path.home() / "Workspace" / "models"