Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding Generics to Pyrsistent Classes #282

Merged
merged 2 commits into from
Oct 17, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions pyrsistent/_checked_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,16 @@

from abc import abstractmethod, ABCMeta
from collections.abc import Iterable
from typing import TypeVar, Generic

from pyrsistent._pmap import PMap, pmap
from pyrsistent._pset import PSet, pset
from pyrsistent._pvector import PythonPVector, python_pvector

T_co = TypeVar('T_co', covariant=True)
KT = TypeVar('KT')
VT_co = TypeVar('VT_co', covariant=True)


class CheckedType(object):
"""
Expand Down Expand Up @@ -271,7 +276,7 @@ def _checked_type_create(cls, source_data, _factory_fields=None, ignore_extra=Fa

return cls(source_data)

class CheckedPVector(PythonPVector, CheckedType, metaclass=_CheckedTypeMeta):
class CheckedPVector(Generic[T_co], PythonPVector, CheckedType, metaclass=_CheckedTypeMeta):
"""
A CheckedPVector is a PVector which allows specifying type and invariant checks.

Expand Down Expand Up @@ -357,7 +362,7 @@ def evolver(self):
return CheckedPVector.Evolver(self.__class__, self)


class CheckedPSet(PSet, CheckedType, metaclass=_CheckedTypeMeta):
class CheckedPSet(PSet[T_co], CheckedType, metaclass=_CheckedTypeMeta):
"""
A CheckedPSet is a PSet which allows specifying type and invariant checks.

Expand Down Expand Up @@ -455,7 +460,7 @@ def default_serializer(self, _, key, value):
_UNDEFINED_CHECKED_PMAP_SIZE = object()


class CheckedPMap(PMap, CheckedType, metaclass=_CheckedMapTypeMeta):
class CheckedPMap(PMap[KT, VT_co], CheckedType, metaclass=_CheckedMapTypeMeta):
"""
A CheckedPMap is a PMap which allows specifying type and invariant checks.

Expand Down
5 changes: 4 additions & 1 deletion pyrsistent/_pbag.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
from collections.abc import Container, Iterable, Sized, Hashable
from functools import reduce
from typing import Generic, TypeVar
from pyrsistent._pmap import pmap

T_co = TypeVar('T_co', covariant=True)


def _add_to_counters(counters, element):
return counters.set(element, counters.get(element, 0) + 1)


class PBag(object):
class PBag(Generic[T_co]):
"""
A persistent bag/multiset type.

Expand Down
9 changes: 6 additions & 3 deletions pyrsistent/_pdeque.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
from collections.abc import Sequence, Hashable
from itertools import islice, chain
from numbers import Integral
from typing import TypeVar, Generic
from pyrsistent._plist import plist

T = TypeVar("T")
Copy link
Owner

@tobgu tobgu Oct 16, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this one not covariant?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good catch :) fixed


class PDeque(object):

class PDeque(Generic[T]):
"""
Persistent double ended queue (deque). Allows quick appends and pops in both ends. Implemented
using two persistent lists.
Expand Down Expand Up @@ -175,7 +178,7 @@ def __eq__(self, other):
return False

def __hash__(self):
return hash(tuple(self))
return hash(tuple(self))

def __len__(self):
return self._length
Expand Down Expand Up @@ -275,7 +278,7 @@ def remove(self, elem):
try:
# This is severely inefficient with a double reverse, should perhaps implement a remove_last()?
return PDeque(self._left_list,
self._right_list.reverse().remove(elem).reverse(), self._length - 1)
self._right_list.reverse().remove(elem).reverse(), self._length - 1)
except ValueError as e:
raise ValueError('{0} not found in PDeque'.format(elem)) from e

Expand Down
5 changes: 4 additions & 1 deletion pyrsistent/_plist.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
from collections.abc import Sequence, Hashable
from numbers import Integral
from functools import reduce
from typing import Generic, TypeVar

T_co = TypeVar('T_co', covariant=True)


class _PListBuilder(object):
Expand Down Expand Up @@ -219,7 +222,7 @@ def remove(self, elem):
raise ValueError('{0} not found in PList'.format(elem))


class PList(_PListBase):
class PList(Generic[T_co], _PListBase):
"""
Classical Lisp style singly linked list. Adding elements to the head using cons is O(1).
Element access is O(k) where k is the position of the element in the list. Taking the
Expand Down
6 changes: 5 additions & 1 deletion pyrsistent/_pmap.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
from collections.abc import Mapping, Hashable
from itertools import chain
from typing import Generic, TypeVar

from pyrsistent._pvector import pvector
from pyrsistent._transformations import transform

KT = TypeVar('KT')
VT_co = TypeVar('VT_co', covariant=True)
class PMapView:
"""View type for the persistent map/dict type `PMap`.

Expand Down Expand Up @@ -103,7 +107,7 @@ def __eq__(self, x):
elif not isinstance(x, type(self)): return False
else: return self._map == x._map

class PMap(object):
class PMap(Generic[KT, VT_co]):
"""
Persistent map/dict. Tries to follow the same naming conventions as the built in dict where feasible.

Expand Down
5 changes: 4 additions & 1 deletion pyrsistent/_pset.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
from collections.abc import Set, Hashable
import sys
from typing import TypeVar, Generic
from pyrsistent._pmap import pmap

T_co = TypeVar('T_co', covariant=True)

class PSet(object):

class PSet(Generic[T_co]):
"""
Persistent set implementation. Built on top of the persistent map. The set supports all operations
in the Set protocol and is Hashable.
Expand Down
6 changes: 5 additions & 1 deletion pyrsistent/_pvector.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,12 @@
from collections.abc import Sequence, Hashable
from numbers import Integral
import operator
from typing import TypeVar, Generic

from pyrsistent._transformations import transform

T_co = TypeVar('T_co', covariant=True)


def _bitcount(val):
return bin(val).count("1")
Expand Down Expand Up @@ -410,7 +414,7 @@ def remove(self, value):
l.remove(value)
return _EMPTY_PVECTOR.extend(l)

class PVector(metaclass=ABCMeta):
class PVector(Generic[T_co],metaclass=ABCMeta):
"""
Persistent vector implementation. Meant as a replacement for the cases where you would normally
use a Python list.
Expand Down