Codebase list heapdict / d5c6501
Update upstream source from tag 'upstream/1.0.1' Update to upstream version '1.0.1' with Debian dir 90d870717857263c2fda7e59bebd9db39aaf6beb Diane Trout 4 years ago
10 changed file(s) with 95 addition(s) and 367 deletion(s). Raw diff Collapse all Expand all
00 Metadata-Version: 1.1
11 Name: HeapDict
2 Version: 1.0.0
2 Version: 1.0.1
33 Summary: a heap with decrease-key and increase-key operations
44 Home-page: http://stutzbachenterprises.com/
55 Author: Stutzbach Enterprises, LLC
1414
1515 ::
1616
17 hd = heapdict()
18 hd[obj1] = priority1
19 hd[obj2] = priority2
20 # ...
21 obj = hd.pop()
17 hd = heapdict()
18 hd[obj1] = priority1
19 hd[obj2] = priority2
20 # ...
21 (obj, priority) = hd.popitem()
2222
2323 Compared to an ordinary dict, a heapdict has the following differences:
2424
2525 popitem():
26 Remove and return the (key, priority) pair with the lowest
27 priority, instead of a random object.
26 Remove and return the (key, priority) pair with the lowest
27 priority, instead of a random object.
2828
2929 peekitem():
30 Return the (key, priority) pair with the lowest priority, without
31 removing it.
30 Return the (key, priority) pair with the lowest priority, without
31 removing it.
3232
3333 Unlike the Python standard library's heapq module, the heapdict
3434 supports efficiently changing the priority of an existing object
00 LICENSE
11 MANIFEST.in
22 README.rst
3 ez_setup.py
43 heapdict.py
54 setup.py
65 test_heap.py
87 HeapDict.egg-info/SOURCES.txt
98 HeapDict.egg-info/dependency_links.txt
109 HeapDict.egg-info/top_level.txt
11 HeapDict.egg-info/zip-safe
12 heapdict.egg-info/SOURCES.txt
10 HeapDict.egg-info/zip-safe
00 include heapdict.py
1 include ez_setup.py
21 include LICENSE
32 include test_heap.py
43 include setup.py
00 Metadata-Version: 1.1
11 Name: HeapDict
2 Version: 1.0.0
2 Version: 1.0.1
33 Summary: a heap with decrease-key and increase-key operations
44 Home-page: http://stutzbachenterprises.com/
55 Author: Stutzbach Enterprises, LLC
1414
1515 ::
1616
17 hd = heapdict()
18 hd[obj1] = priority1
19 hd[obj2] = priority2
20 # ...
21 obj = hd.pop()
17 hd = heapdict()
18 hd[obj1] = priority1
19 hd[obj2] = priority2
20 # ...
21 (obj, priority) = hd.popitem()
2222
2323 Compared to an ordinary dict, a heapdict has the following differences:
2424
2525 popitem():
26 Remove and return the (key, priority) pair with the lowest
27 priority, instead of a random object.
26 Remove and return the (key, priority) pair with the lowest
27 priority, instead of a random object.
2828
2929 peekitem():
30 Return the (key, priority) pair with the lowest priority, without
31 removing it.
30 Return the (key, priority) pair with the lowest priority, without
31 removing it.
3232
3333 Unlike the Python standard library's heapq module, the heapdict
3434 supports efficiently changing the priority of an existing object
1010 hd[obj1] = priority1
1111 hd[obj2] = priority2
1212 # ...
13 obj = hd.pop()
13 (obj, priority) = hd.popitem()
1414
1515 Compared to an ordinary dict, a heapdict has the following differences:
1616
+0
-276
ez_setup.py less more
0 #!python
1 """Bootstrap setuptools installation
2
3 If you want to use setuptools in your package's setup.py, just include this
4 file in the same directory with it, and add this to the top of your setup.py::
5
6 from ez_setup import use_setuptools
7 use_setuptools()
8
9 If you want to require a specific version of setuptools, set a download
10 mirror, or use an alternate download directory, you can do so by supplying
11 the appropriate options to ``use_setuptools()``.
12
13 This file can also be run as a script to install or upgrade setuptools.
14 """
15 import sys
16 DEFAULT_VERSION = "0.6c9"
17 DEFAULT_URL = "http://pypi.python.org/packages/%s/s/setuptools/" % sys.version[:3]
18
19 md5_data = {
20 'setuptools-0.6b1-py2.3.egg': '8822caf901250d848b996b7f25c6e6ca',
21 'setuptools-0.6b1-py2.4.egg': 'b79a8a403e4502fbb85ee3f1941735cb',
22 'setuptools-0.6b2-py2.3.egg': '5657759d8a6d8fc44070a9d07272d99b',
23 'setuptools-0.6b2-py2.4.egg': '4996a8d169d2be661fa32a6e52e4f82a',
24 'setuptools-0.6b3-py2.3.egg': 'bb31c0fc7399a63579975cad9f5a0618',
25 'setuptools-0.6b3-py2.4.egg': '38a8c6b3d6ecd22247f179f7da669fac',
26 'setuptools-0.6b4-py2.3.egg': '62045a24ed4e1ebc77fe039aa4e6f7e5',
27 'setuptools-0.6b4-py2.4.egg': '4cb2a185d228dacffb2d17f103b3b1c4',
28 'setuptools-0.6c1-py2.3.egg': 'b3f2b5539d65cb7f74ad79127f1a908c',
29 'setuptools-0.6c1-py2.4.egg': 'b45adeda0667d2d2ffe14009364f2a4b',
30 'setuptools-0.6c2-py2.3.egg': 'f0064bf6aa2b7d0f3ba0b43f20817c27',
31 'setuptools-0.6c2-py2.4.egg': '616192eec35f47e8ea16cd6a122b7277',
32 'setuptools-0.6c3-py2.3.egg': 'f181fa125dfe85a259c9cd6f1d7b78fa',
33 'setuptools-0.6c3-py2.4.egg': 'e0ed74682c998bfb73bf803a50e7b71e',
34 'setuptools-0.6c3-py2.5.egg': 'abef16fdd61955514841c7c6bd98965e',
35 'setuptools-0.6c4-py2.3.egg': 'b0b9131acab32022bfac7f44c5d7971f',
36 'setuptools-0.6c4-py2.4.egg': '2a1f9656d4fbf3c97bf946c0a124e6e2',
37 'setuptools-0.6c4-py2.5.egg': '8f5a052e32cdb9c72bcf4b5526f28afc',
38 'setuptools-0.6c5-py2.3.egg': 'ee9fd80965da04f2f3e6b3576e9d8167',
39 'setuptools-0.6c5-py2.4.egg': 'afe2adf1c01701ee841761f5bcd8aa64',
40 'setuptools-0.6c5-py2.5.egg': 'a8d3f61494ccaa8714dfed37bccd3d5d',
41 'setuptools-0.6c6-py2.3.egg': '35686b78116a668847237b69d549ec20',
42 'setuptools-0.6c6-py2.4.egg': '3c56af57be3225019260a644430065ab',
43 'setuptools-0.6c6-py2.5.egg': 'b2f8a7520709a5b34f80946de5f02f53',
44 'setuptools-0.6c7-py2.3.egg': '209fdf9adc3a615e5115b725658e13e2',
45 'setuptools-0.6c7-py2.4.egg': '5a8f954807d46a0fb67cf1f26c55a82e',
46 'setuptools-0.6c7-py2.5.egg': '45d2ad28f9750e7434111fde831e8372',
47 'setuptools-0.6c8-py2.3.egg': '50759d29b349db8cfd807ba8303f1902',
48 'setuptools-0.6c8-py2.4.egg': 'cba38d74f7d483c06e9daa6070cce6de',
49 'setuptools-0.6c8-py2.5.egg': '1721747ee329dc150590a58b3e1ac95b',
50 'setuptools-0.6c9-py2.3.egg': 'a83c4020414807b496e4cfbe08507c03',
51 'setuptools-0.6c9-py2.4.egg': '260a2be2e5388d66bdaee06abec6342a',
52 'setuptools-0.6c9-py2.5.egg': 'fe67c3e5a17b12c0e7c541b7ea43a8e6',
53 'setuptools-0.6c9-py2.6.egg': 'ca37b1ff16fa2ede6e19383e7b59245a',
54 }
55
56 import sys, os
57 try: from hashlib import md5
58 except ImportError: from md5 import md5
59
60 def _validate_md5(egg_name, data):
61 if egg_name in md5_data:
62 digest = md5(data).hexdigest()
63 if digest != md5_data[egg_name]:
64 print >>sys.stderr, (
65 "md5 validation of %s failed! (Possible download problem?)"
66 % egg_name
67 )
68 sys.exit(2)
69 return data
70
71 def use_setuptools(
72 version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir,
73 download_delay=15
74 ):
75 """Automatically find/download setuptools and make it available on sys.path
76
77 `version` should be a valid setuptools version number that is available
78 as an egg for download under the `download_base` URL (which should end with
79 a '/'). `to_dir` is the directory where setuptools will be downloaded, if
80 it is not already available. If `download_delay` is specified, it should
81 be the number of seconds that will be paused before initiating a download,
82 should one be required. If an older version of setuptools is installed,
83 this routine will print a message to ``sys.stderr`` and raise SystemExit in
84 an attempt to abort the calling script.
85 """
86 was_imported = 'pkg_resources' in sys.modules or 'setuptools' in sys.modules
87 def do_download():
88 egg = download_setuptools(version, download_base, to_dir, download_delay)
89 sys.path.insert(0, egg)
90 import setuptools; setuptools.bootstrap_install_from = egg
91 try:
92 import pkg_resources
93 except ImportError:
94 return do_download()
95 try:
96 pkg_resources.require("setuptools>="+version); return
97 except pkg_resources.VersionConflict, e:
98 if was_imported:
99 print >>sys.stderr, (
100 "The required version of setuptools (>=%s) is not available, and\n"
101 "can't be installed while this script is running. Please install\n"
102 " a more recent version first, using 'easy_install -U setuptools'."
103 "\n\n(Currently using %r)"
104 ) % (version, e.args[0])
105 sys.exit(2)
106 else:
107 del pkg_resources, sys.modules['pkg_resources'] # reload ok
108 return do_download()
109 except pkg_resources.DistributionNotFound:
110 return do_download()
111
112 def download_setuptools(
113 version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir,
114 delay = 15
115 ):
116 """Download setuptools from a specified location and return its filename
117
118 `version` should be a valid setuptools version number that is available
119 as an egg for download under the `download_base` URL (which should end
120 with a '/'). `to_dir` is the directory where the egg will be downloaded.
121 `delay` is the number of seconds to pause before an actual download attempt.
122 """
123 import urllib2, shutil
124 egg_name = "setuptools-%s-py%s.egg" % (version,sys.version[:3])
125 url = download_base + egg_name
126 saveto = os.path.join(to_dir, egg_name)
127 src = dst = None
128 if not os.path.exists(saveto): # Avoid repeated downloads
129 try:
130 from distutils import log
131 if delay:
132 log.warn("""
133 ---------------------------------------------------------------------------
134 This script requires setuptools version %s to run (even to display
135 help). I will attempt to download it for you (from
136 %s), but
137 you may need to enable firewall access for this script first.
138 I will start the download in %d seconds.
139
140 (Note: if this machine does not have network access, please obtain the file
141
142 %s
143
144 and place it in this directory before rerunning this script.)
145 ---------------------------------------------------------------------------""",
146 version, download_base, delay, url
147 ); from time import sleep; sleep(delay)
148 log.warn("Downloading %s", url)
149 src = urllib2.urlopen(url)
150 # Read/write all in one block, so we don't create a corrupt file
151 # if the download is interrupted.
152 data = _validate_md5(egg_name, src.read())
153 dst = open(saveto,"wb"); dst.write(data)
154 finally:
155 if src: src.close()
156 if dst: dst.close()
157 return os.path.realpath(saveto)
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194 def main(argv, version=DEFAULT_VERSION):
195 """Install or upgrade setuptools and EasyInstall"""
196 try:
197 import setuptools
198 except ImportError:
199 egg = None
200 try:
201 egg = download_setuptools(version, delay=0)
202 sys.path.insert(0,egg)
203 from setuptools.command.easy_install import main
204 return main(list(argv)+[egg]) # we're done here
205 finally:
206 if egg and os.path.exists(egg):
207 os.unlink(egg)
208 else:
209 if setuptools.__version__ == '0.0.1':
210 print >>sys.stderr, (
211 "You have an obsolete version of setuptools installed. Please\n"
212 "remove it from your system entirely before rerunning this script."
213 )
214 sys.exit(2)
215
216 req = "setuptools>="+version
217 import pkg_resources
218 try:
219 pkg_resources.require(req)
220 except pkg_resources.VersionConflict:
221 try:
222 from setuptools.command.easy_install import main
223 except ImportError:
224 from easy_install import main
225 main(list(argv)+[download_setuptools(delay=0)])
226 sys.exit(0) # try to force an exit
227 else:
228 if argv:
229 from setuptools.command.easy_install import main
230 main(argv)
231 else:
232 print "Setuptools version",version,"or greater has been installed."
233 print '(Run "ez_setup.py -U setuptools" to reinstall or upgrade.)'
234
235 def update_md5(filenames):
236 """Update our built-in md5 registry"""
237
238 import re
239
240 for name in filenames:
241 base = os.path.basename(name)
242 f = open(name,'rb')
243 md5_data[base] = md5(f.read()).hexdigest()
244 f.close()
245
246 data = [" %r: %r,\n" % it for it in md5_data.items()]
247 data.sort()
248 repl = "".join(data)
249
250 import inspect
251 srcfile = inspect.getsourcefile(sys.modules[__name__])
252 f = open(srcfile, 'rb'); src = f.read(); f.close()
253
254 match = re.search("\nmd5_data = {\n([^}]+)}", src)
255 if not match:
256 print >>sys.stderr, "Internal error!"
257 sys.exit(2)
258
259 src = src[:match.start(1)] + repl + src[match.end(1):]
260 f = open(srcfile,'w')
261 f.write(src)
262 f.close()
263
264
265 if __name__=='__main__':
266 if len(sys.argv)>2 and sys.argv[1]=='--md5update':
267 update_md5(sys.argv[2:])
268 else:
269 main(sys.argv[1:])
270
271
272
273
274
275
0 import collections
0 try:
1 from collections.abc import MutableMapping
2 except ImportError:
3 from collections import MutableMapping
4
15
26 def doc(s):
37 if hasattr(s, '__call__'):
48 s = s.__doc__
9
510 def f(g):
611 g.__doc__ = s
712 return g
813 return f
914
10 class heapdict(collections.MutableMapping):
15
16 class heapdict(MutableMapping):
1117 __marker = object()
1218
13 @staticmethod
14 def _parent(i):
15 return ((i - 1) >> 1)
16
17 @staticmethod
18 def _left(i):
19 return ((i << 1) + 1)
20
21 @staticmethod
22 def _right(i):
23 return ((i+1) << 1)
24
2519 def __init__(self, *args, **kw):
2620 self.heap = []
2721 self.d = {}
2923
3024 @doc(dict.clear)
3125 def clear(self):
32 self.heap.clear()
26 del self.heap[:]
3327 self.d.clear()
3428
3529 @doc(dict.__setitem__)
4236 self._decrease_key(len(self.heap)-1)
4337
4438 def _min_heapify(self, i):
45 l = self._left(i)
46 r = self._right(i)
4739 n = len(self.heap)
48 if l < n and self.heap[l][0] < self.heap[i][0]:
49 low = l
50 else:
51 low = i
52 if r < n and self.heap[r][0] < self.heap[low][0]:
53 low = r
40 h = self.heap
41 while True:
42 # calculate the offset of the left child
43 l = (i << 1) + 1
44 # calculate the offset of the right child
45 r = (i + 1) << 1
46 if l < n and h[l][0] < h[i][0]:
47 low = l
48 else:
49 low = i
50 if r < n and h[r][0] < h[low][0]:
51 low = r
5452
55 if low != i:
53 if low == i:
54 break
55
5656 self._swap(i, low)
57 self._min_heapify(low)
57 i = low
5858
5959 def _decrease_key(self, i):
6060 while i:
61 parent = self._parent(i)
62 if self.heap[parent][0] < self.heap[i][0]: break
61 # calculate the offset of the parent
62 parent = (i - 1) >> 1
63 if self.heap[parent][0] < self.heap[i][0]:
64 break
6365 self._swap(i, parent)
6466 i = parent
6567
6668 def _swap(self, i, j):
67 self.heap[i], self.heap[j] = self.heap[j], self.heap[i]
68 self.heap[i][2] = i
69 self.heap[j][2] = j
69 h = self.heap
70 h[i], h[j] = h[j], h[i]
71 h[i][2] = i
72 h[j][2] = j
7073
7174 @doc(dict.__delitem__)
7275 def __delitem__(self, key):
7376 wrapper = self.d[key]
7477 while wrapper[2]:
75 parentpos = self._parent(wrapper[2])
78 # calculate the offset of the parent
79 parentpos = (wrapper[2] - 1) >> 1
7680 parent = self.heap[parentpos]
7781 self._swap(wrapper[2], parent[2])
7882 self.popitem()
9195 if len(self.heap) == 1:
9296 self.heap.pop()
9397 else:
94 self.heap[0] = self.heap.pop(-1)
98 self.heap[0] = self.heap.pop()
9599 self.heap[0][2] = 0
96100 self._min_heapify(0)
97101 del self.d[wrapper[1]]
98 return wrapper[1], wrapper[0]
102 return wrapper[1], wrapper[0]
99103
100104 @doc(dict.__len__)
101105 def __len__(self):
105109 """D.peekitem() -> (k, v), return the (key, value) pair with lowest value;\n but raise KeyError if D is empty."""
106110 return (self.heap[0][1], self.heap[0][0])
107111
112
108113 del doc
109114 __all__ = ['heapdict']
00 [egg_info]
11 tag_build =
22 tag_date = 0
3 tag_svn_revision = 0
43
00 #!/usr/bin/env
11
2 import sys
3 if sys.version_info[0] <= 2:
4 import ez_setup
5 ez_setup.use_setuptools()
6 from setuptools import setup, Extension
7 else:
8 from distutils.core import setup, Extension
2 from setuptools import setup
93
104 setup(name='HeapDict',
11 version='1.0.0',
5 version='1.0.1',
126 description='a heap with decrease-key and increase-key operations',
137 author='Stutzbach Enterprises, LLC',
148 author_email='daniel@stutzbachenterprises.com',
3428 ],
3529
3630 long_description=open('README.rst').read(),
37
3831 )
00 #!/usr/bin/python
11 from __future__ import print_function
2 import random
3 import sys
4 import unittest
25 from heapdict import heapdict
3 import random
4 import unittest
5 import sys
66 try:
7 import test.support as test_support # Python 3
7 # Python 3
8 import test.support as test_support
89 except ImportError:
9 import test.test_support as test_support # Python 2
10 # Python 2
11 import test.test_support as test_support
1012
1113 N = 100
1214
15
1316 class TestHeap(unittest.TestCase):
17
1418 def check_invariants(self, h):
15 for i in range(len(h)):
16 self.assertEqual(h.heap[i][2], i)
17 if i > 0:
18 self.assertTrue(h.heap[h._parent(i)][0] <= h.heap[i][0])
19 # the 3rd entry of each heap entry is the position in the heap
20 for i, e in enumerate(h.heap):
21 self.assertEqual(e[2], i)
22 # the parent of each heap element must not be larger than the element
23 for i in range(1, len(h.heap)):
24 parent = (i - 1) >> 1
25 self.assertLessEqual(h.heap[parent][0], h.heap[i][0])
1926
2027 def make_data(self):
2128 pairs = [(random.random(), random.random()) for i in range(N)]
2734
2835 pairs.sort(key=lambda x: x[1], reverse=True)
2936 return h, pairs, d
30
37
3138 def test_popitem(self):
32 h, pairs, d = self.make_data()
39 h, pairs, _ = self.make_data()
3340 while pairs:
3441 v = h.popitem()
3542 v2 = pairs.pop(-1)
4148 for i in range(N):
4249 h[i] = 0
4350 for i in range(N):
44 k, v = h.popitem()
51 _, v = h.popitem()
4552 self.assertEqual(v, 0)
4653 self.check_invariants(h)
4754
4855 def test_peek(self):
49 h, pairs, d = self.make_data()
56 h, pairs, _ = self.make_data()
5057 while pairs:
5158 v = h.peekitem()[0]
5259 h.popitem()
5562 self.assertEqual(len(h), 0)
5663
5764 def test_iter(self):
58 h, pairs, d = self.make_data()
65 h, _, d = self.make_data()
5966 self.assertEqual(list(h), list(d))
6067
6168 def test_keys(self):
62 h, pairs, d = self.make_data()
69 h, _, d = self.make_data()
6370 self.assertEqual(list(sorted(h.keys())), list(sorted(d.keys())))
6471
6572 def test_values(self):
66 h, pairs, d = self.make_data()
73 h, _, d = self.make_data()
6774 self.assertEqual(list(sorted(h.values())), list(sorted(d.values())))
6875
6976 def test_del(self):
70 h, pairs, d = self.make_data()
77 h, pairs, _ = self.make_data()
7178 k, v = pairs.pop(N//2)
7279 del h[k]
7380 while pairs:
7784 self.assertEqual(len(h), 0)
7885
7986 def test_change(self):
80 h, pairs, d = self.make_data()
87 h, pairs, _ = self.make_data()
8188 k, v = pairs[N//2]
8289 h[k] = 0.5
8390 pairs[N//2] = (k, 0.5)
84 pairs.sort(key = lambda x: x[1], reverse=True)
91 pairs.sort(key=lambda x: x[1], reverse=True)
8592 while pairs:
8693 v = h.popitem()
8794 v2 = pairs.pop(-1)
8895 self.assertEqual(v, v2)
8996 self.assertEqual(len(h), 0)
9097
91 #==============================================================================
98 def test_clear(self):
99 h, _, _ = self.make_data()
100 h.clear()
101 self.assertEqual(len(h), 0)
102
92103
93104 def test_main(verbose=None):
94 from types import BuiltinFunctionType
95
96105 test_classes = [TestHeap]
97106 test_support.run_unittest(*test_classes)
98107
100109 if verbose and hasattr(sys, "gettotalrefcount"):
101110 import gc
102111 counts = [None] * 5
103 for i in xrange(len(counts)):
112 for i in range(len(counts)):
104113 test_support.run_unittest(*test_classes)
105114 gc.collect()
106115 counts[i] = sys.gettotalrefcount()
107116 print(counts)
108117
118
109119 if __name__ == "__main__":
110120 test_main(verbose=True)