Skip to content
This repository was archived by the owner on Mar 23, 2023. It is now read-only.

Commit 9beb7e8

Browse files
S-YOUtrotterdylan
authored andcommitted
Add UserList, UserString to stdlib (#184)
1 parent a821eae commit 9beb7e8

5 files changed

Lines changed: 325 additions & 3 deletions

File tree

third_party/stdlib/UserList.py

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
"""A more or less complete user-defined wrapper around list objects."""
2+
3+
import collections
4+
5+
class UserList(collections.MutableSequence):
6+
def __init__(self, initlist=None):
7+
self.data = []
8+
if initlist is not None:
9+
# XXX should this accept an arbitrary sequence?
10+
if type(initlist) == type(self.data):
11+
self.data[:] = initlist
12+
elif isinstance(initlist, UserList):
13+
self.data[:] = initlist.data[:]
14+
else:
15+
self.data = list(initlist)
16+
def __repr__(self): return repr(self.data)
17+
def __lt__(self, other): return self.data < self.__cast(other)
18+
def __le__(self, other): return self.data <= self.__cast(other)
19+
def __eq__(self, other): return self.data == self.__cast(other)
20+
def __ne__(self, other): return self.data != self.__cast(other)
21+
def __gt__(self, other): return self.data > self.__cast(other)
22+
def __ge__(self, other): return self.data >= self.__cast(other)
23+
def __cast(self, other):
24+
if isinstance(other, UserList): return other.data
25+
else: return other
26+
def __cmp__(self, other):
27+
return cmp(self.data, self.__cast(other))
28+
__hash__ = None # Mutable sequence, so not hashable
29+
def __contains__(self, item): return item in self.data
30+
def __len__(self): return len(self.data)
31+
def __getitem__(self, i): return self.data[i]
32+
def __setitem__(self, i, item): self.data[i] = item
33+
def __delitem__(self, i): del self.data[i]
34+
def __getslice__(self, i, j):
35+
i = max(i, 0); j = max(j, 0)
36+
return self.__class__(self.data[i:j])
37+
def __setslice__(self, i, j, other):
38+
i = max(i, 0); j = max(j, 0)
39+
if isinstance(other, UserList):
40+
self.data[i:j] = other.data
41+
elif isinstance(other, type(self.data)):
42+
self.data[i:j] = other
43+
else:
44+
self.data[i:j] = list(other)
45+
def __delslice__(self, i, j):
46+
i = max(i, 0); j = max(j, 0)
47+
del self.data[i:j]
48+
def __add__(self, other):
49+
if isinstance(other, UserList):
50+
return self.__class__(self.data + other.data)
51+
elif isinstance(other, type(self.data)):
52+
return self.__class__(self.data + other)
53+
else:
54+
return self.__class__(self.data + list(other))
55+
def __radd__(self, other):
56+
if isinstance(other, UserList):
57+
return self.__class__(other.data + self.data)
58+
elif isinstance(other, type(self.data)):
59+
return self.__class__(other + self.data)
60+
else:
61+
return self.__class__(list(other) + self.data)
62+
def __iadd__(self, other):
63+
if isinstance(other, UserList):
64+
self.data += other.data
65+
elif isinstance(other, type(self.data)):
66+
self.data += other
67+
else:
68+
self.data += list(other)
69+
return self
70+
def __mul__(self, n):
71+
return self.__class__(self.data*n)
72+
__rmul__ = __mul__
73+
def __imul__(self, n):
74+
self.data *= n
75+
return self
76+
def append(self, item): self.data.append(item)
77+
def insert(self, i, item): self.data.insert(i, item)
78+
def pop(self, i=-1): return self.data.pop(i)
79+
def remove(self, item): self.data.remove(item)
80+
def count(self, item): return self.data.count(item)
81+
def index(self, item, *args): return self.data.index(item, *args)
82+
def reverse(self): self.data.reverse()
83+
def sort(self, *args, **kwds): self.data.sort(*args, **kwds)
84+
def extend(self, other):
85+
if isinstance(other, UserList):
86+
self.data.extend(other.data)
87+
else:
88+
self.data.extend(other)

third_party/stdlib/UserString.py

Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
#!/usr/bin/env python
2+
## vim:ts=4:et:nowrap
3+
"""A user-defined wrapper around string objects
4+
5+
Note: string objects have grown methods in Python 1.6
6+
This module requires Python 1.6 or later.
7+
"""
8+
import sys
9+
import collections
10+
11+
__all__ = ["UserString","MutableString"]
12+
13+
class UserString(collections.Sequence):
14+
def __init__(self, seq):
15+
if isinstance(seq, basestring):
16+
self.data = seq
17+
elif isinstance(seq, UserString):
18+
self.data = seq.data[:]
19+
else:
20+
self.data = str(seq)
21+
def __str__(self): return str(self.data)
22+
def __repr__(self): return repr(self.data)
23+
def __int__(self): return int(self.data)
24+
def __long__(self): return long(self.data)
25+
def __float__(self): return float(self.data)
26+
def __complex__(self): return complex(self.data)
27+
def __hash__(self): return hash(self.data)
28+
29+
def __cmp__(self, string):
30+
if isinstance(string, UserString):
31+
return cmp(self.data, string.data)
32+
else:
33+
return cmp(self.data, string)
34+
def __contains__(self, char):
35+
return char in self.data
36+
37+
def __len__(self): return len(self.data)
38+
def __getitem__(self, index): return self.__class__(self.data[index])
39+
def __getslice__(self, start, end):
40+
start = max(start, 0); end = max(end, 0)
41+
return self.__class__(self.data[start:end])
42+
43+
def __add__(self, other):
44+
if isinstance(other, UserString):
45+
return self.__class__(self.data + other.data)
46+
elif isinstance(other, basestring):
47+
return self.__class__(self.data + other)
48+
else:
49+
return self.__class__(self.data + str(other))
50+
def __radd__(self, other):
51+
if isinstance(other, basestring):
52+
return self.__class__(other + self.data)
53+
else:
54+
return self.__class__(str(other) + self.data)
55+
def __mul__(self, n):
56+
return self.__class__(self.data*n)
57+
__rmul__ = __mul__
58+
def __mod__(self, args):
59+
return self.__class__(self.data % args)
60+
61+
# the following methods are defined in alphabetical order:
62+
def capitalize(self): return self.__class__(self.data.capitalize())
63+
def center(self, width, *args):
64+
return self.__class__(self.data.center(width, *args))
65+
def count(self, sub, start=0, end=sys.maxint):
66+
return self.data.count(sub, start, end)
67+
def decode(self, encoding=None, errors=None): # XXX improve this?
68+
if encoding:
69+
if errors:
70+
return self.__class__(self.data.decode(encoding, errors))
71+
else:
72+
return self.__class__(self.data.decode(encoding))
73+
else:
74+
return self.__class__(self.data.decode())
75+
def encode(self, encoding=None, errors=None): # XXX improve this?
76+
if encoding:
77+
if errors:
78+
return self.__class__(self.data.encode(encoding, errors))
79+
else:
80+
return self.__class__(self.data.encode(encoding))
81+
else:
82+
return self.__class__(self.data.encode())
83+
def endswith(self, suffix, start=0, end=sys.maxint):
84+
return self.data.endswith(suffix, start, end)
85+
def expandtabs(self, tabsize=8):
86+
return self.__class__(self.data.expandtabs(tabsize))
87+
def find(self, sub, start=0, end=sys.maxint):
88+
return self.data.find(sub, start, end)
89+
def index(self, sub, start=0, end=sys.maxint):
90+
return self.data.index(sub, start, end)
91+
def isalpha(self): return self.data.isalpha()
92+
def isalnum(self): return self.data.isalnum()
93+
def isdecimal(self): return self.data.isdecimal()
94+
def isdigit(self): return self.data.isdigit()
95+
def islower(self): return self.data.islower()
96+
def isnumeric(self): return self.data.isnumeric()
97+
def isspace(self): return self.data.isspace()
98+
def istitle(self): return self.data.istitle()
99+
def isupper(self): return self.data.isupper()
100+
def join(self, seq): return self.data.join(seq)
101+
def ljust(self, width, *args):
102+
return self.__class__(self.data.ljust(width, *args))
103+
def lower(self): return self.__class__(self.data.lower())
104+
def lstrip(self, chars=None): return self.__class__(self.data.lstrip(chars))
105+
def partition(self, sep):
106+
return self.data.partition(sep)
107+
def replace(self, old, new, maxsplit=-1):
108+
return self.__class__(self.data.replace(old, new, maxsplit))
109+
def rfind(self, sub, start=0, end=sys.maxint):
110+
return self.data.rfind(sub, start, end)
111+
def rindex(self, sub, start=0, end=sys.maxint):
112+
return self.data.rindex(sub, start, end)
113+
def rjust(self, width, *args):
114+
return self.__class__(self.data.rjust(width, *args))
115+
def rpartition(self, sep):
116+
return self.data.rpartition(sep)
117+
def rstrip(self, chars=None): return self.__class__(self.data.rstrip(chars))
118+
def split(self, sep=None, maxsplit=-1):
119+
return self.data.split(sep, maxsplit)
120+
def rsplit(self, sep=None, maxsplit=-1):
121+
return self.data.rsplit(sep, maxsplit)
122+
def splitlines(self, keepends=0): return self.data.splitlines(keepends)
123+
def startswith(self, prefix, start=0, end=sys.maxint):
124+
return self.data.startswith(prefix, start, end)
125+
def strip(self, chars=None): return self.__class__(self.data.strip(chars))
126+
def swapcase(self): return self.__class__(self.data.swapcase())
127+
def title(self): return self.__class__(self.data.title())
128+
def translate(self, *args):
129+
return self.__class__(self.data.translate(*args))
130+
def upper(self): return self.__class__(self.data.upper())
131+
def zfill(self, width): return self.__class__(self.data.zfill(width))
132+
133+
class MutableString(UserString, collections.MutableSequence):
134+
"""mutable string objects
135+
136+
Python strings are immutable objects. This has the advantage, that
137+
strings may be used as dictionary keys. If this property isn't needed
138+
and you insist on changing string values in place instead, you may cheat
139+
and use MutableString.
140+
141+
But the purpose of this class is an educational one: to prevent
142+
people from inventing their own mutable string class derived
143+
from UserString and than forget thereby to remove (override) the
144+
__hash__ method inherited from UserString. This would lead to
145+
errors that would be very hard to track down.
146+
147+
A faster and better solution is to rewrite your program using lists."""
148+
def __init__(self, string=""):
149+
# from warnings import warnpy3k
150+
import warnings
151+
warnpy3k = warnings.warnpy3k
152+
warnpy3k('the class UserString.MutableString has been removed in '
153+
'Python 3.0', stacklevel=2)
154+
self.data = string
155+
156+
# We inherit object.__hash__, so we must deny this explicitly
157+
__hash__ = None
158+
159+
def __setitem__(self, index, sub):
160+
if isinstance(index, slice):
161+
if isinstance(sub, UserString):
162+
sub = sub.data
163+
elif not isinstance(sub, basestring):
164+
sub = str(sub)
165+
start, stop, step = index.indices(len(self.data))
166+
if step == -1:
167+
start, stop = stop+1, start+1
168+
sub = sub[::-1]
169+
elif step != 1:
170+
# XXX(twouters): I guess we should be reimplementing
171+
# the extended slice assignment/deletion algorithm here...
172+
raise TypeError, "invalid step in slicing assignment"
173+
start = min(start, stop)
174+
self.data = self.data[:start] + sub + self.data[stop:]
175+
else:
176+
if index < 0:
177+
index += len(self.data)
178+
if index < 0 or index >= len(self.data): raise IndexError
179+
self.data = self.data[:index] + sub + self.data[index+1:]
180+
def __delitem__(self, index):
181+
if isinstance(index, slice):
182+
start, stop, step = index.indices(len(self.data))
183+
if step == -1:
184+
start, stop = stop+1, start+1
185+
elif step != 1:
186+
# XXX(twouters): see same block in __setitem__
187+
raise TypeError, "invalid step in slicing deletion"
188+
start = min(start, stop)
189+
self.data = self.data[:start] + self.data[stop:]
190+
else:
191+
if index < 0:
192+
index += len(self.data)
193+
if index < 0 or index >= len(self.data): raise IndexError
194+
self.data = self.data[:index] + self.data[index+1:]
195+
def __setslice__(self, start, end, sub):
196+
start = max(start, 0); end = max(end, 0)
197+
if isinstance(sub, UserString):
198+
self.data = self.data[:start]+sub.data+self.data[end:]
199+
elif isinstance(sub, basestring):
200+
self.data = self.data[:start]+sub+self.data[end:]
201+
else:
202+
self.data = self.data[:start]+str(sub)+self.data[end:]
203+
def __delslice__(self, start, end):
204+
start = max(start, 0); end = max(end, 0)
205+
self.data = self.data[:start] + self.data[end:]
206+
def immutable(self):
207+
return UserString(self.data)
208+
def __iadd__(self, other):
209+
if isinstance(other, UserString):
210+
self.data += other.data
211+
elif isinstance(other, basestring):
212+
self.data += other
213+
else:
214+
self.data += str(other)
215+
return self
216+
def __imul__(self, n):
217+
self.data *= n
218+
return self
219+
def insert(self, index, value):
220+
self[index:index] = value
221+
222+
# if __name__ == "__main__":
223+
# # execute the regression test to stdout, if called as a script:
224+
# import os
225+
# called_in_dir, called_as = os.path.split(sys.argv[0])
226+
# called_as, py = os.path.splitext(called_as)
227+
# if '-q' in sys.argv:
228+
# from test import test_support
229+
# test_support.verbose = 0
230+
# __import__('test.test_' + called_as.lower())

third_party/stdlib/test/string_tests.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
import _struct as struct
88
from test import test_support
99
# from UserList import UserList
10+
import UserList as _UserList
11+
UserList = _UserList.UserList
1012

1113
class Sequence(object):
1214
def __init__(self, seq='wxyz'): self.seq = seq
@@ -1094,7 +1096,7 @@ def test_join(self):
10941096
self.checkequal('ac', '', 'join', ('a', '', 'c', ''))
10951097
self.checkequal('w x y z', ' ', 'join', Sequence())
10961098
self.checkequal('abc', 'a', 'join', ('abc',))
1097-
# self.checkequal('z', 'a', 'join', UserList(['z']))
1099+
self.checkequal('z', 'a', 'join', UserList(['z']))
10981100
if test_support.have_unicode:
10991101
self.checkequal(unicode('a.b.c'), unicode('.'), 'join', ['a', 'b', 'c'])
11001102
self.checkequal(unicode('a.b.c'), '.', 'join', [unicode('a'), 'b', 'c'])

third_party/stdlib/test/test_string.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
Template = string.Template
55
from test import test_support, string_tests
66
# from UserList import UserList
7+
import UserList as _UserList
8+
UserList = _UserList.UserList
79

810
class StringTest(
911
string_tests.CommonTest,
@@ -35,7 +37,7 @@ def test_join(self):
3537
self.checkequal('abcd', ('a', 'b', 'c', 'd'), 'join', '')
3638
self.checkequal('w x y z', string_tests.Sequence(), 'join', ' ')
3739
self.checkequal('abc', ('abc',), 'join', 'a')
38-
# self.checkequal('z', UserList(['z']), 'join', 'a')
40+
self.checkequal('z', UserList(['z']), 'join', 'a')
3941
if test_support.have_unicode:
4042
self.checkequal(unicode('a.b.c'), ['a', 'b', 'c'], 'join', unicode('.'))
4143
self.checkequal(unicode('a.b.c'), [unicode('a'), 'b', 'c'], 'join', '.')

third_party/stdlib/warnings.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
__all__ = ["warn", "warn_explicit", "showwarning",
1212
"formatwarning", "filterwarnings", "simplefilter",
13-
"resetwarnings", "catch_warnings"]
13+
"resetwarnings", "catch_warnings", "warnpy3k"]
1414

1515

1616
def warnpy3k(message, category=None, stacklevel=1):

0 commit comments

Comments
 (0)