mirror of
https://github.com/tiennm99/serena.git
synced 2026-10-15 02:17:26 +00:00
Refactoring in tests: prepare for testing with multiple languages
This commit is contained in:
1 parent
072b5caefb
commit
433d7f4d59
24 files changed
+103
-159
No files matched your search
@@ -0,0 +1,3 @@
|
||||
"""
|
||||
Custom test package for testing code parsing capabilities.
|
||||
"""
|
||||
@@ -0,0 +1,475 @@
|
||||
"""
|
||||
Advanced Python features for testing code parsing capabilities.
|
||||
|
||||
This module contains various advanced Python code patterns to ensure
|
||||
that the code parser can correctly handle them.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
from abc import ABC, abstractmethod
|
||||
from collections.abc import Callable, Iterable
|
||||
from contextlib import contextmanager
|
||||
from dataclasses import dataclass, field
|
||||
from enum import Enum, Flag, IntEnum, auto
|
||||
from functools import wraps
|
||||
from typing import (
|
||||
Annotated,
|
||||
Any,
|
||||
ClassVar,
|
||||
Final,
|
||||
Generic,
|
||||
Literal,
|
||||
NewType,
|
||||
Protocol,
|
||||
TypedDict,
|
||||
TypeVar,
|
||||
)
|
||||
|
||||
# Type variables for generics
|
||||
T = TypeVar("T")
|
||||
K = TypeVar("K")
|
||||
V = TypeVar("V")
|
||||
|
||||
# Custom types using NewType
|
||||
UserId = NewType("UserId", str)
|
||||
ItemId = NewType("ItemId", int)
|
||||
|
||||
# Type aliases
|
||||
PathLike = str | os.PathLike
|
||||
JsonDict = dict[str, Any]
|
||||
|
||||
|
||||
# TypedDict
|
||||
class UserDict(TypedDict):
|
||||
"""TypedDict representing user data."""
|
||||
|
||||
id: str
|
||||
name: str
|
||||
email: str
|
||||
age: int
|
||||
roles: list[str]
|
||||
|
||||
|
||||
# Enums
|
||||
class Status(Enum):
|
||||
"""Status enum for process states."""
|
||||
|
||||
PENDING = "pending"
|
||||
RUNNING = "running"
|
||||
COMPLETED = "completed"
|
||||
FAILED = "failed"
|
||||
|
||||
|
||||
class Priority(IntEnum):
|
||||
"""Priority levels for tasks."""
|
||||
|
||||
LOW = 0
|
||||
MEDIUM = 5
|
||||
HIGH = 10
|
||||
CRITICAL = auto()
|
||||
|
||||
|
||||
class Permissions(Flag):
|
||||
"""Permission flags for access control."""
|
||||
|
||||
NONE = 0
|
||||
READ = 1
|
||||
WRITE = 2
|
||||
EXECUTE = 4
|
||||
ALL = READ | WRITE | EXECUTE
|
||||
|
||||
|
||||
# Abstract class with various method types
|
||||
class BaseProcessor(ABC):
|
||||
"""Abstract base class for processors with various method patterns."""
|
||||
|
||||
# Class variable with type annotation
|
||||
DEFAULT_TIMEOUT: ClassVar[int] = 30
|
||||
MAX_RETRIES: Final[int] = 3
|
||||
|
||||
def __init__(self, name: str, config: dict[str, Any] | None = None):
|
||||
self.name = name
|
||||
self.config = config or {}
|
||||
self._status = Status.PENDING
|
||||
|
||||
@property
|
||||
def status(self) -> Status:
|
||||
"""Status property getter."""
|
||||
return self._status
|
||||
|
||||
@status.setter
|
||||
def status(self, value: Status) -> None:
|
||||
"""Status property setter."""
|
||||
if not isinstance(value, Status):
|
||||
raise TypeError(f"Expected Status enum, got {type(value)}")
|
||||
self._status = value
|
||||
|
||||
@abstractmethod
|
||||
def process(self, data: Any) -> Any:
|
||||
"""Process the input data."""
|
||||
|
||||
@classmethod
|
||||
def create_from_config(cls, config: dict[str, Any]) -> BaseProcessor:
|
||||
"""Factory classmethod."""
|
||||
name = config.get("name", "default")
|
||||
return cls(name=name, config=config)
|
||||
|
||||
@staticmethod
|
||||
def validate_config(config: dict[str, Any]) -> bool:
|
||||
"""Static method for config validation."""
|
||||
return "name" in config
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"{self.__class__.__name__}(name={self.name})"
|
||||
|
||||
|
||||
# Concrete implementation of abstract class
|
||||
class DataProcessor(BaseProcessor):
|
||||
"""Concrete implementation of BaseProcessor."""
|
||||
|
||||
def __init__(self, name: str, config: dict[str, Any] | None = None, priority: Priority = Priority.MEDIUM):
|
||||
super().__init__(name, config)
|
||||
self.priority = priority
|
||||
self.processed_count = 0
|
||||
|
||||
def process(self, data: Any) -> Any:
|
||||
"""Process the data."""
|
||||
|
||||
# Nested function definition
|
||||
def transform(item: Any) -> Any:
|
||||
# Nested function within a nested function
|
||||
def apply_rules(x: Any) -> Any:
|
||||
return x
|
||||
|
||||
return apply_rules(item)
|
||||
|
||||
# Lambda function
|
||||
normalize = lambda x: x / max(x) if hasattr(x, "__iter__") and len(x) > 0 else x # noqa: F841
|
||||
|
||||
result = transform(data)
|
||||
self.processed_count += 1
|
||||
return result
|
||||
|
||||
# Method with complex type hints
|
||||
def batch_process(self, items: list[str | dict[str, Any] | tuple[Any, ...]]) -> dict[str, list[Any]]:
|
||||
"""Process multiple items in a batch."""
|
||||
results: dict[str, list[Any]] = {"success": [], "error": []}
|
||||
|
||||
for item in items:
|
||||
try:
|
||||
result = self.process(item)
|
||||
results["success"].append(result)
|
||||
except Exception as e:
|
||||
results["error"].append((item, str(e)))
|
||||
|
||||
return results
|
||||
|
||||
# Generator method
|
||||
def process_stream(self, data_stream: Iterable[T]) -> Iterable[T]:
|
||||
"""Process a stream of data, yielding results as they're processed."""
|
||||
for item in data_stream:
|
||||
yield self.process(item)
|
||||
|
||||
# Async method
|
||||
async def async_process(self, data: Any) -> Any:
|
||||
"""Process data asynchronously."""
|
||||
await asyncio.sleep(0.1)
|
||||
return self.process(data)
|
||||
|
||||
# Method with function parameters
|
||||
def apply_transform(self, data: Any, transform_func: Callable[[Any], Any]) -> Any:
|
||||
"""Apply a custom transform function to the data."""
|
||||
return transform_func(data)
|
||||
|
||||
|
||||
# Dataclass
|
||||
@dataclass
|
||||
class Task:
|
||||
"""Task dataclass for tracking work items."""
|
||||
|
||||
id: str
|
||||
name: str
|
||||
status: Status = Status.PENDING
|
||||
priority: Priority = Priority.MEDIUM
|
||||
metadata: dict[str, Any] = field(default_factory=dict)
|
||||
dependencies: list[str] = field(default_factory=list)
|
||||
created_at: float | None = None
|
||||
|
||||
def __post_init__(self):
|
||||
if self.created_at is None:
|
||||
import time
|
||||
|
||||
self.created_at = time.time()
|
||||
|
||||
def has_dependencies(self) -> bool:
|
||||
"""Check if task has dependencies."""
|
||||
return len(self.dependencies) > 0
|
||||
|
||||
|
||||
# Generic class
|
||||
class Repository(Generic[T]):
|
||||
"""Generic repository for managing collections of items."""
|
||||
|
||||
def __init__(self):
|
||||
self.items: dict[str, T] = {}
|
||||
|
||||
def add(self, id: str, item: T) -> None:
|
||||
"""Add an item to the repository."""
|
||||
self.items[id] = item
|
||||
|
||||
def get(self, id: str) -> T | None:
|
||||
"""Get an item by id."""
|
||||
return self.items.get(id)
|
||||
|
||||
def remove(self, id: str) -> bool:
|
||||
"""Remove an item by id."""
|
||||
if id in self.items:
|
||||
del self.items[id]
|
||||
return True
|
||||
return False
|
||||
|
||||
def list_all(self) -> list[T]:
|
||||
"""List all items."""
|
||||
return list(self.items.values())
|
||||
|
||||
|
||||
# Type with Protocol (structural subtyping)
|
||||
class Serializable(Protocol):
|
||||
"""Protocol for objects that can be serialized to dict."""
|
||||
|
||||
def to_dict(self) -> dict[str, Any]: ...
|
||||
|
||||
|
||||
#
|
||||
# Decorator function
|
||||
def log_execution(func: Callable) -> Callable:
|
||||
"""Decorator to log function execution."""
|
||||
|
||||
@wraps(func)
|
||||
def wrapper(*args, **kwargs):
|
||||
print(f"Executing {func.__name__}")
|
||||
result = func(*args, **kwargs)
|
||||
print(f"Finished {func.__name__}")
|
||||
return result
|
||||
|
||||
return wrapper
|
||||
|
||||
|
||||
# Context manager
|
||||
@contextmanager
|
||||
def transaction_context(name: str = "default"):
|
||||
"""Context manager for transaction-like operations."""
|
||||
print(f"Starting transaction: {name}")
|
||||
try:
|
||||
yield name
|
||||
print(f"Committing transaction: {name}")
|
||||
except Exception as e:
|
||||
print(f"Rolling back transaction: {name}, error: {e}")
|
||||
raise
|
||||
|
||||
|
||||
# Function with complex parameter annotations
|
||||
def advanced_search(
|
||||
query: str,
|
||||
filters: dict[str, Any] | None = None,
|
||||
sort_by: str | None = None,
|
||||
sort_order: Literal["asc", "desc"] = "asc",
|
||||
page: int = 1,
|
||||
page_size: int = 10,
|
||||
include_metadata: bool = False,
|
||||
) -> tuple[list[dict[str, Any]], int]:
|
||||
"""
|
||||
Advanced search function with many parameters.
|
||||
|
||||
Returns search results and total count.
|
||||
"""
|
||||
results = []
|
||||
total = 0
|
||||
# Simulating search functionality
|
||||
return results, total
|
||||
|
||||
|
||||
# Class with nested classes
|
||||
class OuterClass:
|
||||
"""Outer class with nested classes and methods."""
|
||||
|
||||
class NestedClass:
|
||||
"""Nested class inside OuterClass."""
|
||||
|
||||
def __init__(self, value: Any):
|
||||
self.value = value
|
||||
|
||||
def get_value(self) -> Any:
|
||||
"""Get the stored value."""
|
||||
return self.value
|
||||
|
||||
class DeeplyNestedClass:
|
||||
"""Deeply nested class for testing parser depth capabilities."""
|
||||
|
||||
def deep_method(self) -> str:
|
||||
"""Method in deeply nested class."""
|
||||
return "deep"
|
||||
|
||||
def __init__(self, name: str):
|
||||
self.name = name
|
||||
self.nested = self.NestedClass(name)
|
||||
|
||||
def get_nested(self) -> NestedClass:
|
||||
"""Get the nested class instance."""
|
||||
return self.nested
|
||||
|
||||
# Method with nested functions
|
||||
def process_with_nested(self, data: Any) -> Any:
|
||||
"""Method demonstrating deeply nested function definitions."""
|
||||
|
||||
def level1(x: Any) -> Any:
|
||||
"""First level nested function."""
|
||||
|
||||
def level2(y: Any) -> Any:
|
||||
"""Second level nested function."""
|
||||
|
||||
def level3(z: Any) -> Any:
|
||||
"""Third level nested function."""
|
||||
return z
|
||||
|
||||
return level3(y)
|
||||
|
||||
return level2(x)
|
||||
|
||||
return level1(data)
|
||||
|
||||
|
||||
# Metaclass example
|
||||
class Meta(type):
|
||||
"""Metaclass example for testing advanced class handling."""
|
||||
|
||||
def __new__(mcs, name, bases, attrs):
|
||||
print(f"Creating class: {name}")
|
||||
return super().__new__(mcs, name, bases, attrs)
|
||||
|
||||
def __init__(cls, name, bases, attrs):
|
||||
print(f"Initializing class: {name}")
|
||||
super().__init__(name, bases, attrs)
|
||||
|
||||
|
||||
class WithMeta(metaclass=Meta):
|
||||
"""Class that uses a metaclass."""
|
||||
|
||||
def __init__(self, value: str):
|
||||
self.value = value
|
||||
|
||||
|
||||
# Factory function that creates and returns instances
|
||||
def create_processor(processor_type: str, name: str, config: dict[str, Any] | None = None) -> BaseProcessor:
|
||||
"""Factory function that creates and returns processor instances."""
|
||||
if processor_type == "data":
|
||||
return DataProcessor(name, config)
|
||||
else:
|
||||
raise ValueError(f"Unknown processor type: {processor_type}")
|
||||
|
||||
|
||||
# Nested decorator example
|
||||
def with_retry(max_retries: int = 3):
|
||||
"""Decorator factory that creates a retry decorator."""
|
||||
|
||||
def decorator(func):
|
||||
@wraps(func)
|
||||
def wrapper(*args, **kwargs):
|
||||
for attempt in range(max_retries):
|
||||
try:
|
||||
return func(*args, **kwargs)
|
||||
except Exception as e:
|
||||
if attempt == max_retries - 1:
|
||||
raise
|
||||
print(f"Retrying {func.__name__} after error: {e}")
|
||||
return None
|
||||
|
||||
return wrapper
|
||||
|
||||
return decorator
|
||||
|
||||
|
||||
@with_retry(max_retries=5)
|
||||
def unreliable_operation(data: Any) -> Any:
|
||||
"""Function that might fail and uses the retry decorator."""
|
||||
import random
|
||||
|
||||
if random.random() < 0.5:
|
||||
raise RuntimeError("Random failure")
|
||||
return data
|
||||
|
||||
|
||||
# Complex type annotation with Annotated
|
||||
ValidatedString = Annotated[str, "A string that has been validated"]
|
||||
PositiveInt = Annotated[int, lambda x: x > 0]
|
||||
|
||||
|
||||
def process_validated_data(data: ValidatedString, count: PositiveInt) -> list[str]:
|
||||
"""Process data with Annotated type hints."""
|
||||
return [data] * count
|
||||
|
||||
|
||||
# Example of forward references and string literals in type annotations
|
||||
class TreeNode:
|
||||
"""Tree node with forward reference to itself in annotations."""
|
||||
|
||||
def __init__(self, value: Any):
|
||||
self.value = value
|
||||
self.children: list[TreeNode] = []
|
||||
|
||||
def add_child(self, child: TreeNode) -> None:
|
||||
"""Add a child node."""
|
||||
self.children.append(child)
|
||||
|
||||
def traverse(self) -> list[Any]:
|
||||
"""Traverse the tree and return all values."""
|
||||
result = [self.value]
|
||||
for child in self.children:
|
||||
result.extend(child.traverse())
|
||||
return result
|
||||
|
||||
|
||||
# Main entry point for demonstration
|
||||
def main() -> None:
|
||||
"""Main function demonstrating the use of various features."""
|
||||
# Create processor
|
||||
processor = DataProcessor("test-processor", {"debug": True})
|
||||
|
||||
# Create tasks
|
||||
task1 = Task(id="task1", name="First Task")
|
||||
task2 = Task(id="task2", name="Second Task", dependencies=["task1"])
|
||||
|
||||
# Create repository
|
||||
repo: Repository[Task] = Repository()
|
||||
repo.add(task1.id, task1)
|
||||
repo.add(task2.id, task2)
|
||||
|
||||
# Process some data
|
||||
data = [1, 2, 3, 4, 5]
|
||||
result = processor.process(data) # noqa: F841
|
||||
|
||||
# Use context manager
|
||||
with transaction_context("main"):
|
||||
# Process more data
|
||||
for task in repo.list_all():
|
||||
processor.process(task.name)
|
||||
|
||||
# Use advanced search
|
||||
results, total = advanced_search(query="test", filters={"status": Status.PENDING}, sort_by="priority", page=1, include_metadata=True)
|
||||
|
||||
# Create a tree
|
||||
root = TreeNode("root")
|
||||
child1 = TreeNode("child1")
|
||||
child2 = TreeNode("child2")
|
||||
root.add_child(child1)
|
||||
root.add_child(child2)
|
||||
child1.add_child(TreeNode("grandchild1"))
|
||||
|
||||
print("Done!")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in new issue
Block a user