|
1 | 1 | import asyncio |
2 | 2 | import inspect |
3 | | -import itertools |
4 | 3 | import typing |
| 4 | +from collections import UserDict |
5 | 5 | from collections.abc import Callable, Iterable, Mapping, MutableMapping |
6 | 6 | from functools import cached_property, wraps |
7 | 7 | from inspect import Parameter |
|
47 | 47 | """Sentinel value to distinguish between missing values and present but null values""" |
48 | 48 |
|
49 | 49 |
|
50 | | -class LazyFixtures(Mapping[str, Any]): |
| 50 | +class LazyFixtures(UserDict[str, Any]): |
51 | 51 | """ |
52 | 52 | Wrapper around fixtures and fixture generators |
53 | 53 |
|
54 | 54 | If a fixture is provided at runtime, the generator function does not have to be called. |
55 | 55 | """ |
56 | 56 |
|
57 | | - ready: MutableMapping[str, Any] |
58 | 57 | lazy: MutableMapping[str, Callable[[], Any]] |
59 | 58 |
|
60 | 59 | def __init__( |
61 | 60 | self, |
62 | 61 | provided: Mapping[str, Any] | None, |
63 | 62 | factories: Mapping[str, Callable[[], Any]], |
64 | 63 | ): |
65 | | - # wrap to prevent modification escaping |
66 | | - self.ready = dict(provided or {}) |
67 | | - # drop duplicate keys so the len and iter methods are easier |
68 | | - self.lazy = {k: v for k, v in factories.items() if k not in self.ready} |
69 | | - |
70 | | - def __contains__(self, key: Any) -> bool: |
71 | | - return key in self.ready or key in self.lazy |
72 | | - |
73 | | - def __len__(self) -> int: |
74 | | - # Can just add the lengths as the keys are distinct by construction |
75 | | - return len(self.ready.keys()) + len(self.lazy.keys()) |
| 64 | + super().__init__(dict.fromkeys(factories, _EMPTY) | dict(provided or {})) |
| 65 | + self.lazy = dict(factories) |
76 | 66 |
|
77 | 67 | def __getitem__(self, key: str) -> Any: |
78 | | - if key in self.ready: |
79 | | - return self.ready[key] |
80 | | - if factory := self.lazy.pop(key, None): |
81 | | - value = factory() |
82 | | - self.ready[key] = value |
83 | | - return value |
84 | | - raise KeyError(key) |
85 | | - |
86 | | - def __iter__(self): |
87 | | - return itertools.chain(self.lazy.keys(), self.ready.keys()) |
| 68 | + if self.data[key] is _EMPTY: |
| 69 | + self.data[key] = self.lazy[key]() |
| 70 | + return self.data[key] |
88 | 71 |
|
89 | 72 |
|
90 | 73 | class DeviceFactory(Generic[Args, V2]): |
|
0 commit comments