Skip to content

Commit

Permalink
Add NoCopyMixin and NoCopyDict to ease intentionally mutable model pr…
Browse files Browse the repository at this point in the history
…ivate attributes

Signed-off-by: Jacob Hayes <jacob.r.hayes@gmail.com>
  • Loading branch information
JacobHayes committed Jul 19, 2022
1 parent 349c09a commit 73a9107
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 10 deletions.
12 changes: 2 additions & 10 deletions src/arti/backends/memory.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,15 @@
from collections import defaultdict
from collections.abc import Iterator
from contextlib import contextmanager
from typing import Any, TypeVar

from pydantic import PrivateAttr

from arti.artifacts import Artifact
from arti.backends import Backend
from arti.fingerprints import Fingerprint
from arti.internal.utils import NoCopyMixin
from arti.storage import AnyStorage, InputFingerprints, StoragePartition, StoragePartitions

_Self = TypeVar("_Self")


def _ensure_fingerprinted(partitions: StoragePartitions) -> Iterator[StoragePartition]:
for partition in partitions:
Expand All @@ -24,7 +22,7 @@ def _ensure_fingerprinted(partitions: StoragePartitions) -> Iterator[StoragePart
_StoragePartitions = dict[AnyStorage, set[StoragePartition]]


class _NoCopyContainer:
class _NoCopyContainer(NoCopyMixin):
"""Container for MemoryBackend data that bypasses (deep)copying.
The MemoryBackend is *intended* to be stateful, like a connection to an external database in
Expand All @@ -45,12 +43,6 @@ def __init__(self) -> None:
self.graph_tags: dict[str, dict[str, Fingerprint]] = defaultdict(dict)
self.storage_partitions: _StoragePartitions = defaultdict(set[StoragePartition])

def __copy__(self: _Self) -> _Self:
return self # pragma: no cover

def __deepcopy__(self: _Self, memo: Any) -> _Self:
return self # pragma: no cover


class MemoryBackend(Backend):
_container: _NoCopyContainer = PrivateAttr(default_factory=_NoCopyContainer)
Expand Down
21 changes: 21 additions & 0 deletions src/arti/internal/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,27 @@ def qname(val: Union[object, type]) -> str:
return type(val).__qualname__


_Self = TypeVar("_Self")


class NoCopyMixin:
"""Mixin to bypass (deep)copying.
This is useful for objects that are *intended* to be stateful and preserved, despite usually
preferring immutable data structures and Pydantic models, which (deep)copy often.
"""

def __copy__(self: _Self) -> _Self:
return self # pragma: no cover

def __deepcopy__(self: _Self, memo: Any) -> _Self:
return self # pragma: no cover


class NoCopyDict(dict[_K, _V], NoCopyMixin):
pass


_K_str = TypeVar("_K_str")


Expand Down

0 comments on commit 73a9107

Please sign in to comment.