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
Better
V4qwen2.5-coder-3b-instruct
Better
V5openrouter/qwen/qwen3-235b-a22b-2507
Better
V7qwen2.5-coder-7b-instruct
Better
V8openai/gpt-4.1
Better
V9anthropic/claude-opus-4-7
Same
V12openai/gpt-4o
Better

Comments

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.

← back to all rounds