Skip to content

Commit 2225322

Browse files
committed
-
1 parent 2d0d5d9 commit 2225322

File tree

20 files changed

+143
-124
lines changed

20 files changed

+143
-124
lines changed

source_py2/python_toolbox/__init__.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
import python_toolbox.version_info
1616
import python_toolbox.monkeypatch_copy_reg
1717
import python_toolbox.monkeypatch_envelopes
18-
import python_toolbox.monkeypatch_pathlib
1918

2019
__version_info__ = python_toolbox.version_info.VersionInfo(0, 6, 10)
2120
__version__ = __version_info__.version_text

source_py2/python_toolbox/misc_tools/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
is_magic_variable_name, get_actual_type, is_number, identity_function,
1010
do_nothing, OwnNameDiscoveringDescriptor, find_clear_place_on_circle,
1111
general_sum, general_product, is_legal_email_address, is_type, NonInstatiable,
12-
repeat_getattr, add_extension_if_plain, set_attributes, pocket
12+
repeat_getattr, add_extension_if_plain, set_attributes, pocket,
13+
decimal_number_from_string
1314
)
1415
from . import name_mangling
1516
from .proxy_property import ProxyProperty

source_py2/python_toolbox/misc_tools/misc_tools.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -344,4 +344,22 @@ def pocket(*args):
344344
(pocket.container.value,) = args
345345
else:
346346
return pocket.container.value
347-
347+
348+
_decimal_number_pattern = \
349+
re.compile('''^-?(?:(?:[0-9]+(?:.[0-9]*)?)|(?:.[0-9]+))$''')
350+
def decimal_number_from_string(string):
351+
'''
352+
Turn a string like '7' or '-32.55' into the corresponding number.
353+
354+
Ensures that it was given a number. (This might be more secure than using
355+
something like `int` directly.)
356+
357+
Uses `int` for ints and `float` for floats.
358+
'''
359+
if isinstance(string, bytes):
360+
string = string.decode()
361+
if not isinstance(string, str):
362+
raise Exception("%s isn't a decimal number." % string)
363+
if not _decimal_number_pattern.match(string):
364+
raise Exception("%s isn't a decimal number." % string)
365+
return float(string) if '.' in string else int(string)

source_py2/python_toolbox/monkeypatch_pathlib.py

Lines changed: 0 additions & 56 deletions
This file was deleted.

source_py2/python_toolbox/nifty_collections/emitting_ordered_set.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,10 @@ def add(self, key):
2727
""" Add an element to a set.
2828
2929
This has no effect if the element is already present. """
30-
if key not in self.map:
31-
end = self.end
30+
if key not in self._map:
31+
end = self._end
3232
curr = end[PREV]
33-
curr[NEXT] = end[PREV] = self.map[key] = [key, curr, end]
33+
curr[NEXT] = end[PREV] = self._map[key] = [key, curr, end]
3434
if self.emitter:
3535
self.emitter.emit()
3636

@@ -39,8 +39,8 @@ def discard(self, key):
3939
""" Remove an element from a set if it is a member.
4040
4141
If the element is not a member, do nothing. """
42-
if key in self.map:
43-
key, prev, next = self.map.pop(key)
42+
if key in self._map:
43+
key, prev, next = self._map.pop(key)
4444
prev[NEXT] = next
4545
next[PREV] = prev
4646
if self.emitter:

source_py2/python_toolbox/nifty_collections/lazy_tuple.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,9 @@ def my_generator():
7575
Some actions require exhausting the entire iterator. For example, checking
7676
the `LazyTuple` length, or doing indexex access with a negative index.
7777
(e.g. asking for the seventh-to-last element.)
78+
79+
If you're passing in an iterator you definitely know to be infinite,
80+
specify `definitely_infinite=False`.
7881
'''
7982

8083
def __init__(self, iterable, definitely_infinite=False):
@@ -91,6 +94,12 @@ def __init__(self, iterable, definitely_infinite=False):
9194
'''The internal iterator from which we get data.'''
9295

9396
self.definitely_infinite = definitely_infinite
97+
'''
98+
The iterator is definitely infinite.
99+
100+
The iterator might still be infinite if this is `False`, but if it's
101+
`True` then it's definitely infinite.
102+
'''
94103

95104
self.lock = threading.Lock()
96105
'''Lock used while exhausting to make `LazyTuple` thread-safe.'''

source_py2/python_toolbox/nifty_collections/ordered_dict.py

Lines changed: 3 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -14,31 +14,7 @@
1414

1515
class OrderedDict(StdlibOrderedDict):
1616

17-
def move_to_end(self, key, last=True):
18-
'''Move an existing element to the end (or beginning if last==False).
19-
20-
Raises KeyError if the element does not exist.
21-
When last=True, acts like a fast version of self[key]=self.pop(key).
22-
23-
'''
24-
link = self.__map[key]
25-
link_prev = link[0]
26-
link_next = link[1]
27-
link_prev[1] = link_next
28-
link_next[0] = link_prev
29-
if last:
30-
last = self.__root[0]
31-
link[0] = last
32-
link[1] = self.__root
33-
last[1] = self.__root[0] = link
34-
else:
35-
first = self.__root[1]
36-
link[0] = self.__root
37-
link[1] = first
38-
root[1] = first[0] = link
39-
40-
41-
def sort(self, key=None, reversed=False):
17+
def sort(self, key=None, reverse=False):
4218
'''
4319
Sort the items according to their keys, changing the order in-place.
4420
@@ -47,9 +23,8 @@ def sort(self, key=None, reversed=False):
4723
'''
4824
key_function = \
4925
comparison_tools.process_key_function_or_attribute_name(key)
50-
sorted_keys = sorted(self.keys(), key=key_function)
51-
step = -1 if reversed else 1
52-
for key_ in sorted_keys[1::step]:
26+
sorted_keys = sorted(self.keys(), key=key_function, reverse=reverse)
27+
for key_ in sorted_keys[1:]:
5328
self.move_to_end(key_)
5429

5530

source_py2/python_toolbox/nifty_collections/ordered_set.py

Lines changed: 59 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,13 @@
1010

1111
import collections
1212

13+
from python_toolbox import comparison_tools
14+
15+
1316
KEY, PREV, NEXT = range(3)
1417

1518

16-
class OrderedSet(collections.MutableSet):
19+
class OrderedSet(collections.MutableSet, collections.Sequence):
1720
'''
1821
A set with an order.
1922
@@ -22,49 +25,62 @@ class OrderedSet(collections.MutableSet):
2225
'''
2326

2427
def __init__(self, iterable=None):
25-
self.end = end = []
26-
end += [None, end, end] # sentinel node for doubly linked list
27-
self.map = {} # key --> [key, prev, next]
28+
self.clear()
2829
if iterable is not None:
2930
self |= iterable
3031

32+
33+
def clear(self):
34+
self._end = []
35+
self._end += [None, self._end, self._end]
36+
self._map = {}
37+
38+
39+
def __getitem__(self, index):
40+
for i, item in enumerate(self):
41+
if i == index:
42+
return item
43+
else:
44+
raise IndexError
45+
46+
3147
def __len__(self):
32-
return len(self.map)
48+
return len(self._map)
3349

3450
def __contains__(self, key):
35-
return key in self.map
51+
return key in self._map
3652

3753
def add(self, key):
3854
"""
3955
Add an element to a set.
4056
4157
This has no effect if the element is already present.
4258
"""
43-
if key not in self.map:
44-
end = self.end
59+
if key not in self._map:
60+
end = self._end
4561
curr = end[PREV]
46-
curr[NEXT] = end[PREV] = self.map[key] = [key, curr, end]
62+
curr[NEXT] = end[PREV] = self._map[key] = [key, curr, end]
4763

4864
def discard(self, key):
4965
"""
5066
Remove an element from a set if it is a member.
5167
5268
If the element is not a member, do nothing.
5369
"""
54-
if key in self.map:
55-
key, prev, next = self.map.pop(key)
70+
if key in self._map:
71+
key, prev, next = self._map.pop(key)
5672
prev[NEXT] = next
5773
next[PREV] = prev
5874

5975
def __iter__(self):
60-
end = self.end
76+
end = self._end
6177
curr = end[NEXT]
6278
while curr is not end:
6379
yield curr[KEY]
6480
curr = curr[NEXT]
6581

6682
def __reversed__(self):
67-
end = self.end
83+
end = self._end
6884
curr = end[PREV]
6985
while curr is not end:
7086
yield curr[KEY]
@@ -92,3 +108,33 @@ def __del__(self):
92108
self.clear() # remove circular references
93109
# todo: is this really needed? i'm worried about this making the gc not
94110
# drop circulary-referencing objects.
111+
112+
def move_to_end(self, key):
113+
'''Move an existing element to the end (or beginning if last==False).
114+
115+
Raises KeyError if the element does not exist.
116+
When last=True, acts like a fast version of self[key]=self.pop(key).
117+
118+
'''
119+
# Inefficient implementation until someone cares.
120+
if key in self:
121+
self.remove(key)
122+
self.add(key)
123+
124+
125+
def sort(self, key=None, reverse=False):
126+
'''
127+
Sort the items according to their keys, changing the order in-place.
128+
129+
The optional `key` argument will be passed to the `sorted` function as
130+
a key function.
131+
'''
132+
# Inefficient implementation until someone cares.
133+
key_function = \
134+
comparison_tools.process_key_function_or_attribute_name(key)
135+
sorted_members = sorted(tuple(self), key=key_function, reverse=reverse)
136+
137+
self.clear()
138+
self |= sorted_members
139+
140+

source_py2/python_toolbox/sequence_tools.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,12 @@ def flatten(iterable):
3030
3131
For example, `flatten([[1, 2], [3], [4, 'meow']]) == [1, 2, 3, 4, 'meow']`.
3232
'''
33-
33+
# If that ain't a damn clever implementation, I don't know what is.
3434
iterator = iter(iterable)
3535
try:
36-
first_item = next(iterator)
36+
return sum(iterator, next(iterator))
3737
except StopIteration:
3838
return []
39-
return sum(iterator, first_item)
4039

4140

4241
def combinations(sequence, n=None, start=0):
@@ -244,11 +243,15 @@ def to_tuple(single_or_sequence, item_type=None, item_test=None):
244243
if actual_item_test is None:
245244
if isinstance(single_or_sequence, collections.Sequence):
246245
return tuple(single_or_sequence)
246+
elif single_or_sequence is None:
247+
return tuple()
247248
else:
248249
return (single_or_sequence,)
249250
else: # actual_item_test is not None
250251
if actual_item_test(single_or_sequence):
251252
return (single_or_sequence,)
253+
elif single_or_sequence is None:
254+
return ()
252255
else:
253256
return tuple(single_or_sequence)
254257

source_py2/test_python_toolbox/test_misc_tools/test_add_extension_if_plain.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
# Copyright 2009-2014 Ram Rachum.
22
# This program is distributed under the MIT license.
33

4-
'''Testing module for `find_clear_place_on_circle`.'''
5-
64
import pathlib
75

86
import nose.tools

0 commit comments

Comments
 (0)