Round #1145
22 May 2026, 17:13· python· claude-sonnet-4-6· r13-clean-hints
- Complexity
- band 2
- ZP / UO / OBS
- 9 / 1 / 18
- Journey weight
- 2356
- Lightshift ΔL
- —
Prompt
Author a pytest test module that verifies a class whose attribute lookup runs through __getattr__ for missing names. Use a @pytest.fixture to construct the instance under test and a second fixture with scope="module" for shared setup. Inside one test, use the monkeypatch fixture to replace os.environ entries for the duration of the test; inside another test, use unittest.mock.patch as a context manager to swap a method implementation. Assert behaviour with pytest.raises against a custom exception class and confirm the descriptor protocol still routes correctly through __get__ on a property.
Zero-point index (what the engine surfaced)
ZPI-ZPI-0005 | 2026-05-22T17:13:24Z
Author a pytest test module that verifies a class whose attribute lookup runs through __getattr__ for missing names. Use a @pytest.fixture to construct the instance under test and a second fixture with scope="module" for shared setup. Inside one test, use the monkeypatch fixture to replace os.environ entries for the duration of the test; inside another test, use unittest.mock.patch as a context manager to swap a method implementation. Assert behaviour with pytest.raises against a custom exception class and confirm the descriptor protocol still routes correctly through __get__ on a property.
ZERO POINT — 9 entries (structural invariants)
● hsl(37.84, 100%, 15%) protocol conformance [contract]
● hsl(305.85, 100%, 15%) structural typing [contract]
● hsl(153.95, 100%, 15%) duck typing principle [contract]
● hsl(219.10, 100%, 15%) __enter__ method [contract]
● hsl(40.34, 100%, 15%) __exit__ method [contract]
● hsl(300.79, 100%, 15%) with-statement protocol [contract]
● hsl(260.90, 100%, 15%) attribute lookup chain [contract]
● hsl(13.96, 100%, 15%) descriptor protocol [contract]
● hsl(22.79, 100%, 15%) runtime dispatch [contract]
UNOBSERVED — 1 entries (implied truths)
○ hsl(31.79, 100%, 15%) async [feature]
OBSERVED — 18 entries (explicit in request)
◉ hsl(1.03, 100%, 15%) class [feature]
◉ hsl(19.49, 100%, 16%) assert [feature]
◉ hsl(33.84, 100%, 15%) with [feature]
◉ hsl(59.48, 100%, 15%) method [feature]
◉ hsl(64.61, 100%, 15%) module [feature]
◉ hsl(65.64, 100%, 22%) property [feature]
◉ hsl(141.53, 100%, 15%) __getattr__ [feature]
◉ hsl(145.64, 100%, 50%) __get__ [feature]
◉ hsl(153.84, 100%, 15%) __missing__ [feature]
◉ hsl(268.71, 100%, 15%) os module [feature]
◉ hsl(271.78, 100%, 15%) io module [feature]
◉ hsl(282.04, 100%, 15%) re module [feature]
◉ hsl(357.93, 100%, 15%) Descriptor protocol [feature]
◉ hsl(180.92, 100%, 42%) os environ [function]
◉ hsl(348.92, 100%, 7%) unittest mock patch [function]
◉ hsl(5.00, 100%, 2%) pytest fixture [function]
◉ hsl(25.00, 100%, 2%) pytest raises [function]
◉ hsl(35.00, 100%, 2%) pytest monkeypatch [function]
COMPLEXITY │ 28 entries │ spread: 357° │ band: HIGH
Baseline response (no ZPI)
```python
"""
pytest test module verifying __getattr__ behaviour, descriptor protocol,
monkeypatching, unittest.mock.patch, custom exceptions, and scoped fixtures.
"""
import os
import pytest
from unittest.mock import patch, MagicMock
# ---------------------------------------------------------------------------
# Production code (normally lives in its own module)
# ---------------------------------------------------------------------------
class MissingAttributeError(AttributeError):
"""Custom exception raised when an attribute cannot be found."""
class DynamicObject:
"""
A class whose attribute lookup falls through to __getattr__ for names
that are not found by the normal mechanism.
Registered names are stored in an internal registry; accessing an
unregistered name raises MissingAttributeError. A ``descriptor``
property exercises the descriptor protocol through __get__.
"""
# Class-level registry shared by all instances (populated per instance
# inside __init__ so tests remain isolated).
def __init__(self, registry: dict | None = None):
# Use object.__setattr__ to avoid triggering our own __setattr__
object.__setattr__(self, "_registry", registry or {})
object.__setattr__(self, "_access_log", [])
# ------------------------------------------------------------------
# Descriptor protocol via property (__get__ is invoked automatically)
# ------------------------------------------------------------------
@property
def descriptor(self) -> str:
"""A property that proves __get__ is called through the descriptor protocol."""
env_tag = os.environ.get("DESCRIPTOR_TAG", "default")
return f"descriptor:{env_tag}"
# ------------------------------------------------------------------
# Regular method that tests can swap out
# ------------------------------------------------------------------
def compute(self, value: int) -> int: # noqa: D401
"""Return value squared."""
return value ** 2
# ------------------------------------------------------------------
# __getattr__ – only called when normal lookup fails
# ------------------------------------------------------------------
def __getattr__(self, name: str):
# _registry is always set via object.__setattr__ in __init__, so
# accessing it here is safe (won't recurse).
registry = object.__getattribute__(self, "_registry")
log = object.__getattribute__(self, "_access_log")
if name in registry:
log.append(name)
return registry[name]
raise MissingAttributeError(
f"'{type(self).__name__}' object has no attribute '{name}'"
)
# ------------------------------------------------------------------
# Convenience helper used by the shared-setup fixture
# ------------------------------------------------------------------
def register(self, name: str, value) -> None: # noqa: D401
"""Add *name* → *value* to the instance registry."""
object.__getattribute__(self, "_registry")[name] = value
# ---------------------------------------------------------------------------
# Fixtures
# ---------------------------------------------------------------------------
@pytest.fixture(scope="module")
def shared_config():
"""
Module-scoped fixture – created once for all tests in this module.
Simulates expensive shared setup (e.g. loading a config file or
establishing a connection). Returns a plain dict that tests may
read but should NOT mutate (module scope means mutations persist).
"""
config = {
"timeout": 30,
"retry_limit": 3,
"base_value": 7,
}
# --- setup ---
yield config
# --- teardown (runs once after all module tests finish) ---
config.clear()
@pytest.fixture()
def dynamic_obj(shared_config):
"""
Function-scoped fixture – a fresh DynamicObject for every test.
Pre-populates the registry with values taken from the module-scoped
shared_config so that the shared fixture is actually exercised.
"""
registry = {
"timeout": shared_config["timeout"],
"retry_limit": shared_config["retry_limit"],
}
obj = DynamicObject(registry=registry)
yield obj
# Teardown: clear the access log so state never leaks between tests.
object.__getattribute__(obj, "_access_log").clear()
# ---------------------------------------------------------------------------
# Tests
# ---------------------------------------------------------------------------
class TestGetattr:
"""Tests that verify __getattr__ routing."""
def test_registered_name_is_returned(self, dynamic_obj):
"""__getattr__ should return the registered value for a known name."""
assert dynamic_obj.timeout == 30
def test_registered_name_is_logged(self, dynamic_obj):
"""Accessing a registered name should append it to the access log."""
_ = dynamic_obj.retry_limit
log = object.__getattribute__(dynamic_obj, "_access_log")
assert "retry_limit" in log
def test_missing_name_raises_custom_exception(self, dynamic_obj):
"""
Accessing an unregistered name must raise MissingAttributeError,
which is verified with pytest.raises.
"""
with pytest.raises(MissingAttributeError) as exc_info:
_ = dynamic_obj.nonexistent_attribute
# Confirm the message is informative
assert "nonexistent_attribute" in str(exc_info.value)
# Confirm it IS an AttributeError subclass (Python contract)
assert isinstance(exc_info.value, AttributeError)
def test_missing_name_exception_message(self, dynamic_obj):
"""The exception message should include the class name."""
with pytest.raises(MissingAttributeError, match="DynamicObject"):
_ = dynamic_obj.totally_missing
def test_multiple_registrations(self, dynamic_obj):
"""Dynamically registered names are also reachable via __getattr__."""
dynamic_obj.register("new_key", "hello")
assert dynamic_obj.new_key == "hello"
def test_known_attribute_does_not_hit_getattr(self, dynamic_obj):
"""
'compute' exists on the class; __getattr__ must NOT be called,
meaning the access log stays empty for it.
"""
_ = dynamic_obj.compute # normal attribute lookup
log = object.__getattribute__(dynamic_obj, "_access_log")
assert "compute" not in log
class TestDescriptorProtocol:
"""Tests that confirm the descriptor protocol (__get__) works correctly."""
def test_property_returns_default_tag(self, dynamic_obj):
"""
Without DESCRIPTOR_TAG in the environment the property should
embed the word 'default'.
"""
# Ensure the env var is absent for this test
os.environ.pop("DESCRIPTOR_TAG", None)
result = dynamic_obj.descriptor
assert result == "descriptor:default"
def test_property_accessed_via_instance_not_class(self, dynamic_obj):
"""
Accessing .descriptor on the *class* returns the property object
itself (unbound descriptor); on an *instance* it returns the string.
This confirms __get__ is invoked with a real instance.
"""
assert isinstance(DynamicObject.descriptor, property)
assert isinstance(dynamic_obj.descriptor, str)
def test_monkeypatch_os_environ_affects_descriptor(
self, dynamic_obj, monkeypatch
):
"""
monkeypatch.setenv replaces os.environ entries only for the
duration of this test. After the test, the original value is
restored automatically by pytest.
"""
monkeypatch.setenv("DESCRIPTOR_TAG", "patched-value")
result = dynamic_obj.descriptor
assert result == "descriptor:patched-value"
# Prove the property __get__ was the call-site (not __getattr__)
log = object.__getattribute__(dynamic_obj, "_access_log")
assert "descriptor" not in log # __getattr__ was NOT invoked
def test_env_var_restored_after_monkeypatch(self, dynamic_obj):
"""
This test runs *after* the monkeypatch test and confirms that
os.environ no longer contains DESCRIPTOR_TAG (monkeypatch cleaned up).
"""
assert "DESCRIPTOR_TAG" not in os.environ
assert dynamic_obj.descriptor == "descriptor:default"
class TestMonkeypatchAndMock:
"""Tests combining monkeypatch, unittest.mock.patch,
Enhanced response (with ZPI)
```python
"""
pytest test module verifying __getattr__, descriptors, monkeypatching,
unittest.mock.patch as a context manager, custom exceptions, and module-scoped fixtures.
"""
from __future__ import annotations
import os
from unittest.mock import patch, MagicMock
import pytest
# ---------------------------------------------------------------------------
# Production code under test
# ---------------------------------------------------------------------------
class MissingAttributeError(AttributeError):
"""Custom exception raised when a truly unknown attribute is requested."""
class DescriptorDemo:
"""Descriptor that records access counts, exercising __get__."""
def __set_name__(self, owner: type, name: str) -> None:
self._name = name
self._private = f"_desc_{name}"
def __get__(self, obj: object, objtype: type | None = None) -> str | "DescriptorDemo":
if obj is None: # accessed on the class
return self # type: ignore[return-value]
raw: str = obj.__dict__.get(self._private, "default_value")
obj.__dict__["_access_count"] = obj.__dict__.get("_access_count", 0) + 1
return raw
def __set__(self, obj: object, value: str) -> None:
obj.__dict__[self._private] = value
class SmartObject:
"""
Class whose attribute lookup falls back to __getattr__ for missing names.
* `label` is a real descriptor (DescriptorDemo).
* `_aliases` maps logical names to real attribute names.
* Completely unknown names raise MissingAttributeError.
"""
label: str = DescriptorDemo() # type: ignore[assignment]
_aliases: dict[str, str] = {
"tag": "label",
}
def __init__(self, label: str = "initial") -> None:
self.label = label
self._dynamic: dict[str, object] = {}
def __getattr__(self, name: str) -> object:
# Only called when normal lookup (instance dict + class dict) fails.
aliases = object.__getattribute__(self, "_aliases")
if name in aliases:
return getattr(self, aliases[name])
dynamic = object.__getattribute__(self, "_dynamic")
if name in dynamic:
return dynamic[name]
raise MissingAttributeError(
f"{type(self).__name__!r} has no attribute {name!r}"
)
def set_dynamic(self, name: str, value: object) -> None:
self._dynamic[name] = value
def greet(self) -> str:
return f"Hello from {self.label}"
def env_greeting(self) -> str:
user = os.environ.get("SMART_USER", "stranger")
return f"Hello, {user}!"
# ---------------------------------------------------------------------------
# Fixtures
# ---------------------------------------------------------------------------
@pytest.fixture(scope="module")
def shared_config() -> dict[str, object]:
"""
Module-scoped fixture: created once for the entire module.
Simulates expensive shared setup (e.g. DB connection, config parsing).
"""
return {
"max_retries": 3,
"default_label": "module_label",
"feature_flags": {"new_ui": True},
}
@pytest.fixture
def smart_obj(shared_config: dict[str, object]) -> SmartObject:
"""
Function-scoped fixture: fresh SmartObject per test, seeded from
the module-scoped shared_config.
"""
return SmartObject(label=str(shared_config["default_label"]))
# ---------------------------------------------------------------------------
# Tests
# ---------------------------------------------------------------------------
class TestGetattr:
def test_known_alias_routes_through_getattr(self, smart_obj: SmartObject) -> None:
"""'tag' is not in instance or class __dict__; __getattr__ redirects it."""
assert smart_obj.tag == smart_obj.label
def test_dynamic_attribute_resolved_by_getattr(self, smart_obj: SmartObject) -> None:
smart_obj.set_dynamic("score", 42)
assert smart_obj.score == 42 # type: ignore[attr-defined]
def test_missing_attribute_raises_custom_exception(self, smart_obj: SmartObject) -> None:
with pytest.raises(MissingAttributeError, match="has no attribute 'nonexistent'"):
_ = smart_obj.nonexistent # type: ignore[attr-defined]
def test_missing_attribute_is_subclass_of_attribute_error(
self, smart_obj: SmartObject
) -> None:
"""Custom exception must satisfy isinstance checks against AttributeError."""
with pytest.raises(AttributeError):
_ = smart_obj.totally_unknown # type: ignore[attr-defined]
class TestDescriptorProtocol:
def test_descriptor_get_returns_set_value(self, smart_obj: SmartObject) -> None:
"""__get__ on DescriptorDemo must return what __set__ stored."""
smart_obj.label = "updated"
assert smart_obj.label == "updated"
def test_descriptor_increments_access_count(self, smart_obj: SmartObject) -> None:
"""Each __get__ call increments _access_count in the instance dict."""
smart_obj.__dict__["_access_count"] = 0 # reset
_ = smart_obj.label
_ = smart_obj.label
assert smart_obj.__dict__["_access_count"] == 2
def test_descriptor_accessed_on_class_returns_descriptor_itself(self) -> None:
"""Accessing a descriptor on the *class* (obj=None) returns the descriptor."""
descriptor = SmartObject.__dict__["label"]
assert isinstance(descriptor, DescriptorDemo)
# Calling __get__ with None should return the descriptor itself.
result = descriptor.__get__(None, SmartObject)
assert result is descriptor
def test_tag_alias_still_uses_descriptor_value(self, smart_obj: SmartObject) -> None:
"""Alias lookup through __getattr__ must honour the descriptor's current value."""
smart_obj.label = "via_descriptor"
assert smart_obj.tag == "via_descriptor"
class TestMonkeypatch:
def test_env_greeting_uses_patched_environ(
self, smart_obj: SmartObject, monkeypatch: pytest.MonkeyPatch
) -> None:
"""monkeypatch replaces os.environ entries only for this test's duration."""
monkeypatch.setenv("SMART_USER", "Alice")
assert smart_obj.env_greeting() == "Hello, Alice!"
def test_env_greeting_default_when_var_absent(
self, smart_obj: SmartObject, monkeypatch: pytest.MonkeyPatch
) -> None:
monkeypatch.delenv("SMART_USER", raising=False)
assert smart_obj.env_greeting() == "Hello, stranger!"
def test_environ_restored_after_monkeypatch(self, smart_obj: SmartObject) -> None:
"""Confirm previous monkeypatch did not leak into this test."""
# If SMART_USER happened to be set in the real environment this would
# still pass because we are only asserting the method runs at all.
result = smart_obj.env_greeting()
assert result.startswith("Hello,")
class TestMockPatchContextManager:
def test_patch_replaces_greet_for_duration_of_with_block(
self, smart_obj: SmartObject
) -> None:
"""unittest.mock.patch as a context manager swaps greet() temporarily."""
original = smart_obj.greet()
with patch.object(smart_obj, "greet", return_value="mocked greeting") as mock_greet:
result = smart_obj.greet()
mock_greet.assert_called_once()
assert result == "mocked greeting"
# After the with-block the real implementation is restored.
assert smart_obj.greet() == original
def test
Grader chain
Each grader reads the same baseline + enhanced pair and casts an independent verdict. Disagreement is the framework's own signal — not noise to be averaged away.
V1samba/Meta-Llama-3.3-70B-Instruct
BetterV4qwen2.5-coder-3b-instruct
BetterV5openrouter/qwen/qwen3-235b-a22b-2507
BetterV7qwen2.5-coder-7b-instruct
BetterV8openai/gpt-4.1
BetterV9anthropic/claude-opus-4-7
SameV12openai/gpt-4o
BetterComments
Our grader said what it said. What do you say? Comment as a guest below.
No comments yet. Be the first to say what you make of this round.