• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

basilisp-lang / basilisp / 7379247703

01 Jan 2024 06:37PM CUT coverage: 99.008%. Remained the same
7379247703

push

github

web-flow
callable var (#768)

Hi,

could you please review compatibility patch with Clojure to make vars
callable. It addresses #767.

I am not sure this if the `class Var` is the right place to make vars
callable or the analyzer, which should expand them to a callable var
value last node.

Nevertheless, I will kindly request your help with the type hinting,
currently it will fail the linter with the following error

```
src/basilisp/lang/runtime.py:279:15: E1102: self.value is not callable (not-callable)
```

but not sure how to fix it, I've tried the class Var `value` property
method to return a maybe Callable but it didn't work.

Thanks

Co-authored-by: ikappaki <ikappaki@users.noreply.github.com>

1691 of 1693 branches covered (0.0%)

Branch coverage included in aggregate %.

7892 of 7986 relevant lines covered (98.82%)

0.99 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

96.13
/src/basilisp/lang/vector.py
1
from functools import total_ordering
1✔
2
from typing import Iterable, Optional, Sequence, TypeVar, Union
1✔
3

4
from pyrsistent import PVector, pvector  # noqa # pylint: disable=unused-import
1✔
5
from pyrsistent.typing import PVectorEvolver
1✔
6

7
from basilisp.lang.interfaces import (
1✔
8
    IEvolveableCollection,
9
    ILispObject,
10
    IMapEntry,
11
    IPersistentMap,
12
    IPersistentVector,
13
    ISeq,
14
    ITransientVector,
15
    IWithMeta,
16
    seq_equals,
17
)
18
from basilisp.lang.obj import seq_lrepr as _seq_lrepr
1✔
19
from basilisp.lang.seq import sequence
1✔
20
from basilisp.util import partition
1✔
21

22
T = TypeVar("T")
1✔
23

24

25
class TransientVector(ITransientVector[T]):
1✔
26
    __slots__ = ("_inner",)
1✔
27

28
    def __init__(self, wrapped: "PVectorEvolver[T]") -> None:
1✔
29
        self._inner = wrapped
1✔
30

31
    def __bool__(self):
1✔
32
        return True
1✔
33

34
    def __contains__(self, item):
1✔
35
        return item in self._inner
×
36

37
    def __eq__(self, other):
1✔
38
        return self is other
1✔
39

40
    def __len__(self):
1✔
41
        return len(self._inner)
1✔
42

43
    def cons_transient(self, *elems: T) -> "TransientVector[T]":  # type: ignore[override]
1✔
44
        for elem in elems:
1✔
45
            self._inner.append(elem)
1✔
46
        return self
1✔
47

48
    def assoc_transient(self, *kvs: T) -> "TransientVector[T]":
1✔
49
        for i, v in partition(kvs, 2):
1✔
50
            self._inner.set(i, v)
1✔
51
        return self
1✔
52

53
    def contains_transient(self, k: int) -> bool:
1✔
54
        return 0 <= k < len(self._inner)
×
55

56
    def entry_transient(self, k: int) -> Optional[IMapEntry[int, T]]:
1✔
57
        try:
×
58
            return MapEntry.of(k, self._inner[k])
×
59
        except IndexError:
×
60
            return None
×
61

62
    def val_at(self, k: int, default=None):
1✔
63
        try:
1✔
64
            return self._inner[k]
1✔
65
        except IndexError:
1✔
66
            return default
1✔
67

68
    def pop_transient(self) -> "TransientVector[T]":
1✔
69
        if len(self) == 0:
1✔
70
            raise IndexError("Cannot pop an empty vector")
1✔
71
        del self._inner[-1]
1✔
72
        return self
1✔
73

74
    def to_persistent(self) -> "PersistentVector[T]":
1✔
75
        return PersistentVector(self._inner.persistent())
1✔
76

77

78
@total_ordering
1✔
79
class PersistentVector(
1✔
80
    IPersistentVector[T], IEvolveableCollection[TransientVector], ILispObject, IWithMeta
81
):
82
    """Basilisp Vector. Delegates internally to a pyrsistent.PVector object.
83
    Do not instantiate directly. Instead use the v() and vec() factory
84
    methods below."""
85

86
    __slots__ = ("_inner", "_meta")
1✔
87

88
    def __init__(
1✔
89
        self, wrapped: "PVector[T]", meta: Optional[IPersistentMap] = None
90
    ) -> None:
91
        self._inner = wrapped
1✔
92
        self._meta = meta
1✔
93

94
    def __bool__(self):
1✔
95
        return True
1✔
96

97
    def __contains__(self, item):
1✔
98
        return item in self._inner
1✔
99

100
    def __eq__(self, other):
1✔
101
        if self is other:
1✔
102
            return True
1✔
103
        if hasattr(other, "__len__") and len(self) != len(other):
1✔
104
            return False
1✔
105
        return seq_equals(self, other)
1✔
106

107
    def __getitem__(self, item):
1✔
108
        if isinstance(item, slice):
1✔
109
            return PersistentVector(self._inner[item])
1✔
110
        return self._inner[item]
1✔
111

112
    def __hash__(self):
1✔
113
        return hash(self._inner)
1✔
114

115
    def __iter__(self):
1✔
116
        yield from self._inner
1✔
117

118
    def __len__(self):
1✔
119
        return len(self._inner)
1✔
120

121
    def __lt__(self, other):
1✔
122
        """Return true if the `self` vector is shorter than the
123
        `other` vector, or the first unequal element in `self` when
124
        iterating from left to right is less than the corresponding
125
        `other` element.
126

127
        This is to support the comparing and sorting operations of
128
        vectors in Clojure."""
129

130
        if other is None:  # pragma: no cover
131
            return False
132
        if not isinstance(other, PersistentVector):
1✔
133
            return NotImplemented
1✔
134
        if len(self) != len(other):
1✔
135
            return len(self) < len(other)
1✔
136

137
        for x, y in zip(self, other):
1✔
138
            if x < y:
1✔
139
                return True
1✔
140
            elif y < x:
1✔
141
                return False
1✔
142
        return False
1✔
143

144
    def _lrepr(self, **kwargs) -> str:
1✔
145
        return _seq_lrepr(self._inner, "[", "]", meta=self._meta, **kwargs)
1✔
146

147
    @property
1✔
148
    def meta(self) -> Optional[IPersistentMap]:
1✔
149
        return self._meta
1✔
150

151
    def with_meta(self, meta: Optional[IPersistentMap]) -> "PersistentVector[T]":
1✔
152
        return vector(self._inner, meta=meta)
1✔
153

154
    def cons(self, *elems: T) -> "PersistentVector[T]":  # type: ignore[override]
1✔
155
        e = self._inner.evolver()
1✔
156
        for elem in elems:
1✔
157
            e.append(elem)
1✔
158
        return PersistentVector(e.persistent(), meta=self.meta)
1✔
159

160
    def assoc(self, *kvs: T) -> "PersistentVector[T]":
1✔
161
        return PersistentVector(self._inner.mset(*kvs))  # type: ignore[arg-type]
1✔
162

163
    def contains(self, k):
1✔
164
        return 0 <= k < len(self._inner)
1✔
165

166
    def entry(self, k):
1✔
167
        try:
1✔
168
            return MapEntry.of(k, self._inner[k])
1✔
169
        except IndexError:
1✔
170
            return None
1✔
171

172
    def val_at(self, k, default=None):
1✔
173
        try:
1✔
174
            return self._inner[k]
1✔
175
        except IndexError:
1✔
176
            return default
1✔
177

178
    @staticmethod
1✔
179
    def empty() -> "PersistentVector[T]":
1✔
180
        return EMPTY
1✔
181

182
    def seq(self) -> Optional[ISeq[T]]:  # type: ignore[override]
1✔
183
        if len(self._inner) == 0:
1✔
184
            return None
1✔
185
        return sequence(self)
1✔
186

187
    def peek(self) -> Optional[T]:
1✔
188
        if len(self) == 0:
1✔
189
            return None
1✔
190
        return self[-1]
1✔
191

192
    def pop(self) -> "PersistentVector[T]":
1✔
193
        if len(self) == 0:
1✔
194
            raise IndexError("Cannot pop an empty vector")
1✔
195
        return self[:-1]
1✔
196

197
    def rseq(self) -> ISeq[T]:
1✔
198
        return sequence(reversed(self))
1✔
199

200
    def to_transient(self) -> TransientVector:
1✔
201
        return TransientVector(self._inner.evolver())
1✔
202

203

204
K = TypeVar("K")
1✔
205
V = TypeVar("V")
1✔
206

207

208
class MapEntry(IMapEntry[K, V], PersistentVector[Union[K, V]]):
1✔
209
    __slots__ = ()
1✔
210

211
    def __init__(self, wrapped: "PVector[Union[K, V]]") -> None:
1✔
212
        try:
1✔
213
            if not len(wrapped) == 2:
1✔
214
                raise ValueError("Vector arg to map conj must be a pair")
1✔
215
        except TypeError as e:
1✔
216
            raise TypeError(f"Cannot make map entry from {type(wrapped)}") from e
×
217

218
        super().__init__(wrapped)
1✔
219

220
    @property
1✔
221
    def key(self) -> K:
1✔
222
        return self[0]
1✔
223

224
    @property
1✔
225
    def value(self) -> V:
1✔
226
        return self[1]
1✔
227

228
    @staticmethod
1✔
229
    def of(k: K, v: V) -> "MapEntry[K, V]":
1✔
230
        return MapEntry(pvector([k, v]))
1✔
231

232
    @staticmethod
1✔
233
    def from_vec(v: Sequence[Union[K, V]]) -> "MapEntry[K, V]":
1✔
234
        return MapEntry(pvector(v))
1✔
235

236

237
EMPTY: PersistentVector = PersistentVector(pvector(()))
1✔
238

239

240
def vector(
1✔
241
    members: Iterable[T], meta: Optional[IPersistentMap] = None
242
) -> PersistentVector[T]:
243
    """Creates a new vector."""
244
    return PersistentVector(pvector(members), meta=meta)
1✔
245

246

247
def v(*members: T, meta: Optional[IPersistentMap] = None) -> PersistentVector[T]:
1✔
248
    """Creates a new vector from members."""
249
    return PersistentVector(pvector(members), meta=meta)
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc