Skip to content

Commit 1cdb41e

Browse files
committed
enh: make env and dyn provide the Mapping API
1 parent 75ce089 commit 1cdb41e

File tree

4 files changed

+43
-5
lines changed

4 files changed

+43
-5
lines changed

unpythonic/collections.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717

1818
from .llist import cons
1919
from .misc import getattrrec
20+
from .env import env
21+
from .dynassign import _Env
2022

2123
def get_abcs(cls):
2224
"""Return a set of the collections.abc superclasses of cls (virtuals too)."""
@@ -100,7 +102,9 @@ def doit(x):
100102
# immutable containers
101103
elif isinstance(x, cons):
102104
return cons(doit(x.car), doit(x.cdr))
103-
elif isinstance(x, Mapping):
105+
# env and dyn provide the Mapping API, but shouldn't get the general Mapping treatment here.
106+
# (This is important for the curry and lazify macros.)
107+
elif isinstance(x, Mapping) and not isinstance(x, (env, _Env)):
104108
ctor = type(x)
105109
return ctor({k: doit(v) for k, v in x.items()})
106110
elif isinstance(x, Sequence) and not isinstance(x, (str, bytes, range)):

unpythonic/dynassign.py

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import threading
77
from collections import ChainMap
8+
from collections.abc import Container, Sized, Iterable, Mapping
89

910
# Each new thread, when spawned, inherits the contents of the main thread's
1011
# dynamic scope stack.
@@ -148,14 +149,23 @@ def asdict(self):
148149
"""
149150
return _DynLiveView()
150151

151-
def items(self):
152-
"""Abbreviation for asdict().items()."""
153-
return self.asdict().items()
154-
155152
def __iter__(self):
156153
return iter(self.asdict())
157154
# no __next__, iterating over dict.
158155

156+
# Mapping
157+
def items(self):
158+
"""Abbreviation for asdict().items()."""
159+
return self.asdict().items()
160+
def keys(self):
161+
return self.asdict().keys()
162+
def values(self):
163+
return self.asdict().values()
164+
def get(self, k, default=None):
165+
return self[k] if k in self else default
166+
def __eq__(self, other): # dyn is a singleton, but its contents can be compared to another mapping.
167+
return other == self.asdict()
168+
159169
def __len__(self):
160170
return len(self.asdict())
161171

@@ -199,3 +209,8 @@ def make_dynvar(**bindings):
199209
_global_dynvars[name] = bindings[name]
200210

201211
dyn = _Env()
212+
213+
# register virtual base classes
214+
for abscls in (Container, Sized, Iterable, Mapping):
215+
abscls.register(_Env)
216+
del abscls

unpythonic/env.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33

44
__all__ = ["env"]
55

6+
from collections.abc import Container, Sized, Iterable, Mapping
7+
68
class env:
79
"""Environment for let-like constructs.
810
@@ -90,9 +92,18 @@ def __iter__(self):
9092
return self._env.__iter__()
9193
# no __next__, iterating over dict.
9294

95+
# Mapping
9396
def items(self):
9497
"""Like dict.items()."""
9598
return self._env.items()
99+
def keys(self):
100+
return self._env.keys()
101+
def values(self):
102+
return self._env.values()
103+
def get(self, k, default=None):
104+
return self[k] if k in self else default
105+
def __eq__(self, other):
106+
return other == self._env
96107

97108
def __len__(self):
98109
return len(self._env)
@@ -193,3 +204,8 @@ def finalize(self):
193204
# return cls(obj) # copy-construct obj without wrapper
194205
# assert False, "wrapped value missing in {} {}".format(type(obj), obj)
195206
# return _assignonce_wrapper(obj) # copy-construct obj with wrapper
207+
208+
# register virtual base classes
209+
for abscls in (Container, Sized, Iterable, Mapping):
210+
abscls.register(env)
211+
del abscls

unpythonic/llist.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"""
66

77
from abc import ABCMeta, abstractmethod
8+
from collections.abc import Iterable, Iterator
89
from itertools import zip_longest
910

1011
from .fun import composer1i
@@ -71,6 +72,8 @@ def __iter__(self):
7172
return self
7273
def __next__(self):
7374
return next(self.walker)
75+
Iterable.register(ConsIterator)
76+
Iterator.register(ConsIterator)
7477

7578
class LinkedListIterator(ConsIterator):
7679
"""Iterator for linked lists built from cons cells."""

0 commit comments

Comments
 (0)