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

basilisp-lang / basilisp / 12037821047

26 Nov 2024 07:38PM UTC coverage: 98.79% (+0.001%) from 98.789%
12037821047

Pull #1147

github

web-flow
Merge 6af1bc1e7 into c8b168ed8
Pull Request #1147: Proxies

1031 of 1038 branches covered (99.33%)

Branch coverage included in aggregate %.

11 of 11 new or added lines in 3 files covered. (100.0%)

1 existing line in 1 file now uncovered.

8849 of 8963 relevant lines covered (98.73%)

0.99 hits per line

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

99.62
/src/basilisp/lang/interfaces.py
1
import itertools
1✔
2
from abc import ABC, abstractmethod
1✔
3
from collections.abc import Hashable, Iterable, Iterator, Mapping, Sequence, Sized
1✔
4
from typing import (
1✔
5
    AbstractSet,
6
    Any,
7
    Callable,
8
    Final,
9
    Generic,
10
    Optional,
11
    Protocol,
12
    TypeVar,
13
    Union,
14
    overload,
15
)
16

17
from typing_extensions import Self, Unpack
1✔
18

19
from basilisp.lang.obj import LispObject as _LispObject
1✔
20
from basilisp.lang.obj import PrintSettings, seq_lrepr
1✔
21

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

24

25
class IDeref(Generic[T], ABC):
1✔
26
    """``IDeref`` types are reference container types which return their contained
27
    value via :lpy:fn:`deref` .
28

29
    .. seealso::
30

31
       :py:class:`IBlockingDeref`"""
32

33
    __slots__ = ()
1✔
34

35
    @abstractmethod
1✔
36
    def deref(self) -> Optional[T]:
1✔
37
        raise NotImplementedError()
38

39

40
class IBlockingDeref(IDeref[T]):
1✔
41
    """``IBlockingDeref`` types are reference container types which may block returning
42
    their contained value. The contained value can be fetched with a timeout and default
43
    via :lpy:fn:`deref` .
44

45
    .. seealso::
46

47
       :py:class:`IDeref`"""
48

49
    __slots__ = ()
1✔
50

51
    @abstractmethod
1✔
52
    def deref(
1✔
53
        self, timeout: Optional[float] = None, timeout_val: Optional[T] = None
54
    ) -> Optional[T]:
55
        raise NotImplementedError()
56

57

58
class ICounted(Sized, ABC):
1✔
59
    """``ICounted`` is a marker interface for types can produce their length in
60
    constant time.
61

62
    All the builtin collections are ``ICounted``, except Lists whose length is
63
    determined by counting all the elements in the list in linear time.
64

65
    .. seealso::
66

67
       :lpy:fn:`counted?`"""
68

69
    __slots__ = ()
1✔
70

71

72
class IIndexed(ICounted, ABC):
1✔
73
    """``IIndexed`` is a marker interface for types can be accessed by index.
74

75
    Of the builtin collections, only Vectors are ``IIndexed`` . ``IIndexed`` types
76
    respond ``True`` to the :lpy:fn:`indexed?` predicate.
77

78
    .. seealso::
79

80
       :lpy:fn:`indexed?`"""
81

82
    __slots__ = ()
1✔
83

84

85
T_ExceptionInfo = TypeVar("T_ExceptionInfo", bound="IPersistentMap")
1✔
86

87

88
class IExceptionInfo(Exception, Generic[T_ExceptionInfo], ABC):
1✔
89
    """``IExceptionInfo`` types are exception types which contain an optional
90
    :py:class:`IPersistentMap` data element of contextual information about the thrown
91
    exception.
92

93
    .. seealso::
94

95
       :lpy:fn:`ex-data`"""
96

97
    __slots__ = ()
1✔
98

99
    @property
1✔
100
    @abstractmethod
1✔
101
    def data(self) -> T_ExceptionInfo:
1✔
102
        raise NotImplementedError()
103

104

105
K = TypeVar("K")
1✔
106
V = TypeVar("V")
1✔
107

108

109
class IMapEntry(Generic[K, V], ABC):
1✔
110
    """``IMapEntry`` values are produced :lpy:fn:`seq` ing over any
111
    :py:class:`IAssociative` (such as a Basilisp map).
112

113
    .. seealso::
114

115
       :lpy:fn:`key` , :lpy:fn:`val` , :lpy:fn:`map-entry?`"""
116

117
    __slots__ = ()
1✔
118

119
    @property
1✔
120
    @abstractmethod
1✔
121
    def key(self) -> K:
1✔
122
        raise NotImplementedError()
123

124
    @property
1✔
125
    @abstractmethod
1✔
126
    def value(self) -> V:
1✔
127
        raise NotImplementedError()
128

129

130
class IMeta(ABC):
1✔
131
    """``IMeta`` types can optionally include a map of metadata.
132

133
    Persistent data types metadata cannot be mutated, but many of these data types
134
    also implement :py:class:`IWithMeta` which allows creating a copy of the structure
135
    with new metadata.
136

137
    .. seealso::
138

139
       :lpy:fn:`meta`"""
140

141
    __slots__ = ()
1✔
142

143
    @property
1✔
144
    @abstractmethod
1✔
145
    def meta(self) -> Optional["IPersistentMap"]:
1✔
146
        raise NotImplementedError()
147

148

149
class IWithMeta(IMeta):
1✔
150
    """``IWithMeta`` are :py:class:`IMeta` types which can create copies of themselves
151
    with new metadata.
152

153
    .. seealso::
154

155
       :lpy:fn:`with-meta`"""
156

157
    __slots__ = ()
1✔
158

159
    @abstractmethod
1✔
160
    def with_meta(self, meta: "Optional[IPersistentMap]") -> Self:
1✔
161
        raise NotImplementedError()
162

163

164
class INamed(ABC):
1✔
165
    """``INamed`` instances are symbolic identifiers with a name and optional
166
    namespace.
167

168
    .. seealso::
169

170
       :lpy:fn:`name` , :lpy:fn:`namespace`"""
171

172
    __slots__ = ()
1✔
173

174
    @property
1✔
175
    @abstractmethod
1✔
176
    def name(self) -> str:
1✔
177
        raise NotImplementedError()
178

179
    @property
1✔
180
    @abstractmethod
1✔
181
    def ns(self) -> Optional[str]:
1✔
182
        raise NotImplementedError()
183

184
    @classmethod
1✔
185
    @abstractmethod
1✔
186
    def with_name(cls, name: str, ns: Optional[str] = None) -> Self:
1✔
187
        """Create a new instance of this INamed with `name` and optional `ns`."""
188
        raise NotImplementedError()
189

190

191
ILispObject = _LispObject
1✔
192

193

194
class IReference(IMeta):
1✔
195
    """``IReference`` types are mutable reference containers which allow mutation of
196
    the associated metadata.
197

198
    .. seealso::
199

200
       :lpy:fn:`alter-meta!` , :lpy:fn:`reset-meta!`"""
201

202
    __slots__ = ()
1✔
203

204
    @abstractmethod
1✔
205
    def alter_meta(
1✔
206
        self, f: Callable[..., Optional["IPersistentMap"]], *args
207
    ) -> Optional["IPersistentMap"]:
208
        raise NotImplementedError()
209

210
    @abstractmethod
1✔
211
    def reset_meta(
1✔
212
        self, meta: Optional["IPersistentMap"]
213
    ) -> Optional["IPersistentMap"]:
214
        raise NotImplementedError()
215

216

217
RefValidator = Callable[[T], bool]
1✔
218
RefWatchKey = Hashable
1✔
219
RefWatcher = Callable[[RefWatchKey, "IRef", T, T], None]
1✔
220

221

222
class IRef(IDeref[T]):
1✔
223
    """``IRef`` types are mutable reference containers which support validation of the
224
    contained value and watchers which are notified when the contained value changes.
225

226
    .. seealso::
227

228
       :lpy:fn:`add-watch` , :lpy:fn:`remove-watch` , :lpy:fn:`get-validator` ,
229
       :lpy:fn:`set-validator!`"""
230

231
    __slots__ = ()
1✔
232

233
    @abstractmethod
1✔
234
    def add_watch(self, k: RefWatchKey, wf: RefWatcher[T]) -> "IReference":
1✔
235
        raise NotImplementedError()
236

237
    @abstractmethod
1✔
238
    def remove_watch(self, k: RefWatchKey) -> "IReference":
1✔
239
        raise NotImplementedError()
240

241
    @abstractmethod
1✔
242
    def get_validator(self) -> Optional[RefValidator[T]]:
1✔
243
        raise NotImplementedError()
244

245
    @abstractmethod
1✔
246
    def set_validator(self, vf: Optional[RefValidator[T]] = None) -> None:
1✔
247
        raise NotImplementedError()
248

249

250
class IReversible(Generic[T]):
1✔
251
    """``IReversible`` types can produce a sequences of their elements in reverse in
252
    constant time.
253

254
    Of the builtin collections, only Vectors are ``IReversible``.
255

256
    .. seealso::
257

258
       :lpy:fn:`reversible?`"""
259

260
    __slots__ = ()
1✔
261

262
    @abstractmethod
1✔
263
    def rseq(self) -> "ISeq[T]":
1✔
264
        raise NotImplementedError()
265

266

267
class ISeqable(Iterable[T]):
1✔
268
    """``ISeqable`` types can produce sequences of their elements, but are not
269
    :py:class:`ISeq` .
270

271
    All the builtin collections are ``ISeqable``, except Lists which directly implement
272
    :py:class:`ISeq` .
273

274
    .. seealso::
275

276
       :ref:`seqs` , :lpy:fn:`seq` , :lpy:fn:`seqable?`"""
277

278
    __slots__ = ()
1✔
279

280
    @abstractmethod
1✔
281
    def seq(self) -> "Optional[ISeq[T]]":
1✔
282
        raise NotImplementedError()
283

284

285
class ISequential(ABC):
1✔
286
    """``ISequential`` is a marker interface for sequential types.
287

288
    Lists and Vectors are both considered ``ISequential``.
289

290
    .. seealso::
291

292
       :lpy:fn:`sequential?`"""
293

294
    __slots__ = ()
1✔
295

296

297
class ILookup(Generic[K, V], ABC):
1✔
298
    """``ILookup`` types allow accessing contained values by a key or index.
299

300
    .. seealso::
301

302
       :lpy:fn:`get`"""
303

304
    __slots__ = ()
1✔
305

306
    @abstractmethod
1✔
307
    def val_at(self, k: K, default: Optional[V] = None) -> Optional[V]:
1✔
308
        raise NotImplementedError()
309

310

311
class IPersistentCollection(ISeqable[T]):
1✔
312
    """``IPersistentCollection`` types support both fetching empty variants of an
313
    existing persistent collection and creating a new collection with additional
314
    members.
315

316
    .. seealso::
317

318
       :lpy:fn:`conj` , :lpy:fn:`empty` , :lpy:fn:`coll?`"""
319

320
    __slots__ = ()
1✔
321

322
    @abstractmethod
1✔
323
    def cons(self: Self, *elems: T) -> Self:
1✔
324
        raise NotImplementedError()
325

326
    @abstractmethod
1✔
327
    def empty(self) -> "IPersistentCollection[T]":
1✔
328
        raise NotImplementedError()
329

330

331
class IAssociative(ILookup[K, V], IPersistentCollection[IMapEntry[K, V]]):
1✔
332
    """``IAssociative`` types support a persistent data structure variant of
333
    associative operations.
334

335
    .. seealso::
336

337
       :lpy:fn:`assoc` , :lpy:fn:`contains?`, :lpy:fn:`find` , :lpy:fn:`associative?`
338
    """
339

340
    __slots__ = ()
1✔
341

342
    @abstractmethod
1✔
343
    def assoc(self: Self, *kvs) -> Self:
1✔
344
        raise NotImplementedError()
345

346
    @abstractmethod
1✔
347
    def contains(self, k: K) -> bool:
1✔
348
        raise NotImplementedError()
349

350
    @abstractmethod
1✔
351
    def entry(self, k: K) -> Optional[IMapEntry[K, V]]:
1✔
352
        raise NotImplementedError()
353

354

355
class IPersistentStack(IPersistentCollection[T]):
1✔
356
    """``IPersistentStack`` types support a persistent data structure variant of
357
    classical stack operations.
358

359
    .. seealso::
360

361
       :lpy:fn:`pop` , :lpy:fn:`peek`
362
    """
363

364
    __slots__ = ()
1✔
365

366
    @abstractmethod
1✔
367
    def peek(self) -> Optional[T]:
1✔
368
        raise NotImplementedError()
369

370
    @abstractmethod
1✔
371
    def pop(self: Self) -> Self:
1✔
372
        raise NotImplementedError()
373

374

375
class IProxy(ABC):
1✔
376
    """``IProxy`` is a marker interface for proxy types.
377

378
    All types created by ``proxy`` are automatically marked with ``IProxy``.
379

380
    .. seealso::
381

382
       :ref:`proxies`, :lpy:fn:`proxy`, :lpy:fn:`proxy-mappings`, :lpy:fn:`proxy-super`,
383
       :lpy:fn:`construct-proxy`, :lpy:fn:`init-proxy`, :lpy:fn:`update-proxy`,
384
       :lpy:fn:`get-proxy-class`"""
385

386
    __slots__ = ()
1✔
387

388
    _proxy_mappings: "IPersistentMap[str, Callable]"
1✔
389

390
    def _get_proxy_mappings(self) -> "IPersistentMap[str, Callable]":
1✔
391
        raise NotImplementedError()
392

393
    def _set_proxy_mappings(
1✔
394
        self, proxy_mappings: "IPersistentMap[str, Callable]"
395
    ) -> None:
396
        raise NotImplementedError()
397

398
    def _update_proxy_mappings(
1✔
399
        self, proxy_mappings: "IPersistentMap[str, Callable]"
400
    ) -> None:
401
        raise NotImplementedError()
402

403

404
T_key = TypeVar("T_key")
1✔
405
V_contra = TypeVar("V_contra", contravariant=True)
1✔
406

407

408
class ReduceFunction(Protocol[T, V_contra]):
1✔
409
    @overload
1✔
410
    def __call__(self) -> T: ...
1✔
411

412
    @overload
1✔
413
    def __call__(self, init: T, val: V_contra) -> T: ...
1✔
414

415
    def __call__(self, *args, **kwargs): ...
1✔
416

417

418
ReduceKVFunction = Callable[[T, T_key, V_contra], T]
1✔
419

420

421
class IReduce(ABC):
1✔
422
    """``IReduce`` types define custom implementations of ``reduce``.
423

424
    Only vectors are ``IReduce`` by default, providing faster iteration than relying on
425
    ``seq``.
426

427
    .. seealso::
428

429
       :lpy:fn:`reduce`
430
    """
431

432
    REDUCE_SENTINEL: Final = object()
1✔
433

434
    __slots__ = ()
1✔
435

436
    @overload
1✔
437
    def reduce(self, f: ReduceFunction[T, V_contra]) -> T: ...
1✔
438

439
    @overload
1✔
440
    def reduce(self, f: ReduceFunction[T, V_contra], init: T) -> T: ...
1✔
441

442
    @abstractmethod
1✔
443
    def reduce(self, f, init=REDUCE_SENTINEL):
1✔
444
        raise NotImplementedError()
445

446

447
class IReduceKV(ABC):
1✔
448
    """``IReduceKV`` types define custom implementations of ``reduce-kv``.
449

450
    Both vectors and maps are ``IReduceKV`` by default, providing faster iteration than
451
    relying on ``seq``. Maps iterate over the key-value pairs as expected, and vectors
452
    iterate over the index-item pairs of the vector.
453

454
    .. seealso::
455

456
       :lpy:fn:`reduce-kv`
457
    """
458

459
    __slots__ = ()
1✔
460

461
    @abstractmethod
1✔
462
    def reduce_kv(self: Self, f: ReduceKVFunction, init: T):
1✔
463
        raise NotImplementedError()
464

465

466
class IPersistentList(ISequential, IPersistentStack[T]):
1✔
467
    """``IPersistentList`` is a marker interface for a singly-linked list."""
468

469
    __slots__ = ()
1✔
470

471

472
class IPersistentMap(ICounted, Mapping[K, V], IAssociative[K, V]):
1✔
473
    """``IPersistentMap`` types support creating and modifying persistent maps.
474

475
    .. seealso::
476

477
       :lpy:fn:`conj` , :lpy:fn:`dissoc` , :lpy:fn:`map?`"""
478

479
    __slots__ = ()
1✔
480

481
    @abstractmethod
1✔
482
    def cons(
1✔
483
        self: Self, *elems: Union[IMapEntry[K, V], "IPersistentMap[K, V]", None]
484
    ) -> Self:
485
        raise NotImplementedError()
486

487
    @abstractmethod
1✔
488
    def dissoc(self: Self, *ks: K) -> Self:
1✔
489
        raise NotImplementedError()
490

491

492
class IPersistentSet(AbstractSet[T], ICounted, IPersistentCollection[T]):
1✔
493
    """``IPersistentSet`` types support creating and modifying persistent sets.
494

495
    .. seealso::
496

497
       :lpy:fn:`disj` , :lpy:fn:`set?`"""
498

499
    __slots__ = ()
1✔
500

501
    @abstractmethod
1✔
502
    def disj(self: Self, *elems: T) -> Self:
1✔
503
        raise NotImplementedError()
504

505

506
class IPersistentVector(
1✔
507
    Sequence[T],
508
    IAssociative[int, T],
509
    IIndexed,
510
    IReversible[T],
511
    ISequential,
512
    IPersistentStack[T],
513
):
514
    """``IPersistentVector`` types support creating and modifying persistent vectors.
515

516
    .. seealso::
517

518
       :lpy:fn:`vector?`"""
519

520
    __slots__ = ()
1✔
521

522
    @abstractmethod
1✔
523
    def assoc(self: Self, *kvs) -> Self:
1✔
524
        raise NotImplementedError()
525

526
    @abstractmethod
1✔
527
    def cons(self: Self, *elems: T) -> Self:  # type: ignore[override]
1✔
528
        raise NotImplementedError()
529

530
    @abstractmethod
1✔
531
    def seq(self) -> "Optional[ISeq[T]]":  # type: ignore[override]
1✔
532
        raise NotImplementedError()
533

534

535
T_tcoll_co = TypeVar("T_tcoll_co", bound="ITransientCollection", covariant=True)
1✔
536

537

538
# Including ABC as a base seems to cause catastrophic meltdown.
539
class IEvolveableCollection(Generic[T_tcoll_co]):
1✔
540
    """``IEvolveableCollection`` types support creating transient variants of persistent
541
    data structures which can be modified efficiently and then returned back into
542
    persistent data structures once modification is complete.
543

544
    .. seealso::
545

546
       :lpy:fn:`transient`"""
547

548
    @abstractmethod
1✔
549
    def to_transient(self) -> T_tcoll_co:
1✔
550
        raise NotImplementedError()
551

552

553
class ITransientCollection(Generic[T]):
1✔
554
    """``ITransientCollection`` types support efficient modification of otherwise
555
    persistent data structures.
556

557
    .. seealso::
558

559
       :lpy:fn:`conj!` , :lpy:fn:`persistent!`"""
560

561
    __slots__ = ()
1✔
562

563
    @abstractmethod
1✔
564
    def cons_transient(self: T_tcoll_co, *elems: T) -> "T_tcoll_co":
1✔
565
        raise NotImplementedError()
566

567
    @abstractmethod
1✔
568
    def to_persistent(self: T_tcoll_co) -> "IPersistentCollection[T]":
1✔
569
        raise NotImplementedError()
570

571

572
class ITransientAssociative(ILookup[K, V], ITransientCollection[IMapEntry[K, V]]):
1✔
573
    """``ITransientAssociative`` types are the transient counterpart of
574
    :py:class:`IAssociative` types.
575

576
    .. seealso::
577

578
       :lpy:fn:`assoc!` , :lpy:fn:`contains?`, :lpy:fn:`find`"""
579

580
    __slots__ = ()
1✔
581

582
    @abstractmethod
1✔
583
    def assoc_transient(self, *kvs) -> Self:
1✔
584
        raise NotImplementedError()
585

586
    @abstractmethod
1✔
587
    def contains_transient(self, k: K) -> bool:
1✔
588
        raise NotImplementedError()
589

590
    @abstractmethod
1✔
591
    def entry_transient(self, k: K) -> Optional[IMapEntry[K, V]]:
1✔
592
        raise NotImplementedError()
593

594

595
class ITransientMap(ICounted, ITransientAssociative[K, V]):
1✔
596
    """``ITransientMap`` types are the transient counterpart of
597
    :py:class:`IPersistentMap` types.
598

599
    .. seealso::
600

601
       :lpy:fn:`dissoc!`"""
602

603
    __slots__ = ()
1✔
604

605
    @abstractmethod
1✔
606
    def cons_transient(
1✔
607
        self, *elems: Union[IMapEntry[K, V], "IPersistentMap[K, V]", None]
608
    ) -> Self:
609
        raise NotImplementedError()
610

611
    @abstractmethod
1✔
612
    def dissoc_transient(self, *ks: K) -> Self:
1✔
613
        raise NotImplementedError()
614

615

616
class ITransientSet(ICounted, ITransientCollection[T]):
1✔
617
    """``ITransientSet`` types are the transient counterpart of
618
    :py:class:`IPersistentSet` types.
619

620
    .. seealso::
621

622
       :lpy:fn:`disj!`"""
623

624
    __slots__ = ()
1✔
625

626
    @abstractmethod
1✔
627
    def disj_transient(self, *elems: T) -> Self:
1✔
628
        raise NotImplementedError()
629

630

631
T_tvec = TypeVar("T_tvec", bound="ITransientVector")
1✔
632

633

634
class ITransientVector(
1✔
635
    ITransientAssociative[int, T],
636
    IIndexed,
637
):
638
    """``ITransientVector`` types are the transient counterpart of
639
    :py:class:`IPersistentVector` types."""
640

641
    __slots__ = ()
1✔
642

643
    @abstractmethod
1✔
644
    def assoc_transient(self: T_tvec, *kvs) -> T_tvec:
1✔
645
        raise NotImplementedError()
646

647
    @abstractmethod
1✔
648
    def cons_transient(self: T_tvec, *elems: T) -> T_tvec:  # type: ignore[override]
1✔
649
        raise NotImplementedError()
650

651
    @abstractmethod
1✔
652
    def pop_transient(self: T_tvec) -> T_tvec:
1✔
653
        raise NotImplementedError()
654

655

656
class IRecord(ILispObject):
1✔
657
    """``IRecord`` is a marker interface for types :lpy:form:`def` 'ed by
658
    :lpy:fn:`defrecord` forms.
659

660
    All types created by ``defrecord`` are automatically marked with ``IRecord``.
661

662
    .. seealso::
663

664
       :ref:`data_types_and_records` , :lpy:fn:`defrecord` , :lpy:fn:`record?`
665
    """
666

667
    __slots__ = ()
1✔
668

669
    @classmethod
1✔
670
    @abstractmethod
1✔
671
    def create(cls, m: IPersistentMap) -> "IRecord":
1✔
672
        """Class method constructor from an :py:class:`IPersistentMap` instance."""
673
        raise NotImplementedError()
674

675
    def _lrepr(self, **kwargs: Unpack[PrintSettings]) -> str:
1✔
676
        return self._record_lrepr(kwargs)
1✔
677

678
    @abstractmethod
1✔
679
    def _record_lrepr(self, kwargs: PrintSettings) -> str:
1✔
680
        """Translation method converting Python keyword arguments into a
681
        Python dict.
682

683
        Basilisp methods and functions cannot formally accept Python keyword
684
        arguments, so this method is called by `_lrepr` with the keyword
685
        arguments cast to a Python dict."""
686
        raise NotImplementedError()
687

688

689
def seq_equals(s1: Union["ISeq", ISequential], s2: Any) -> bool:
1✔
690
    """Return True if two sequences contain exactly the same elements in the same
691
    order. Return False if one sequence is shorter than the other."""
692
    assert isinstance(s1, (ISeq, ISequential))
1✔
693

694
    if not isinstance(s2, (ISeq, ISequential)):
1✔
695
        return NotImplemented
1✔
696

697
    sentinel = object()
1✔
698
    for e1, e2 in itertools.zip_longest(s1, s2, fillvalue=sentinel):  # type: ignore[arg-type]
1✔
699
        if bool(e1 is sentinel) or bool(e2 is sentinel):
1✔
700
            return False
1✔
701
        if e1 != e2:
1✔
702
            return False
1✔
703
    return True
1✔
704

705

706
class ISeq(ILispObject, IPersistentCollection[T]):
1✔
707
    """``ISeq`` types represent a potentially infinite sequence of elements.
708

709
    .. seealso::
710

711
       :ref:`seqs` , :lpy:fn:`lazy-seq` , :lpy:fn:`seq` , :lpy:fn:`first` ,
712
       :lpy:fn:`rest` , :lpy:fn:`next` , :lpy:fn:`second` , :lpy:fn:`seq?` ,
713
       :lpy:fn:`nfirst` , :lpy:fn:`fnext` , :lpy:fn:`nnext` , :lpy:fn:`empty?` ,
714
       :lpy:fn:`seq?`
715
    """
716

717
    __slots__ = ()
1✔
718

719
    class _SeqIter(Iterator[T]):
1✔
720
        """Stateful iterator for sequence types.
721

722
        This is primarily useful for avoiding blowing the stack on a long (or infinite)
723
        sequence. It is not safe to use `yield` statements to iterate over sequences,
724
        since they accrete one Python stack frame per sequence element."""
725

726
        __slots__ = ("_cur",)
1✔
727

728
        def __init__(self, seq: "ISeq[T]"):
1✔
729
            self._cur = seq
1✔
730

731
        def __next__(self):
1✔
732
            if not self._cur:
1✔
UNCOV
733
                raise StopIteration
×
734
            v = self._cur.first
1✔
735
            if self._cur.is_empty:
1✔
736
                raise StopIteration
1✔
737
            self._cur = self._cur.rest
1✔
738
            return v
1✔
739

740
        def __repr__(self):  # pragma: no cover
741
            return repr(self._cur)
742

743
    @property
1✔
744
    @abstractmethod
1✔
745
    def is_empty(self) -> bool:
1✔
746
        raise NotImplementedError()
747

748
    @property
1✔
749
    @abstractmethod
1✔
750
    def first(self) -> Optional[T]:
1✔
751
        raise NotImplementedError()
752

753
    @property
1✔
754
    @abstractmethod
1✔
755
    def rest(self) -> "ISeq[T]":
1✔
756
        raise NotImplementedError()
757

758
    @abstractmethod
1✔
759
    def cons(self, *elem: T) -> "ISeq[T]":
1✔
760
        raise NotImplementedError()
761

762
    def seq(self) -> "Optional[ISeq[T]]":
1✔
763
        return self
1✔
764

765
    def _lrepr(self, **kwargs: Unpack[PrintSettings]):
1✔
766
        return seq_lrepr(iter(self), "(", ")", **kwargs)
1✔
767

768
    def __eq__(self, other):
1✔
769
        if self is other:
1✔
770
            return True
1✔
771
        return seq_equals(self, other)
1✔
772

773
    def __hash__(self):
1✔
774
        return hash(tuple(self))
1✔
775

776
    def __iter__(self):
1✔
777
        return self._SeqIter(self)
1✔
778

779

780
class IType(ABC):
1✔
781
    """``IType`` is a marker interface for types :lpy:form:`def` 'ed by
782
    :lpy:fn:`deftype` forms.
783

784
    All types created by ``deftype`` are automatically marked with ``IType``.
785

786
    .. seealso::
787

788
       :ref:`data_types_and_records`"""
789

790
    __slots__ = ()
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