| 539 | |
| 540 | @final |
| 541 | class NodeKeywords(MutableMapping[str, Any]): |
| 542 | __slots__ = ("node", "parent", "_markers") |
| 543 | |
| 544 | def __init__(self, node: "Node") -> None: |
| 545 | self.node = node |
| 546 | self.parent = node.parent |
| 547 | self._markers = {node.name: True} |
| 548 | |
| 549 | def __getitem__(self, key: str) -> Any: |
| 550 | try: |
| 551 | return self._markers[key] |
| 552 | except KeyError: |
| 553 | if self.parent is None: |
| 554 | raise |
| 555 | return self.parent.keywords[key] |
| 556 | |
| 557 | def __setitem__(self, key: str, value: Any) -> None: |
| 558 | self._markers[key] = value |
| 559 | |
| 560 | # Note: we could've avoided explicitly implementing some of the methods |
| 561 | # below and use the collections.abc fallback, but that would be slow. |
| 562 | |
| 563 | def __contains__(self, key: object) -> bool: |
| 564 | return ( |
| 565 | key in self._markers |
| 566 | or self.parent is not None |
| 567 | and key in self.parent.keywords |
| 568 | ) |
| 569 | |
| 570 | def update( # type: ignore[override] |
| 571 | self, |
| 572 | other: Union[Mapping[str, Any], Iterable[Tuple[str, Any]]] = (), |
| 573 | **kwds: Any, |
| 574 | ) -> None: |
| 575 | self._markers.update(other) |
| 576 | self._markers.update(kwds) |
| 577 | |
| 578 | def __delitem__(self, key: str) -> None: |
| 579 | raise ValueError("cannot delete key in keywords dict") |
| 580 | |
| 581 | def __iter__(self) -> Iterator[str]: |
| 582 | # Doesn't need to be fast. |
| 583 | yield from self._markers |
| 584 | if self.parent is not None: |
| 585 | for keyword in self.parent.keywords: |
| 586 | # self._marks and self.parent.keywords can have duplicates. |
| 587 | if keyword not in self._markers: |
| 588 | yield keyword |
| 589 | |
| 590 | def __len__(self) -> int: |
| 591 | # Doesn't need to be fast. |
| 592 | return sum(1 for keyword in self) |
| 593 | |
| 594 | def __repr__(self) -> str: |
| 595 | return f"<NodeKeywords for node {self.node}>" |