put-back-iterator 0.1.0a0__py2.py3-none-any.whl → 0.1.0a1__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {put_back_iterator-0.1.0a0.dist-info → put_back_iterator-0.1.0a1.dist-info}/METADATA +7 -4
- put_back_iterator-0.1.0a1.dist-info/RECORD +6 -0
- put_back_iterator.py +98 -15
- put_back_iterator-0.1.0a0.dist-info/RECORD +0 -6
- {put_back_iterator-0.1.0a0.dist-info → put_back_iterator-0.1.0a1.dist-info}/WHEEL +0 -0
- {put_back_iterator-0.1.0a0.dist-info → put_back_iterator-0.1.0a1.dist-info}/licenses/LICENSE +0 -0
- {put_back_iterator-0.1.0a0.dist-info → put_back_iterator-0.1.0a1.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: put-back-iterator
|
3
|
-
Version: 0.1.
|
3
|
+
Version: 0.1.0a1
|
4
4
|
Summary: A drop-in replacement for `iter(iterable)` that allows **putting items back** after consuming them. Ideal for parsing, lexing, and other scenarios requiring lookahead or backtracking.
|
5
5
|
Author-email: Jifeng Wu <jifengwu2k@gmail.com>
|
6
6
|
License-Expression: MIT
|
@@ -12,6 +12,7 @@ Classifier: Operating System :: OS Independent
|
|
12
12
|
Requires-Python: >=2
|
13
13
|
Description-Content-Type: text/markdown
|
14
14
|
License-File: LICENSE
|
15
|
+
Requires-Dist: typing; python_version < "3.5"
|
15
16
|
Dynamic: license-file
|
16
17
|
|
17
18
|
# `put-back-iterator`
|
@@ -35,6 +36,8 @@ This package solves it with:
|
|
35
36
|
## Quick Start
|
36
37
|
|
37
38
|
```python
|
39
|
+
# coding=utf-8
|
40
|
+
from __future__ import print_function
|
38
41
|
from put_back_iterator import PutBackIterator
|
39
42
|
|
40
43
|
# Wrap any iterable
|
@@ -57,7 +60,7 @@ print(list(it)) # [1, 2, 3]
|
|
57
60
|
|
58
61
|
### 1. **Parsing/Tokenizing**
|
59
62
|
|
60
|
-
```
|
63
|
+
```
|
61
64
|
tokens = PutBackIterator(tokenize(source_code))
|
62
65
|
while tokens.has_next():
|
63
66
|
token = next(tokens)
|
@@ -70,7 +73,7 @@ while tokens.has_next():
|
|
70
73
|
|
71
74
|
### 2. **Backtracking Algorithms**
|
72
75
|
|
73
|
-
```
|
76
|
+
```
|
74
77
|
def backtrack(it):
|
75
78
|
item = next(it)
|
76
79
|
if not is_valid(item):
|
@@ -80,7 +83,7 @@ def backtrack(it):
|
|
80
83
|
|
81
84
|
### 3. **Stream Processing**
|
82
85
|
|
83
|
-
```
|
86
|
+
```
|
84
87
|
for chunk in PutBackIterator(stream):
|
85
88
|
if needs_retry(chunk):
|
86
89
|
chunk = modify(chunk)
|
@@ -0,0 +1,6 @@
|
|
1
|
+
put_back_iterator.py,sha256=YaWSHy7WdrMHkfKudP6sCyBN8KwwfxwzIIqrt2x3Pfo,4336
|
2
|
+
put_back_iterator-0.1.0a1.dist-info/licenses/LICENSE,sha256=FZ9XWedK_wQ4wfqVanrQVQpArRHDkxwxic2rgii1pZg,1066
|
3
|
+
put_back_iterator-0.1.0a1.dist-info/METADATA,sha256=oEMOGzBHbBlJJY5WTmoIHnWaEqso180qX1jKQZmXxYM,3089
|
4
|
+
put_back_iterator-0.1.0a1.dist-info/WHEEL,sha256=JNWh1Fm1UdwIQV075glCn4MVuCRs0sotJIq-J6rbxCU,109
|
5
|
+
put_back_iterator-0.1.0a1.dist-info/top_level.txt,sha256=8XJh5rF6eOPUkwrmXZutOmEHGnbXK6VqPPp6mrvkrs4,18
|
6
|
+
put_back_iterator-0.1.0a1.dist-info/RECORD,,
|
put_back_iterator.py
CHANGED
@@ -1,25 +1,87 @@
|
|
1
|
-
|
1
|
+
# coding=utf-8
|
2
|
+
# Copyright (c) 2025 Jifeng Wu
|
3
|
+
# Licensed under the MIT License. See LICENSE file in the project root for full license information.
|
2
4
|
import sys
|
5
|
+
from typing import Iterable, Iterator, List, TypeVar
|
3
6
|
|
7
|
+
DEFAULT_PLACEHOLDER = object()
|
8
|
+
T = TypeVar('T')
|
4
9
|
|
5
|
-
_DEFAULT_PLACEHOLDER = object()
|
6
10
|
|
7
|
-
class PutBackIterator:
|
11
|
+
class PutBackIterator(Iterator[T]):
|
12
|
+
"""A drop-in replacement for built-in iterators that supports putting items back.
|
13
|
+
|
14
|
+
This iterator wraps any iterable and provides additional functionality to
|
15
|
+
push consumed items back into the iterator for later consumption. Ideal for
|
16
|
+
parsing, lexing, and other scenarios requiring lookahead or backtracking.
|
17
|
+
|
18
|
+
Args:
|
19
|
+
iterable: Any iterable object (list, string, generator, etc.) to wrap.
|
20
|
+
|
21
|
+
Example:
|
22
|
+
>>> it = PutBackIterator([1, 2, 3])
|
23
|
+
>>> next(it)
|
24
|
+
1
|
25
|
+
>>> it.put_back(1)
|
26
|
+
>>> list(it)
|
27
|
+
[1, 2, 3]
|
28
|
+
|
29
|
+
Attributes:
|
30
|
+
iterator (Iterator[T]): The underlying iterator
|
31
|
+
put_back_stack (List[T]): Stack for items that have been put back
|
32
|
+
"""
|
33
|
+
__slots__ = (
|
34
|
+
'iterator',
|
35
|
+
'put_back_stack'
|
36
|
+
)
|
37
|
+
|
8
38
|
def __init__(self, iterable):
|
9
|
-
|
10
|
-
|
39
|
+
# type: (Iterable[T]) -> None
|
40
|
+
"""Initialize the PutBackIterator with an iterable.
|
41
|
+
|
42
|
+
Args:
|
43
|
+
iterable: Any object that can be iterated over
|
44
|
+
"""
|
45
|
+
self.iterator = iter(iterable) # type: Iterator[T]
|
46
|
+
self.put_back_stack = [] # type: List[T]
|
11
47
|
|
12
48
|
def __iter__(self):
|
49
|
+
# type: () -> PutBackIterator[T]
|
50
|
+
"""
|
51
|
+
Return the iterator object itself.
|
52
|
+
|
53
|
+
Returns:
|
54
|
+
PutBackIterator[T]: The current iterator instance.
|
55
|
+
|
56
|
+
This makes PutBackIterator compatible with the iterator protocol,
|
57
|
+
so it can be used directly in for-loops and other iterable contexts.
|
58
|
+
"""
|
13
59
|
return self
|
14
60
|
|
15
|
-
def
|
16
|
-
|
17
|
-
|
61
|
+
def next_implementation(self, default=DEFAULT_PLACEHOLDER):
|
62
|
+
"""
|
63
|
+
Return the next item from the iterator, considering any put-back items.
|
64
|
+
|
65
|
+
Args:
|
66
|
+
default: Optional; a value to return if the iterator is exhausted.
|
67
|
+
If not provided and no items remain, raises StopIteration.
|
68
|
+
|
69
|
+
Returns:
|
70
|
+
T: The next item from the put-back stack (if not empty), or the underlying iterator.
|
71
|
+
|
72
|
+
Raises:
|
73
|
+
StopIteration: If there are no more items and no default is provided.
|
74
|
+
|
75
|
+
Notes:
|
76
|
+
This method underlies both the Python 2 and 3 iterator protocol methods.
|
77
|
+
"""
|
78
|
+
if self.put_back_stack:
|
79
|
+
return self.put_back_stack.pop()
|
18
80
|
else:
|
19
81
|
end_sentinel = object()
|
20
|
-
element_or_sentinel = next(self.
|
82
|
+
element_or_sentinel = next(self.iterator, end_sentinel)
|
21
83
|
if element_or_sentinel is end_sentinel:
|
22
|
-
if default is
|
84
|
+
if default is DEFAULT_PLACEHOLDER:
|
23
85
|
raise StopIteration
|
24
86
|
else:
|
25
87
|
return default
|
@@ -27,15 +89,36 @@ class PutBackIterator:
|
|
27
89
|
return element_or_sentinel
|
28
90
|
|
29
91
|
if sys.version_info < (3,):
|
30
|
-
next =
|
92
|
+
next = next_implementation
|
31
93
|
else:
|
32
|
-
__next__ =
|
94
|
+
__next__ = next_implementation
|
33
95
|
|
34
96
|
def put_back(self, element):
|
35
|
-
|
97
|
+
# type: (T) -> None
|
98
|
+
"""
|
99
|
+
Put an item back into the iterator to be returned on the next call to `next()`.
|
100
|
+
|
101
|
+
Args:
|
102
|
+
element (T): The item to put back onto the iterator.
|
103
|
+
|
104
|
+
Notes:
|
105
|
+
Items are put back in a last-in, first-out (LIFO) order. Calling `put_back()` multiple times will return those items in reverse order of addition.
|
106
|
+
"""
|
107
|
+
self.put_back_stack.append(element)
|
36
108
|
|
37
109
|
def has_next(self):
|
38
|
-
|
110
|
+
# type: () -> bool
|
111
|
+
"""
|
112
|
+
Check whether the iterator has at least one more item to yield, without consuming it.
|
113
|
+
|
114
|
+
Returns:
|
115
|
+
bool: True if there is another item available, False otherwise.
|
116
|
+
|
117
|
+
Notes:
|
118
|
+
If there is no item in the put-back stack, this method advances
|
119
|
+
the underlying iterator once for lookahead, puts the value back if found, and then returns the result.
|
120
|
+
"""
|
121
|
+
if self.put_back_stack:
|
39
122
|
return True
|
40
123
|
else:
|
41
124
|
end_sentinel = object()
|
@@ -43,5 +126,5 @@ class PutBackIterator:
|
|
43
126
|
if element_or_sentinel is end_sentinel:
|
44
127
|
return False
|
45
128
|
else:
|
46
|
-
self.
|
129
|
+
self.put_back_stack.append(element_or_sentinel)
|
47
130
|
return True
|
@@ -1,6 +0,0 @@
|
|
1
|
-
put_back_iterator.py,sha256=2ME12t-aK1xpCMwAae0yVTrFYIWQPBdNC3emHUpt7JI,1365
|
2
|
-
put_back_iterator-0.1.0a0.dist-info/licenses/LICENSE,sha256=FZ9XWedK_wQ4wfqVanrQVQpArRHDkxwxic2rgii1pZg,1066
|
3
|
-
put_back_iterator-0.1.0a0.dist-info/METADATA,sha256=GGca8R3UzTev5VB4uBbewobeaql8BeVC6SXrYVxXhLc,3008
|
4
|
-
put_back_iterator-0.1.0a0.dist-info/WHEEL,sha256=JNWh1Fm1UdwIQV075glCn4MVuCRs0sotJIq-J6rbxCU,109
|
5
|
-
put_back_iterator-0.1.0a0.dist-info/top_level.txt,sha256=8XJh5rF6eOPUkwrmXZutOmEHGnbXK6VqPPp6mrvkrs4,18
|
6
|
-
put_back_iterator-0.1.0a0.dist-info/RECORD,,
|
File without changes
|
{put_back_iterator-0.1.0a0.dist-info → put_back_iterator-0.1.0a1.dist-info}/licenses/LICENSE
RENAMED
File without changes
|
File without changes
|