Merge lp:~jseutter/testresources/py3 into lp:~testresources-developers/testresources/trunk
- py3
- Merge into trunk
Status: | Needs review |
---|---|
Proposed branch: | lp:~jseutter/testresources/py3 |
Merge into: | lp:~testresources-developers/testresources/trunk |
Diff against target: |
695 lines (+526/-20) 7 files modified
distribute_setup.py (+494/-0) lib/testresources/__init__.py (+13/-12) lib/testresources/tests/TestUtil.py (+2/-1) lib/testresources/tests/test_resource_graph.py (+2/-2) lib/testresources/tests/test_resourced_test_case.py (+2/-2) lib/testresources/tests/test_test_resource.py (+1/-1) setup.py (+12/-2) |
To merge this branch: | bzr merge lp:~jseutter/testresources/py3 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Jerry Seutter (community) | Disapprove | ||
Barry Warsaw | Pending | ||
testresources developers | Pending | ||
Review via email: mp+105525@code.launchpad.net |
Commit message
Description of the change
This branch adds support for python 3. It uses "from __future__ import print_function", so it will not work in Python versions older than Python 2.6.
Barry Warsaw (barry) wrote : | # |
On May 11, 2012, at 08:49 PM, Robert Collins wrote:
>This seems to be much more than py3; whats the additional stuff for?
>[and why would it be in-tree, it looks boilerplatey].
Are you referring to the distribute_setup.py file? IME, distribute is much
better at Python 3 compatibility and is future-proof for when distutils is
removed[*], so I recommended Jerry switch to it rather than use it or
ez_setup.
[*] and not a moment too soon.
Barry Warsaw (barry) wrote : | # |
On May 11, 2012, at 08:01 PM, Jerry Seutter wrote:
>You have been requested to review the proposed merge of
>lp:~jseutter/testresources/py3 into lp:testresources.
>
>For more details, see:
>https:/
>
>This branch adds support for python 3. It uses "from __future__ import
>print_function", so it will not work in Python versions older than Python
>2.6.
+1
Robert Collins (lifeless) wrote : | # |
I have a philospohical objection to having such massive boilerplate in
source trees. I'd put a smiley face here, but I'm not being humourous
;) It has to be maintained and updated - its dead weight.
Barry Warsaw (barry) wrote : | # |
On May 11, 2012, at 11:40 PM, Robert Collins wrote:
>I have a philospohical objection to having such massive boilerplate in
>source trees. I'd put a smiley face here, but I'm not being humourous
>;) It has to be maintained and updated - its dead weight.
If the package is already pulling in ez_setup.py then it should definitely
convert to using distribute_
change it back to using distutils.
Robert Collins (lifeless) wrote : | # |
On Sat, May 12, 2012 at 2:14 PM, Barry Warsaw <email address hidden> wrote:
> On May 11, 2012, at 11:40 PM, Robert Collins wrote:
>
>>I have a philospohical objection to having such massive boilerplate in
>>source trees. I'd put a smiley face here, but I'm not being humourous
>>;) It has to be maintained and updated - its dead weight.
>
> If the package is already pulling in ez_setup.py then it should definitely
> convert to using distribute_
> change it back to using distutils.
Its not; ez_setup.py is terrible too :)
I'll look at this tomorrow/monday and merge just the py3 bits.
-Rob
Jerry Seutter (jseutter) wrote : | # |
I made a new merge proposal that does not include distribute_setup. See https:/
Unmerged revisions
- 61. By Jerry Seutter
-
Adding python 3 support.
Preview Diff
1 | === added file 'distribute_setup.py' |
2 | --- distribute_setup.py 1970-01-01 00:00:00 +0000 |
3 | +++ distribute_setup.py 2012-05-11 19:59:18 +0000 |
4 | @@ -0,0 +1,494 @@ |
5 | +#!python |
6 | +"""Bootstrap distribute installation |
7 | + |
8 | +If you want to use setuptools in your package's setup.py, just include this |
9 | +file in the same directory with it, and add this to the top of your setup.py:: |
10 | + |
11 | + from distribute_setup import use_setuptools |
12 | + use_setuptools() |
13 | + |
14 | +If you want to require a specific version of setuptools, set a download |
15 | +mirror, or use an alternate download directory, you can do so by supplying |
16 | +the appropriate options to ``use_setuptools()``. |
17 | + |
18 | +This file can also be run as a script to install or upgrade setuptools. |
19 | +""" |
20 | +import os |
21 | +import sys |
22 | +import time |
23 | +import fnmatch |
24 | +import tempfile |
25 | +import tarfile |
26 | +from distutils import log |
27 | + |
28 | +try: |
29 | + from site import USER_SITE |
30 | +except ImportError: |
31 | + USER_SITE = None |
32 | + |
33 | +try: |
34 | + import subprocess |
35 | + |
36 | + def _python_cmd(*args): |
37 | + args = (sys.executable,) + args |
38 | + return subprocess.call(args) == 0 |
39 | + |
40 | +except ImportError: |
41 | + # will be used for python 2.3 |
42 | + def _python_cmd(*args): |
43 | + args = (sys.executable,) + args |
44 | + # quoting arguments if windows |
45 | + if sys.platform == 'win32': |
46 | + def quote(arg): |
47 | + if ' ' in arg: |
48 | + return '"%s"' % arg |
49 | + return arg |
50 | + args = [quote(arg) for arg in args] |
51 | + return os.spawnl(os.P_WAIT, sys.executable, *args) == 0 |
52 | + |
53 | +DEFAULT_VERSION = "0.6.26" |
54 | +DEFAULT_URL = "http://pypi.python.org/packages/source/d/distribute/" |
55 | +SETUPTOOLS_FAKED_VERSION = "0.6c11" |
56 | + |
57 | +SETUPTOOLS_PKG_INFO = """\ |
58 | +Metadata-Version: 1.0 |
59 | +Name: setuptools |
60 | +Version: %s |
61 | +Summary: xxxx |
62 | +Home-page: xxx |
63 | +Author: xxx |
64 | +Author-email: xxx |
65 | +License: xxx |
66 | +Description: xxx |
67 | +""" % SETUPTOOLS_FAKED_VERSION |
68 | + |
69 | + |
70 | +def _install(tarball, install_args=()): |
71 | + # extracting the tarball |
72 | + tmpdir = tempfile.mkdtemp() |
73 | + log.warn('Extracting in %s', tmpdir) |
74 | + old_wd = os.getcwd() |
75 | + try: |
76 | + os.chdir(tmpdir) |
77 | + tar = tarfile.open(tarball) |
78 | + _extractall(tar) |
79 | + tar.close() |
80 | + |
81 | + # going in the directory |
82 | + subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0]) |
83 | + os.chdir(subdir) |
84 | + log.warn('Now working in %s', subdir) |
85 | + |
86 | + # installing |
87 | + log.warn('Installing Distribute') |
88 | + if not _python_cmd('setup.py', 'install', *install_args): |
89 | + log.warn('Something went wrong during the installation.') |
90 | + log.warn('See the error message above.') |
91 | + finally: |
92 | + os.chdir(old_wd) |
93 | + |
94 | + |
95 | +def _build_egg(egg, tarball, to_dir): |
96 | + # extracting the tarball |
97 | + tmpdir = tempfile.mkdtemp() |
98 | + log.warn('Extracting in %s', tmpdir) |
99 | + old_wd = os.getcwd() |
100 | + try: |
101 | + os.chdir(tmpdir) |
102 | + tar = tarfile.open(tarball) |
103 | + _extractall(tar) |
104 | + tar.close() |
105 | + |
106 | + # going in the directory |
107 | + subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0]) |
108 | + os.chdir(subdir) |
109 | + log.warn('Now working in %s', subdir) |
110 | + |
111 | + # building an egg |
112 | + log.warn('Building a Distribute egg in %s', to_dir) |
113 | + _python_cmd('setup.py', '-q', 'bdist_egg', '--dist-dir', to_dir) |
114 | + |
115 | + finally: |
116 | + os.chdir(old_wd) |
117 | + # returning the result |
118 | + log.warn(egg) |
119 | + if not os.path.exists(egg): |
120 | + raise IOError('Could not build the egg.') |
121 | + |
122 | + |
123 | +def _do_download(version, download_base, to_dir, download_delay): |
124 | + egg = os.path.join(to_dir, 'distribute-%s-py%d.%d.egg' |
125 | + % (version, sys.version_info[0], sys.version_info[1])) |
126 | + if not os.path.exists(egg): |
127 | + tarball = download_setuptools(version, download_base, |
128 | + to_dir, download_delay) |
129 | + _build_egg(egg, tarball, to_dir) |
130 | + sys.path.insert(0, egg) |
131 | + import setuptools |
132 | + setuptools.bootstrap_install_from = egg |
133 | + |
134 | + |
135 | +def use_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL, |
136 | + to_dir=os.curdir, download_delay=15, no_fake=True): |
137 | + # making sure we use the absolute path |
138 | + to_dir = os.path.abspath(to_dir) |
139 | + was_imported = 'pkg_resources' in sys.modules or \ |
140 | + 'setuptools' in sys.modules |
141 | + try: |
142 | + try: |
143 | + import pkg_resources |
144 | + if not hasattr(pkg_resources, '_distribute'): |
145 | + if not no_fake: |
146 | + _fake_setuptools() |
147 | + raise ImportError |
148 | + except ImportError: |
149 | + return _do_download(version, download_base, to_dir, download_delay) |
150 | + try: |
151 | + pkg_resources.require("distribute>="+version) |
152 | + return |
153 | + except pkg_resources.VersionConflict: |
154 | + e = sys.exc_info()[1] |
155 | + if was_imported: |
156 | + sys.stderr.write( |
157 | + "The required version of distribute (>=%s) is not available,\n" |
158 | + "and can't be installed while this script is running. Please\n" |
159 | + "install a more recent version first, using\n" |
160 | + "'easy_install -U distribute'." |
161 | + "\n\n(Currently using %r)\n" % (version, e.args[0])) |
162 | + sys.exit(2) |
163 | + else: |
164 | + del pkg_resources, sys.modules['pkg_resources'] # reload ok |
165 | + return _do_download(version, download_base, to_dir, |
166 | + download_delay) |
167 | + except pkg_resources.DistributionNotFound: |
168 | + return _do_download(version, download_base, to_dir, |
169 | + download_delay) |
170 | + finally: |
171 | + if not no_fake: |
172 | + _create_fake_setuptools_pkg_info(to_dir) |
173 | + |
174 | +def download_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL, |
175 | + to_dir=os.curdir, delay=15): |
176 | + """Download distribute from a specified location and return its filename |
177 | + |
178 | + `version` should be a valid distribute version number that is available |
179 | + as an egg for download under the `download_base` URL (which should end |
180 | + with a '/'). `to_dir` is the directory where the egg will be downloaded. |
181 | + `delay` is the number of seconds to pause before an actual download |
182 | + attempt. |
183 | + """ |
184 | + # making sure we use the absolute path |
185 | + to_dir = os.path.abspath(to_dir) |
186 | + try: |
187 | + from urllib.request import urlopen |
188 | + except ImportError: |
189 | + from urllib2 import urlopen |
190 | + tgz_name = "distribute-%s.tar.gz" % version |
191 | + url = download_base + tgz_name |
192 | + saveto = os.path.join(to_dir, tgz_name) |
193 | + src = dst = None |
194 | + if not os.path.exists(saveto): # Avoid repeated downloads |
195 | + try: |
196 | + log.warn("Downloading %s", url) |
197 | + src = urlopen(url) |
198 | + # Read/write all in one block, so we don't create a corrupt file |
199 | + # if the download is interrupted. |
200 | + data = src.read() |
201 | + dst = open(saveto, "wb") |
202 | + dst.write(data) |
203 | + finally: |
204 | + if src: |
205 | + src.close() |
206 | + if dst: |
207 | + dst.close() |
208 | + return os.path.realpath(saveto) |
209 | + |
210 | +def _no_sandbox(function): |
211 | + def __no_sandbox(*args, **kw): |
212 | + try: |
213 | + from setuptools.sandbox import DirectorySandbox |
214 | + if not hasattr(DirectorySandbox, '_old'): |
215 | + def violation(*args): |
216 | + pass |
217 | + DirectorySandbox._old = DirectorySandbox._violation |
218 | + DirectorySandbox._violation = violation |
219 | + patched = True |
220 | + else: |
221 | + patched = False |
222 | + except ImportError: |
223 | + patched = False |
224 | + |
225 | + try: |
226 | + return function(*args, **kw) |
227 | + finally: |
228 | + if patched: |
229 | + DirectorySandbox._violation = DirectorySandbox._old |
230 | + del DirectorySandbox._old |
231 | + |
232 | + return __no_sandbox |
233 | + |
234 | +def _patch_file(path, content): |
235 | + """Will backup the file then patch it""" |
236 | + existing_content = open(path).read() |
237 | + if existing_content == content: |
238 | + # already patched |
239 | + log.warn('Already patched.') |
240 | + return False |
241 | + log.warn('Patching...') |
242 | + _rename_path(path) |
243 | + f = open(path, 'w') |
244 | + try: |
245 | + f.write(content) |
246 | + finally: |
247 | + f.close() |
248 | + return True |
249 | + |
250 | +_patch_file = _no_sandbox(_patch_file) |
251 | + |
252 | +def _same_content(path, content): |
253 | + return open(path).read() == content |
254 | + |
255 | +def _rename_path(path): |
256 | + new_name = path + '.OLD.%s' % time.time() |
257 | + log.warn('Renaming %s into %s', path, new_name) |
258 | + os.rename(path, new_name) |
259 | + return new_name |
260 | + |
261 | +def _remove_flat_installation(placeholder): |
262 | + if not os.path.isdir(placeholder): |
263 | + log.warn('Unkown installation at %s', placeholder) |
264 | + return False |
265 | + found = False |
266 | + for file in os.listdir(placeholder): |
267 | + if fnmatch.fnmatch(file, 'setuptools*.egg-info'): |
268 | + found = True |
269 | + break |
270 | + if not found: |
271 | + log.warn('Could not locate setuptools*.egg-info') |
272 | + return |
273 | + |
274 | + log.warn('Removing elements out of the way...') |
275 | + pkg_info = os.path.join(placeholder, file) |
276 | + if os.path.isdir(pkg_info): |
277 | + patched = _patch_egg_dir(pkg_info) |
278 | + else: |
279 | + patched = _patch_file(pkg_info, SETUPTOOLS_PKG_INFO) |
280 | + |
281 | + if not patched: |
282 | + log.warn('%s already patched.', pkg_info) |
283 | + return False |
284 | + # now let's move the files out of the way |
285 | + for element in ('setuptools', 'pkg_resources.py', 'site.py'): |
286 | + element = os.path.join(placeholder, element) |
287 | + if os.path.exists(element): |
288 | + _rename_path(element) |
289 | + else: |
290 | + log.warn('Could not find the %s element of the ' |
291 | + 'Setuptools distribution', element) |
292 | + return True |
293 | + |
294 | +_remove_flat_installation = _no_sandbox(_remove_flat_installation) |
295 | + |
296 | +def _after_install(dist): |
297 | + log.warn('After install bootstrap.') |
298 | + placeholder = dist.get_command_obj('install').install_purelib |
299 | + _create_fake_setuptools_pkg_info(placeholder) |
300 | + |
301 | +def _create_fake_setuptools_pkg_info(placeholder): |
302 | + if not placeholder or not os.path.exists(placeholder): |
303 | + log.warn('Could not find the install location') |
304 | + return |
305 | + pyver = '%s.%s' % (sys.version_info[0], sys.version_info[1]) |
306 | + setuptools_file = 'setuptools-%s-py%s.egg-info' % \ |
307 | + (SETUPTOOLS_FAKED_VERSION, pyver) |
308 | + pkg_info = os.path.join(placeholder, setuptools_file) |
309 | + if os.path.exists(pkg_info): |
310 | + log.warn('%s already exists', pkg_info) |
311 | + return |
312 | + |
313 | + log.warn('Creating %s', pkg_info) |
314 | + f = open(pkg_info, 'w') |
315 | + try: |
316 | + f.write(SETUPTOOLS_PKG_INFO) |
317 | + finally: |
318 | + f.close() |
319 | + |
320 | + pth_file = os.path.join(placeholder, 'setuptools.pth') |
321 | + log.warn('Creating %s', pth_file) |
322 | + f = open(pth_file, 'w') |
323 | + try: |
324 | + f.write(os.path.join(os.curdir, setuptools_file)) |
325 | + finally: |
326 | + f.close() |
327 | + |
328 | +_create_fake_setuptools_pkg_info = _no_sandbox(_create_fake_setuptools_pkg_info) |
329 | + |
330 | +def _patch_egg_dir(path): |
331 | + # let's check if it's already patched |
332 | + pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO') |
333 | + if os.path.exists(pkg_info): |
334 | + if _same_content(pkg_info, SETUPTOOLS_PKG_INFO): |
335 | + log.warn('%s already patched.', pkg_info) |
336 | + return False |
337 | + _rename_path(path) |
338 | + os.mkdir(path) |
339 | + os.mkdir(os.path.join(path, 'EGG-INFO')) |
340 | + pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO') |
341 | + f = open(pkg_info, 'w') |
342 | + try: |
343 | + f.write(SETUPTOOLS_PKG_INFO) |
344 | + finally: |
345 | + f.close() |
346 | + return True |
347 | + |
348 | +_patch_egg_dir = _no_sandbox(_patch_egg_dir) |
349 | + |
350 | +def _before_install(): |
351 | + log.warn('Before install bootstrap.') |
352 | + _fake_setuptools() |
353 | + |
354 | + |
355 | +def _under_prefix(location): |
356 | + if 'install' not in sys.argv: |
357 | + return True |
358 | + args = sys.argv[sys.argv.index('install')+1:] |
359 | + for index, arg in enumerate(args): |
360 | + for option in ('--root', '--prefix'): |
361 | + if arg.startswith('%s=' % option): |
362 | + top_dir = arg.split('root=')[-1] |
363 | + return location.startswith(top_dir) |
364 | + elif arg == option: |
365 | + if len(args) > index: |
366 | + top_dir = args[index+1] |
367 | + return location.startswith(top_dir) |
368 | + if arg == '--user' and USER_SITE is not None: |
369 | + return location.startswith(USER_SITE) |
370 | + return True |
371 | + |
372 | + |
373 | +def _fake_setuptools(): |
374 | + log.warn('Scanning installed packages') |
375 | + try: |
376 | + import pkg_resources |
377 | + except ImportError: |
378 | + # we're cool |
379 | + log.warn('Setuptools or Distribute does not seem to be installed.') |
380 | + return |
381 | + ws = pkg_resources.working_set |
382 | + try: |
383 | + setuptools_dist = ws.find(pkg_resources.Requirement.parse('setuptools', |
384 | + replacement=False)) |
385 | + except TypeError: |
386 | + # old distribute API |
387 | + setuptools_dist = ws.find(pkg_resources.Requirement.parse('setuptools')) |
388 | + |
389 | + if setuptools_dist is None: |
390 | + log.warn('No setuptools distribution found') |
391 | + return |
392 | + # detecting if it was already faked |
393 | + setuptools_location = setuptools_dist.location |
394 | + log.warn('Setuptools installation detected at %s', setuptools_location) |
395 | + |
396 | + # if --root or --preix was provided, and if |
397 | + # setuptools is not located in them, we don't patch it |
398 | + if not _under_prefix(setuptools_location): |
399 | + log.warn('Not patching, --root or --prefix is installing Distribute' |
400 | + ' in another location') |
401 | + return |
402 | + |
403 | + # let's see if its an egg |
404 | + if not setuptools_location.endswith('.egg'): |
405 | + log.warn('Non-egg installation') |
406 | + res = _remove_flat_installation(setuptools_location) |
407 | + if not res: |
408 | + return |
409 | + else: |
410 | + log.warn('Egg installation') |
411 | + pkg_info = os.path.join(setuptools_location, 'EGG-INFO', 'PKG-INFO') |
412 | + if (os.path.exists(pkg_info) and |
413 | + _same_content(pkg_info, SETUPTOOLS_PKG_INFO)): |
414 | + log.warn('Already patched.') |
415 | + return |
416 | + log.warn('Patching...') |
417 | + # let's create a fake egg replacing setuptools one |
418 | + res = _patch_egg_dir(setuptools_location) |
419 | + if not res: |
420 | + return |
421 | + log.warn('Patched done.') |
422 | + _relaunch() |
423 | + |
424 | + |
425 | +def _relaunch(): |
426 | + log.warn('Relaunching...') |
427 | + # we have to relaunch the process |
428 | + # pip marker to avoid a relaunch bug |
429 | + if sys.argv[:3] == ['-c', 'install', '--single-version-externally-managed']: |
430 | + sys.argv[0] = 'setup.py' |
431 | + args = [sys.executable] + sys.argv |
432 | + sys.exit(subprocess.call(args)) |
433 | + |
434 | + |
435 | +def _extractall(self, path=".", members=None): |
436 | + """Extract all members from the archive to the current working |
437 | + directory and set owner, modification time and permissions on |
438 | + directories afterwards. `path' specifies a different directory |
439 | + to extract to. `members' is optional and must be a subset of the |
440 | + list returned by getmembers(). |
441 | + """ |
442 | + import copy |
443 | + import operator |
444 | + from tarfile import ExtractError |
445 | + directories = [] |
446 | + |
447 | + if members is None: |
448 | + members = self |
449 | + |
450 | + for tarinfo in members: |
451 | + if tarinfo.isdir(): |
452 | + # Extract directories with a safe mode. |
453 | + directories.append(tarinfo) |
454 | + tarinfo = copy.copy(tarinfo) |
455 | + tarinfo.mode = 448 # decimal for oct 0700 |
456 | + self.extract(tarinfo, path) |
457 | + |
458 | + # Reverse sort directories. |
459 | + if sys.version_info < (2, 4): |
460 | + def sorter(dir1, dir2): |
461 | + return cmp(dir1.name, dir2.name) |
462 | + directories.sort(sorter) |
463 | + directories.reverse() |
464 | + else: |
465 | + directories.sort(key=operator.attrgetter('name'), reverse=True) |
466 | + |
467 | + # Set correct owner, mtime and filemode on directories. |
468 | + for tarinfo in directories: |
469 | + dirpath = os.path.join(path, tarinfo.name) |
470 | + try: |
471 | + self.chown(tarinfo, dirpath) |
472 | + self.utime(tarinfo, dirpath) |
473 | + self.chmod(tarinfo, dirpath) |
474 | + except ExtractError: |
475 | + e = sys.exc_info()[1] |
476 | + if self.errorlevel > 1: |
477 | + raise |
478 | + else: |
479 | + self._dbg(1, "tarfile: %s" % e) |
480 | + |
481 | +def _build_install_args(argv): |
482 | + install_args = [] |
483 | + user_install = '--user' in argv |
484 | + if user_install and sys.version_info < (2,6): |
485 | + log.warn("--user requires Python 2.6 or later") |
486 | + raise SystemExit(1) |
487 | + if user_install: |
488 | + install_args.append('--user') |
489 | + return install_args |
490 | + |
491 | +def main(argv, version=DEFAULT_VERSION): |
492 | + """Install or upgrade setuptools and EasyInstall""" |
493 | + tarball = download_setuptools() |
494 | + _install(tarball, _build_install_args(argv)) |
495 | + |
496 | + |
497 | +if __name__ == '__main__': |
498 | + main(sys.argv[1:]) |
499 | |
500 | === modified file 'lib/testresources/__init__.py' |
501 | --- lib/testresources/__init__.py 2011-05-03 18:38:27 +0000 |
502 | +++ lib/testresources/__init__.py 2012-05-11 19:59:18 +0000 |
503 | @@ -21,6 +21,7 @@ |
504 | import inspect |
505 | import operator |
506 | import unittest |
507 | +import collections |
508 | |
509 | |
510 | def test_suite(): |
511 | @@ -41,12 +42,12 @@ |
512 | No other edges are created. |
513 | """ |
514 | result = {} |
515 | - for from_node, from_prime_node in prime_node_mapping.iteritems(): |
516 | + for from_node, from_prime_node in prime_node_mapping.items(): |
517 | result[from_node] = {from_prime_node:0} |
518 | result[from_prime_node] = {from_node:0} |
519 | - for from_node, to_nodes in digraph.iteritems(): |
520 | + for from_node, to_nodes in digraph.items(): |
521 | from_prime = prime_node_mapping[from_node] |
522 | - for to_node, value in to_nodes.iteritems(): |
523 | + for to_node, value in to_nodes.items(): |
524 | to_prime = prime_node_mapping[to_node] |
525 | result[from_prime][to_node] = value |
526 | result[to_node][from_prime] = value |
527 | @@ -72,8 +73,8 @@ |
528 | # collect edges: every edge is present twice (due to the graph |
529 | # representation), so normalise. |
530 | edges = set() |
531 | - for from_node, to_nodes in graph.iteritems(): |
532 | - for to_node, value in to_nodes.iteritems(): |
533 | + for from_node, to_nodes in graph.items(): |
534 | + for to_node, value in to_nodes.items(): |
535 | edge = (value,) + tuple(sorted([from_node, to_node])) |
536 | edges.add(edge) |
537 | edges = list(edges) |
538 | @@ -87,7 +88,7 @@ |
539 | continue # already joined |
540 | # combine g1 and g2 into g1 |
541 | graphs -= 1 |
542 | - for from_node, to_nodes in g2.iteritems(): |
543 | + for from_node, to_nodes in g2.items(): |
544 | #remember its symmetric, don't need to do 'to'. |
545 | forest[from_node] = g1 |
546 | g1.setdefault(from_node, {}).update(to_nodes) |
547 | @@ -96,10 +97,10 @@ |
548 | g1[edge[2]][edge[1]] = edge[0] |
549 | # union the remaining graphs |
550 | _, result = forest.popitem() |
551 | - for _, g2 in forest.iteritems(): |
552 | + for _, g2 in forest.items(): |
553 | if g2 is result: # common case |
554 | continue |
555 | - for from_node, to_nodes in g2.iteritems(): |
556 | + for from_node, to_nodes in g2.items(): |
557 | result.setdefault(from_node, {}).update(to_nodes) |
558 | return result |
559 | |
560 | @@ -120,7 +121,7 @@ |
561 | for resource in resource_set: |
562 | edges.setdefault(resource, []).append(node) |
563 | # populate the adjacent members of nodes |
564 | - for node, connected in nodes.iteritems(): |
565 | + for node, connected in nodes.items(): |
566 | for resource in node: |
567 | connected.update(edges[resource]) |
568 | connected.discard(node) |
569 | @@ -361,7 +362,7 @@ |
570 | node = root |
571 | cycle = [node] |
572 | steps = 2 * (len(mst) - 1) |
573 | - for step in xrange(steps): |
574 | + for step in range(steps): |
575 | found = False |
576 | outgoing = None # For clearer debugging. |
577 | for outgoing in mst[node]: |
578 | @@ -438,7 +439,7 @@ |
579 | def _call_result_method_if_exists(self, result, methodname, *args): |
580 | """Call a method on a TestResult that may exist.""" |
581 | method = getattr(result, methodname, None) |
582 | - if callable(method): |
583 | + if isinstance(method, collections.Callable): |
584 | method(*args) |
585 | |
586 | def _clean_all(self, resource, result): |
587 | @@ -518,7 +519,7 @@ |
588 | for name, resource in self.resources: |
589 | dependency_resources[name] = resource.getResource() |
590 | resource = self.make(dependency_resources) |
591 | - for name, value in dependency_resources.items(): |
592 | + for name, value in list(dependency_resources.items()): |
593 | setattr(resource, name, value) |
594 | self._call_result_method_if_exists(result, "stopMakeResource", self) |
595 | return resource |
596 | |
597 | === modified file 'lib/testresources/tests/TestUtil.py' |
598 | --- lib/testresources/tests/TestUtil.py 2008-08-16 07:10:40 +0000 |
599 | +++ lib/testresources/tests/TestUtil.py 2012-05-11 19:59:18 +0000 |
600 | @@ -15,6 +15,7 @@ |
601 | # along with this program; if not, write to the Free Software |
602 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
603 | # |
604 | +from __future__ import print_function |
605 | |
606 | import sys |
607 | import logging |
608 | @@ -56,7 +57,7 @@ |
609 | visitor.visitSuite(test) |
610 | visitTests(test, visitor) |
611 | else: |
612 | - print "unvisitable non-unittest.TestCase element %r (%r)" % (test, test.__class__) |
613 | + print("unvisitable non-unittest.TestCase element %r (%r)" % (test, test.__class__)) |
614 | |
615 | |
616 | class TestSuite(unittest.TestSuite): |
617 | |
618 | === modified file 'lib/testresources/tests/test_resource_graph.py' |
619 | --- lib/testresources/tests/test_resource_graph.py 2010-02-26 22:40:43 +0000 |
620 | +++ lib/testresources/tests/test_resource_graph.py 2012-05-11 19:59:18 +0000 |
621 | @@ -132,8 +132,8 @@ |
622 | F:{ D:6}, |
623 | G:{ E:9}} |
624 | result = testresources._kruskals_graph_MST(graph) |
625 | - e_weight = sum(sum(row.itervalues()) for row in expected.itervalues()) |
626 | - r_weight = sum(sum(row.itervalues()) for row in result.itervalues()) |
627 | + e_weight = sum(sum(row.values()) for row in expected.values()) |
628 | + r_weight = sum(sum(row.values()) for row in result.values()) |
629 | self.assertEqual(e_weight, r_weight) |
630 | self.assertEqual(expected, |
631 | testresources._kruskals_graph_MST(graph)) |
632 | |
633 | === modified file 'lib/testresources/tests/test_resourced_test_case.py' |
634 | --- lib/testresources/tests/test_resourced_test_case.py 2011-05-04 22:08:24 +0000 |
635 | +++ lib/testresources/tests/test_resourced_test_case.py 2012-05-11 19:59:18 +0000 |
636 | @@ -129,7 +129,7 @@ |
637 | self.resourced_case.resources = [("foo", self.resource_manager)] |
638 | self.resourced_case.setUpResources() |
639 | self.resourced_case.tearDownResources() |
640 | - self.failIf(hasattr(self.resourced_case, "foo")) |
641 | + self.assertFalse(hasattr(self.resourced_case, "foo")) |
642 | |
643 | def testTearDownResourcesStopsUsingResource(self): |
644 | # tearDownResources records that there is one less use of each |
645 | @@ -158,5 +158,5 @@ |
646 | self.assertEqual(self.resourced_case.foo, self.resource) |
647 | self.assertEqual(self.resource_manager._uses, 1) |
648 | self.resourced_case.tearDown() |
649 | - self.failIf(hasattr(self.resourced_case, "foo")) |
650 | + self.assertFalse(hasattr(self.resourced_case, "foo")) |
651 | self.assertEqual(self.resource_manager._uses, 0) |
652 | |
653 | === modified file 'lib/testresources/tests/test_test_resource.py' |
654 | --- lib/testresources/tests/test_test_resource.py 2010-11-14 17:43:44 +0000 |
655 | +++ lib/testresources/tests/test_test_resource.py 2012-05-11 19:59:18 +0000 |
656 | @@ -127,7 +127,7 @@ |
657 | def testGetResourceReturnsMakeResource(self): |
658 | resource_manager = MockResource() |
659 | resource = resource_manager.getResource() |
660 | - self.assertEqual(resource_manager.make({}), resource) |
661 | + self.assertEqual(type(resource_manager.make({})), type(resource)) |
662 | |
663 | def testGetResourceIncrementsUses(self): |
664 | resource_manager = MockResource() |
665 | |
666 | === modified file 'setup.py' |
667 | --- setup.py 2012-01-27 04:59:50 +0000 |
668 | +++ setup.py 2012-05-11 19:59:18 +0000 |
669 | @@ -1,9 +1,13 @@ |
670 | #!/usr/bin/env python |
671 | |
672 | -from distutils.core import setup |
673 | +from distribute_setup import use_setuptools |
674 | +use_setuptools() |
675 | + |
676 | +from setuptools import setup |
677 | import os.path |
678 | |
679 | -description = file(os.path.join(os.path.dirname(__file__), 'README'), 'rb').read() |
680 | +description = open(os.path.join(os.path.dirname(__file__), 'README'), 'rb').read() |
681 | +description = description.decode('utf-8') |
682 | |
683 | setup(name="testresources", |
684 | version="0.2.5", |
685 | @@ -25,4 +29,10 @@ |
686 | 'Topic :: Software Development :: Quality Assurance', |
687 | 'Topic :: Software Development :: Testing', |
688 | ], |
689 | + extras_require = dict( |
690 | + test=[ |
691 | + 'testtools', |
692 | + ] |
693 | + ), |
694 | + test_suite="testresources.tests", |
695 | ) |
This seems to be much more than py3; whats the additional stuff for?
[and why would it be in-tree, it looks boilerplatey].
-Rob