|
6 | 6 |
|
7 | 7 | from abc import ABCMeta, abstractmethod |
8 | 8 | from collections.abc import Callable, Generator, Iterable, Iterator |
| 9 | +from dataclasses import FrozenInstanceError |
9 | 10 | from itertools import zip_longest |
10 | 11 | from typing import Any |
11 | 12 |
|
|
18 | 19 | _fill = gensym("fill") |
19 | 20 |
|
20 | 21 | # explicit list better for tooling support |
21 | | -_exports = ["cons", "nil", |
| 22 | +_exports = ["FrozenAttributeError", |
| 23 | + "cons", "nil", |
22 | 24 | "LinkedListIterator", "LinkedListOrCellIterator", "TailIterator", |
23 | 25 | "BinaryTreeIterator", "ConsIterator", |
24 | 26 | "car", "cdr", |
|
37 | 39 | #_exports.extend(_c4r) |
38 | 40 | __all__ = _exports |
39 | 41 |
|
| 42 | +class FrozenAttributeError(TypeError, FrozenInstanceError): |
| 43 | + """Raised on a write/delete attempt against a frozen-instance type. |
| 44 | +
|
| 45 | + Multiply-inherits from `TypeError` (the legacy unpythonic <= 2.x base) |
| 46 | + and `dataclasses.FrozenInstanceError` (the standard-library convention |
| 47 | + since Python 3.7, itself a subclass of `AttributeError`). Either |
| 48 | + `except` clause catches it. |
| 49 | +
|
| 50 | + Compatibility shim: lets unpythonic align with the stdlib idiom |
| 51 | + without breaking user code that catches `TypeError`. The `TypeError` |
| 52 | + base will be dropped in 3.0.0 (see issue #35), at which point this |
| 53 | + class becomes a plain `FrozenInstanceError` and likely goes away. |
| 54 | + """ |
| 55 | + |
40 | 56 | class Nil(Singleton): |
41 | 57 | """The empty linked list. Singleton.""" |
42 | 58 | # support the iterator protocol so we can say tuple(nil) --> () |
@@ -220,9 +236,9 @@ def __init__(self, v1: Any, v2: Any) -> None: |
220 | 236 | object.__setattr__(self, "car", v1) |
221 | 237 | object.__setattr__(self, "cdr", v2) |
222 | 238 | def __setattr__(self, k: str, v: Any) -> None: |
223 | | - raise TypeError(f"'cons' object does not support attribute assignment; tried to set {k!r}") |
| 239 | + raise FrozenAttributeError(f"'cons' object does not support attribute assignment; tried to set {k!r}") |
224 | 240 | def __delattr__(self, k: str) -> None: |
225 | | - raise TypeError(f"'cons' object does not support attribute deletion; tried to delete {k!r}") |
| 241 | + raise FrozenAttributeError(f"'cons' object does not support attribute deletion; tried to delete {k!r}") |
226 | 242 | def __iter__(self) -> LinkedListOrCellIterator: |
227 | 243 | """Return iterator with default iteration scheme: single cell or list.""" |
228 | 244 | return LinkedListOrCellIterator(self) |
|
0 commit comments