OLD | NEW |
| (Empty) |
1 import unittest | |
2 from modulegraph import modulegraph | |
3 import pkg_resources | |
4 import os | |
5 import imp | |
6 import sys | |
7 import shutil | |
8 import warnings | |
9 from altgraph import Graph | |
10 import textwrap | |
11 import xml.etree.ElementTree as ET | |
12 import pickle | |
13 | |
14 try: | |
15 bytes | |
16 except NameError: | |
17 bytes = str | |
18 | |
19 try: | |
20 from StringIO import StringIO | |
21 except ImportError: | |
22 from io import StringIO | |
23 | |
24 TESTDATA = os.path.join( | |
25 os.path.dirname(os.path.abspath(__file__)), | |
26 "testdata", "nspkg") | |
27 | |
28 try: | |
29 expectedFailure = unittest.expectedFailure | |
30 except AttributeError: | |
31 import functools | |
32 def expectedFailure(function): | |
33 @functools.wraps(function) | |
34 def wrapper(*args, **kwds): | |
35 try: | |
36 function(*args, **kwds) | |
37 except AssertionError: | |
38 pass | |
39 | |
40 else: | |
41 self.fail("unexpected pass") | |
42 | |
43 class TestDependencyInfo (unittest.TestCase): | |
44 def test_pickling(self): | |
45 info = modulegraph.DependencyInfo(function=True, conditional=False, trye
xcept=True, fromlist=False) | |
46 for proto in range(pickle.HIGHEST_PROTOCOL + 1): | |
47 b = pickle.dumps(info, proto) | |
48 self.assertTrue(isinstance(b, bytes)) | |
49 | |
50 o = pickle.loads(b) | |
51 self.assertEqual(o, info) | |
52 | |
53 def test_merging(self): | |
54 info1 = modulegraph.DependencyInfo(function=True, conditional=False, try
except=True, fromlist=False) | |
55 info2 = modulegraph.DependencyInfo(function=False, conditional=True, try
except=True, fromlist=False) | |
56 self.assertEqual( | |
57 info1._merged(info2), modulegraph.DependencyInfo(function=True, cond
itional=True, tryexcept=True, fromlist=False)) | |
58 | |
59 info2 = modulegraph.DependencyInfo(function=False, conditional=True, try
except=False, fromlist=False) | |
60 self.assertEqual( | |
61 info1._merged(info2), modulegraph.DependencyInfo(function=True, cond
itional=True, tryexcept=True, fromlist=False)) | |
62 | |
63 info2 = modulegraph.DependencyInfo(function=False, conditional=False, tr
yexcept=False, fromlist=False) | |
64 self.assertEqual( | |
65 info1._merged(info2), modulegraph.DependencyInfo(function=False, con
ditional=False, tryexcept=False, fromlist=False)) | |
66 | |
67 info1 = modulegraph.DependencyInfo(function=True, conditional=False, try
except=True, fromlist=True) | |
68 self.assertEqual( | |
69 info1._merged(info2), modulegraph.DependencyInfo(function=False, con
ditional=False, tryexcept=False, fromlist=False)) | |
70 | |
71 info2 = modulegraph.DependencyInfo(function=False, conditional=False, tr
yexcept=False, fromlist=True) | |
72 self.assertEqual( | |
73 info1._merged(info2), modulegraph.DependencyInfo(function=False, con
ditional=False, tryexcept=False, fromlist=True)) | |
74 | |
75 | |
76 class TestFunctions (unittest.TestCase): | |
77 if not hasattr(unittest.TestCase, 'assertIsInstance'): | |
78 def assertIsInstance(self, obj, types): | |
79 self.assertTrue(isinstance(obj, types), '%r is not instance of %r'%(
obj, types)) | |
80 | |
81 def test_eval_str_tuple(self): | |
82 for v in [ | |
83 '()', | |
84 '("hello",)', | |
85 '("hello", "world")', | |
86 "('hello',)", | |
87 "('hello', 'world')", | |
88 "('hello', \"world\")", | |
89 ]: | |
90 | |
91 self.assertEqual(modulegraph._eval_str_tuple(v), eval(v)) | |
92 | |
93 self.assertRaises(ValueError, modulegraph._eval_str_tuple, "") | |
94 self.assertRaises(ValueError, modulegraph._eval_str_tuple, "'a'") | |
95 self.assertRaises(ValueError, modulegraph._eval_str_tuple, "'a', 'b'") | |
96 self.assertRaises(ValueError, modulegraph._eval_str_tuple, "('a', ('b',
'c'))") | |
97 self.assertRaises(ValueError, modulegraph._eval_str_tuple, "('a', ('b\",
'c'))") | |
98 | |
99 def test_namespace_package_path(self): | |
100 class DS (object): | |
101 def __init__(self, path, namespace_packages=None): | |
102 self.location = path | |
103 self._namespace_packages = namespace_packages | |
104 | |
105 def has_metadata(self, key): | |
106 if key == 'namespace_packages.txt': | |
107 return self._namespace_packages is not None | |
108 | |
109 raise ValueError("invalid lookup key") | |
110 | |
111 def get_metadata(self, key): | |
112 if key == 'namespace_packages.txt': | |
113 if self._namespace_packages is None: | |
114 raise ValueError("no file") | |
115 | |
116 return self._namespace_packages | |
117 | |
118 raise ValueError("invalid lookup key") | |
119 | |
120 class WS (object): | |
121 def __init__(self, path=None): | |
122 pass | |
123 | |
124 def __iter__(self): | |
125 yield DS("/pkg/pkg1") | |
126 yield DS("/pkg/pkg2", "foo\n") | |
127 yield DS("/pkg/pkg3", "bar.baz\n") | |
128 yield DS("/pkg/pkg4", "foobar\nfoo\n") | |
129 | |
130 saved_ws = pkg_resources.WorkingSet | |
131 try: | |
132 pkg_resources.WorkingSet = WS | |
133 | |
134 self.assertEqual(modulegraph._namespace_package_path("sys", ["appdir
/pkg"]), ["appdir/pkg"]) | |
135 self.assertEqual(modulegraph._namespace_package_path("foo", ["appdir
/pkg"]), ["appdir/pkg", "/pkg/pkg2/foo", "/pkg/pkg4/foo"]) | |
136 self.assertEqual(modulegraph._namespace_package_path("bar.baz", ["ap
pdir/pkg"]), ["appdir/pkg", "/pkg/pkg3/bar/baz"]) | |
137 | |
138 finally: | |
139 pkg_resources.WorkingSet = saved_ws | |
140 | |
141 def test_os_listdir(self): | |
142 root = os.path.join( | |
143 os.path.dirname(os.path.abspath(__file__)), 'testdata') | |
144 | |
145 self.assertEqual(modulegraph.os_listdir('/etc/'), os.listdir('/etc')) | |
146 self.assertRaises(IOError, modulegraph.os_listdir, '/etc/hosts/foobar') | |
147 self.assertRaises(IOError, modulegraph.os_listdir, os.path.join(root, 't
est.egg', 'bar')) | |
148 | |
149 self.assertEqual(list(sorted(modulegraph.os_listdir(os.path.join(root, '
test.egg', 'foo')))), | |
150 [ 'bar', 'bar.txt', 'baz.txt' ]) | |
151 | |
152 def test_code_to_file(self): | |
153 try: | |
154 code = modulegraph._code_to_file.__code__ | |
155 except AttributeError: | |
156 code = modulegraph._code_to_file.func_code | |
157 | |
158 data = modulegraph._code_to_file(code) | |
159 self.assertTrue(hasattr(data, 'read')) | |
160 | |
161 content = data.read() | |
162 self.assertIsInstance(content, bytes) | |
163 data.close() | |
164 | |
165 def test_find_module(self): | |
166 for path in ('syspath', 'syspath.zip', 'syspath.egg'): | |
167 path = os.path.join(os.path.dirname(TESTDATA), path) | |
168 if os.path.exists(os.path.join(path, 'mymodule.pyc')): | |
169 os.unlink(os.path.join(path, 'mymodule.pyc')) | |
170 | |
171 # Plain module | |
172 info = modulegraph.find_module('mymodule', path=[path] + sys.path) | |
173 | |
174 fp = info[0] | |
175 filename = info[1] | |
176 description = info[2] | |
177 | |
178 self.assertTrue(hasattr(fp, 'read')) | |
179 | |
180 if path.endswith('.zip') or path.endswith('.egg'): | |
181 # Zip importers may precompile | |
182 if filename.endswith('.py'): | |
183 self.assertEqual(filename, os.path.join(path, 'mymodule.py')
) | |
184 self.assertEqual(description, ('.py', 'rU', imp.PY_SOURCE)) | |
185 | |
186 else: | |
187 self.assertEqual(filename, os.path.join(path, 'mymodule.pyc'
)) | |
188 self.assertEqual(description, ('.pyc', 'rb', imp.PY_COMPILED
)) | |
189 | |
190 else: | |
191 self.assertEqual(filename, os.path.join(path, 'mymodule.py')) | |
192 self.assertEqual(description, ('.py', 'rU', imp.PY_SOURCE)) | |
193 | |
194 # Compiled plain module, no source | |
195 if path.endswith('.zip') or path.endswith('.egg'): | |
196 self.assertRaises(ImportError, modulegraph.find_module, 'mymodul
e2', path=[path] + sys.path) | |
197 | |
198 else: | |
199 info = modulegraph.find_module('mymodule2', path=[path] + sys.pa
th) | |
200 | |
201 fp = info[0] | |
202 filename = info[1] | |
203 description = info[2] | |
204 | |
205 self.assertTrue(hasattr(fp, 'read')) | |
206 self.assertEqual(filename, os.path.join(path, 'mymodule2.pyc')) | |
207 self.assertEqual(description, ('.pyc', 'rb', imp.PY_COMPILED)) | |
208 | |
209 fp.close() | |
210 | |
211 # Compiled plain module, with source | |
212 # info = modulegraph.find_module('mymodule3', path=[path] + sys.path) | |
213 # | |
214 # fp = info[0] | |
215 # filename = info[1] | |
216 # description = info[2] | |
217 # | |
218 # self.assertTrue(hasattr(fp, 'read')) | |
219 # | |
220 # if sys.version_info[:2] >= (3,2): | |
221 # self.assertEqual(filename, os.path.join(path, '__pycache__', 'm
ymodule3.cpython-32.pyc')) | |
222 # else: | |
223 # self.assertEqual(filename, os.path.join(path, 'mymodule3.pyc')) | |
224 # self.assertEqual(description, ('.pyc', 'rb', imp.PY_COMPILED)) | |
225 | |
226 | |
227 # Package | |
228 info = modulegraph.find_module('mypkg', path=[path] + sys.path) | |
229 fp = info[0] | |
230 filename = info[1] | |
231 description = info[2] | |
232 | |
233 self.assertEqual(fp, None) | |
234 self.assertEqual(filename, os.path.join(path, 'mypkg')) | |
235 self.assertEqual(description, ('', '', imp.PKG_DIRECTORY)) | |
236 | |
237 # Extension | |
238 if path.endswith('.zip'): | |
239 self.assertRaises(ImportError, modulegraph.find_module, 'myext',
path=[path] + sys.path) | |
240 | |
241 else: | |
242 info = modulegraph.find_module('myext', path=[path] + sys.path) | |
243 fp = info[0] | |
244 filename = info[1] | |
245 description = info[2] | |
246 | |
247 if sys.platform == 'win32': | |
248 ext = '.pyd' | |
249 else: | |
250 # This is a ly, but is good enough for now | |
251 ext = '.so' | |
252 | |
253 self.assertEqual(filename, os.path.join(path, 'myext' + ext)) | |
254 self.assertEqual(description, (ext, 'rb', imp.C_EXTENSION)) | |
255 self.assertEqual(fp, None) | |
256 | |
257 def test_moduleInfoForPath(self): | |
258 self.assertEqual(modulegraph.moduleInfoForPath("/somewhere/else/file.txt
"), None) | |
259 | |
260 info = modulegraph.moduleInfoForPath("/somewhere/else/file.py") | |
261 self.assertEqual(info[0], "file") | |
262 if sys.version_info[:2] >= (3,4): | |
263 self.assertEqual(info[1], "r") | |
264 else: | |
265 self.assertEqual(info[1], "U") | |
266 self.assertEqual(info[2], imp.PY_SOURCE) | |
267 | |
268 info = modulegraph.moduleInfoForPath("/somewhere/else/file.pyc") | |
269 self.assertEqual(info[0], "file") | |
270 self.assertEqual(info[1], "rb") | |
271 self.assertEqual(info[2], imp.PY_COMPILED) | |
272 | |
273 if sys.platform in ('darwin', 'linux2'): | |
274 info = modulegraph.moduleInfoForPath("/somewhere/else/file.so") | |
275 self.assertEqual(info[0], "file") | |
276 self.assertEqual(info[1], "rb") | |
277 self.assertEqual(info[2], imp.C_EXTENSION) | |
278 | |
279 elif sys.platform in ('win32',): | |
280 info = modulegraph.moduleInfoForPath("/somewhere/else/file.pyd") | |
281 self.assertEqual(info[0], "file") | |
282 self.assertEqual(info[1], "rb") | |
283 self.assertEqual(info[2], imp.C_EXTENSION) | |
284 | |
285 if sys.version_info[:2] > (2,5): | |
286 exec(textwrap.dedent('''\ | |
287 def test_deprecated(self): | |
288 saved_add = modulegraph.addPackagePath | |
289 saved_replace = modulegraph.replacePackage | |
290 try: | |
291 called = [] | |
292 | |
293 def log_add(*args, **kwds): | |
294 called.append(('add', args, kwds)) | |
295 def log_replace(*args, **kwds): | |
296 called.append(('replace', args, kwds)) | |
297 | |
298 modulegraph.addPackagePath = log_add | |
299 modulegraph.replacePackage = log_replace | |
300 | |
301 with warnings.catch_warnings(record=True) as w: | |
302 warnings.simplefilter("always") | |
303 modulegraph.ReplacePackage('a', 'b') | |
304 modulegraph.AddPackagePath('c', 'd') | |
305 | |
306 self.assertEqual(len(w), 2) | |
307 self.assertTrue(w[-1].category is DeprecationWarning) | |
308 self.assertTrue(w[-2].category is DeprecationWarning) | |
309 | |
310 self.assertEqual(called, [ | |
311 ('replace', ('a', 'b'), {}), | |
312 ('add', ('c', 'd'), {}), | |
313 ]) | |
314 | |
315 finally: | |
316 modulegraph.addPackagePath = saved_add | |
317 modulegraph.replacePackage = saved_replace | |
318 '''), locals(), globals()) | |
319 | |
320 def test_addPackage(self): | |
321 saved = modulegraph._packagePathMap | |
322 self.assertIsInstance(saved, dict) | |
323 try: | |
324 modulegraph._packagePathMap = {} | |
325 | |
326 modulegraph.addPackagePath('foo', 'a') | |
327 self.assertEqual(modulegraph._packagePathMap, { 'foo': ['a'] }) | |
328 | |
329 modulegraph.addPackagePath('foo', 'b') | |
330 self.assertEqual(modulegraph._packagePathMap, { 'foo': ['a', 'b'] }) | |
331 | |
332 modulegraph.addPackagePath('bar', 'b') | |
333 self.assertEqual(modulegraph._packagePathMap, { 'foo': ['a', 'b'], '
bar': ['b'] }) | |
334 | |
335 finally: | |
336 modulegraph._packagePathMap = saved | |
337 | |
338 | |
339 def test_replacePackage(self): | |
340 saved = modulegraph._replacePackageMap | |
341 self.assertIsInstance(saved, dict) | |
342 try: | |
343 modulegraph._replacePackageMap = {} | |
344 | |
345 modulegraph.replacePackage("a", "b") | |
346 self.assertEqual(modulegraph._replacePackageMap, {"a": "b"}) | |
347 modulegraph.replacePackage("a", "c") | |
348 self.assertEqual(modulegraph._replacePackageMap, {"a": "c"}) | |
349 modulegraph.replacePackage("b", "c") | |
350 self.assertEqual(modulegraph._replacePackageMap, {"a": "c", 'b': 'c'
}) | |
351 | |
352 finally: | |
353 modulegraph._replacePackageMap = saved | |
354 | |
355 class TestNode (unittest.TestCase): | |
356 if not hasattr(unittest.TestCase, 'assertIsInstance'): | |
357 def assertIsInstance(self, obj, types): | |
358 self.assertTrue(isinstance(obj, types), '%r is not instance of %r'%(
obj, types)) | |
359 def testBasicAttributes(self): | |
360 n = modulegraph.Node("foobar.xyz") | |
361 self.assertIsInstance(n.debug, int) | |
362 self.assertEqual(n.identifier, n.graphident) | |
363 self.assertEqual(n.identifier, 'foobar.xyz') | |
364 self.assertEqual(n.filename, None) | |
365 self.assertEqual(n.packagepath, None) | |
366 self.assertEqual(n.code, None) | |
367 self.assertEqual(n.globalnames, set()) | |
368 self.assertEqual(n.starimports, set()) | |
369 | |
370 def testMapping(self): | |
371 n = modulegraph.Node("foobar.xyz") | |
372 self.assertEqual(n._namespace, {}) | |
373 | |
374 self.assertFalse('foo' in n) | |
375 self.assertRaises(KeyError, n.__getitem__, 'foo') | |
376 self.assertEqual(n.get('foo'), None) | |
377 self.assertEqual(n.get('foo', 'a'), 'a') | |
378 n['foo'] = 42 | |
379 self.assertEqual(n['foo'], 42) | |
380 self.assertTrue('foo' in n) | |
381 self.assertEqual(n._namespace, {'foo':42}) | |
382 | |
383 def testOrder(self): | |
384 n1 = modulegraph.Node("n1") | |
385 n2 = modulegraph.Node("n2") | |
386 | |
387 self.assertTrue(n1 < n2) | |
388 self.assertFalse(n2 < n1) | |
389 self.assertTrue(n1 <= n1) | |
390 self.assertFalse(n1 == n2) | |
391 self.assertTrue(n1 == n1) | |
392 self.assertTrue(n1 != n2) | |
393 self.assertFalse(n1 != n1) | |
394 self.assertTrue(n2 > n1) | |
395 self.assertFalse(n1 > n2) | |
396 self.assertTrue(n1 >= n1) | |
397 self.assertTrue(n2 >= n1) | |
398 | |
399 def testHashing(self): | |
400 n1a = modulegraph.Node('n1') | |
401 n1b = modulegraph.Node('n1') | |
402 n2 = modulegraph.Node('n2') | |
403 | |
404 d = {} | |
405 d[n1a] = 'n1' | |
406 d[n2] = 'n2' | |
407 self.assertEqual(d[n1b], 'n1') | |
408 self.assertEqual(d[n2], 'n2') | |
409 | |
410 def test_infoTuple(self): | |
411 n = modulegraph.Node('n1') | |
412 self.assertEqual(n.infoTuple(), ('n1',)) | |
413 | |
414 def assertNoMethods(self, klass): | |
415 d = dict(klass.__dict__) | |
416 del d['__doc__'] | |
417 del d['__module__'] | |
418 if '__qualname__' in d: | |
419 # New in Python 3.3 | |
420 del d['__qualname__'] | |
421 if '__dict__' in d: | |
422 # New in Python 3.4 | |
423 del d['__dict__'] | |
424 self.assertEqual(d, {}) | |
425 | |
426 def assertHasExactMethods(self, klass, *methods): | |
427 d = dict(klass.__dict__) | |
428 del d['__doc__'] | |
429 del d['__module__'] | |
430 if '__qualname__' in d: | |
431 # New in Python 3.3 | |
432 del d['__qualname__'] | |
433 if '__dict__' in d: | |
434 # New in Python 3.4 | |
435 del d['__dict__'] | |
436 | |
437 for nm in methods: | |
438 self.assertTrue(nm in d, "%s doesn't have attribute %r"%(klass, nm)) | |
439 del d[nm] | |
440 | |
441 self.assertEqual(d, {}) | |
442 | |
443 | |
444 if not hasattr(unittest.TestCase, 'assertIsSubclass'): | |
445 def assertIsSubclass(self, cls1, cls2, message=None): | |
446 self.assertTrue(issubclass(cls1, cls2), | |
447 message or "%r is not a subclass of %r"%(cls1, cls2)) | |
448 | |
449 def test_subclasses(self): | |
450 self.assertIsSubclass(modulegraph.AliasNode, modulegraph.Node) | |
451 self.assertIsSubclass(modulegraph.Script, modulegraph.Node) | |
452 self.assertIsSubclass(modulegraph.BadModule, modulegraph.Node) | |
453 self.assertIsSubclass(modulegraph.ExcludedModule, modulegraph.BadModule) | |
454 self.assertIsSubclass(modulegraph.MissingModule, modulegraph.BadModule) | |
455 self.assertIsSubclass(modulegraph.BaseModule, modulegraph.Node) | |
456 self.assertIsSubclass(modulegraph.BuiltinModule, modulegraph.BaseModule) | |
457 self.assertIsSubclass(modulegraph.SourceModule, modulegraph.BaseModule) | |
458 self.assertIsSubclass(modulegraph.CompiledModule, modulegraph.BaseModule
) | |
459 self.assertIsSubclass(modulegraph.Package, modulegraph.BaseModule) | |
460 self.assertIsSubclass(modulegraph.Extension, modulegraph.BaseModule) | |
461 | |
462 # These classes have no new functionality, check that no code | |
463 # got added: | |
464 self.assertNoMethods(modulegraph.BadModule) | |
465 self.assertNoMethods(modulegraph.ExcludedModule) | |
466 self.assertNoMethods(modulegraph.MissingModule) | |
467 self.assertNoMethods(modulegraph.BuiltinModule) | |
468 self.assertNoMethods(modulegraph.SourceModule) | |
469 self.assertNoMethods(modulegraph.CompiledModule) | |
470 self.assertNoMethods(modulegraph.Package) | |
471 self.assertNoMethods(modulegraph.Extension) | |
472 | |
473 # AliasNode is basicly a clone of an existing node | |
474 self.assertHasExactMethods(modulegraph.Script, '__init__', 'infoTuple') | |
475 n1 = modulegraph.Node('n1') | |
476 n1.packagepath = ['a', 'b'] | |
477 | |
478 a1 = modulegraph.AliasNode('a1', n1) | |
479 self.assertEqual(a1.graphident, 'a1') | |
480 self.assertEqual(a1.identifier, 'n1') | |
481 self.assertTrue(a1.packagepath is n1.packagepath) | |
482 self.assertTrue(a1._namespace is n1._namespace) | |
483 self.assertTrue(a1.globalnames is n1.globalnames) | |
484 self.assertTrue(a1.starimports is n1.starimports) | |
485 | |
486 v = a1.infoTuple() | |
487 self.assertEqual(v, ('a1', 'n1')) | |
488 | |
489 # Scripts have a filename | |
490 self.assertHasExactMethods(modulegraph.Script, '__init__', 'infoTuple') | |
491 s1 = modulegraph.Script('do_import') | |
492 self.assertEqual(s1.graphident, 'do_import') | |
493 self.assertEqual(s1.identifier, 'do_import') | |
494 self.assertEqual(s1.filename, 'do_import') | |
495 | |
496 v = s1.infoTuple() | |
497 self.assertEqual(v, ('do_import',)) | |
498 | |
499 # BaseModule adds some attributes and a custom infotuple | |
500 self.assertHasExactMethods(modulegraph.BaseModule, '__init__', 'infoTupl
e') | |
501 m1 = modulegraph.BaseModule('foo') | |
502 self.assertEqual(m1.graphident, 'foo') | |
503 self.assertEqual(m1.identifier, 'foo') | |
504 self.assertEqual(m1.filename, None) | |
505 self.assertEqual(m1.packagepath, None) | |
506 | |
507 m1 = modulegraph.BaseModule('foo', 'bar', ['a']) | |
508 self.assertEqual(m1.graphident, 'foo') | |
509 self.assertEqual(m1.identifier, 'foo') | |
510 self.assertEqual(m1.filename, 'bar') | |
511 self.assertEqual(m1.packagepath, ['a']) | |
512 | |
513 class TestModuleGraph (unittest.TestCase): | |
514 # Test for class modulegraph.modulegraph.ModuleGraph | |
515 if not hasattr(unittest.TestCase, 'assertIsInstance'): | |
516 def assertIsInstance(self, obj, types): | |
517 self.assertTrue(isinstance(obj, types), '%r is not instance of %r'%(
obj, types)) | |
518 | |
519 def test_constructor(self): | |
520 o = modulegraph.ModuleGraph() | |
521 self.assertTrue(o.path is sys.path) | |
522 self.assertEqual(o.lazynodes, {}) | |
523 self.assertEqual(o.replace_paths, ()) | |
524 self.assertEqual(o.debug, 0) | |
525 | |
526 # Stricter tests would be nice, but that requires | |
527 # better control over what's on sys.path | |
528 self.assertIsInstance(o.nspackages, dict) | |
529 | |
530 g = Graph.Graph() | |
531 o = modulegraph.ModuleGraph(['a', 'b', 'c'], ['modA'], [ | |
532 ('fromA', 'toB'), ('fromC', 'toD')], | |
533 { | |
534 'modA': ['modB', 'modC'], | |
535 'modC': ['modE', 'modF'], | |
536 }, g, 1) | |
537 self.assertEqual(o.path, ['a', 'b', 'c']) | |
538 self.assertEqual(o.lazynodes, { | |
539 'modA': None, | |
540 'modC': ['modE', 'modF'], | |
541 }) | |
542 self.assertEqual(o.replace_paths, [('fromA', 'toB'), ('fromC', 'toD')]) | |
543 self.assertEqual(o.nspackages, {}) | |
544 self.assertTrue(o.graph is g) | |
545 self.assertEqual(o.debug, 1) | |
546 | |
547 def test_calc_setuptools_nspackages(self): | |
548 stdlib = [ fn for fn in sys.path if fn.startswith(sys.prefix) and 'site-
packages' not in fn ] | |
549 for subdir in [ nm for nm in os.listdir(TESTDATA) if nm != 'src' ]: | |
550 graph = modulegraph.ModuleGraph(path=[ | |
551 os.path.join(TESTDATA, subdir, "parent"), | |
552 os.path.join(TESTDATA, subdir, "child"), | |
553 ] + stdlib) | |
554 | |
555 pkgs = graph.nspackages | |
556 self.assertTrue('namedpkg' in pkgs) | |
557 self.assertEqual(set(pkgs['namedpkg']), | |
558 set([ | |
559 os.path.join(TESTDATA, subdir, "parent", "namedpkg"), | |
560 os.path.join(TESTDATA, subdir, "child", "namedpkg"), | |
561 ])) | |
562 self.assertFalse(os.path.exists(os.path.join(TESTDATA, subdir, "pare
nt", "namedpkg", "__init__.py"))) | |
563 self.assertFalse(os.path.exists(os.path.join(TESTDATA, subdir, "chil
d", "namedpkg", "__init__.py"))) | |
564 | |
565 def testImpliedReference(self): | |
566 graph = modulegraph.ModuleGraph() | |
567 | |
568 record = [] | |
569 def import_hook(*args): | |
570 record.append(('import_hook',) + args) | |
571 return [graph.createNode(modulegraph.Node, args[0])] | |
572 | |
573 def _safe_import_hook(*args): | |
574 record.append(('_safe_import_hook',) + args) | |
575 return [graph.createNode(modulegraph.Node, args[0])] | |
576 | |
577 graph.import_hook = import_hook | |
578 graph._safe_import_hook = _safe_import_hook | |
579 | |
580 n1 = graph.createNode(modulegraph.Node, 'n1') | |
581 n2 = graph.createNode(modulegraph.Node, 'n2') | |
582 | |
583 graph.implyNodeReference(n1, n2) | |
584 outs, ins = map(list, graph.get_edges(n1)) | |
585 self.assertEqual(outs, [n2]) | |
586 self.assertEqual(ins, []) | |
587 | |
588 self.assertEqual(record, []) | |
589 | |
590 graph.implyNodeReference(n2, "n3") | |
591 n3 = graph.findNode('n3') | |
592 outs, ins = map(list, graph.get_edges(n2)) | |
593 self.assertEqual(outs, [n3]) | |
594 self.assertEqual(ins, [n1]) | |
595 self.assertEqual(record, [ | |
596 ('_safe_import_hook', 'n3', n2, None) | |
597 ]) | |
598 | |
599 | |
600 | |
601 @expectedFailure | |
602 def test_findNode(self): | |
603 self.fail("findNode") | |
604 | |
605 def test_run_script(self): | |
606 script = os.path.join(os.path.dirname(TESTDATA), 'script') | |
607 | |
608 graph = modulegraph.ModuleGraph() | |
609 master = graph.createNode(modulegraph.Node, 'root') | |
610 m = graph.run_script(script, master) | |
611 self.assertEqual(list(graph.get_edges(master)[0])[0], m) | |
612 self.assertEqual(set(graph.get_edges(m)[0]), set([ | |
613 graph.findNode('sys'), | |
614 graph.findNode('os'), | |
615 ])) | |
616 | |
617 @expectedFailure | |
618 def test_import_hook(self): | |
619 self.fail("import_hook") | |
620 | |
621 def test_determine_parent(self): | |
622 graph = modulegraph.ModuleGraph() | |
623 graph.import_hook('os.path', None) | |
624 graph.import_hook('idlelib', None) | |
625 graph.import_hook('xml.dom', None) | |
626 | |
627 for node in graph.nodes(): | |
628 if isinstance(node, modulegraph.Package): | |
629 break | |
630 else: | |
631 self.fail("No package located, should have at least 'os'") | |
632 | |
633 self.assertIsInstance(node, modulegraph.Package) | |
634 parent = graph._determine_parent(node) | |
635 self.assertEqual(parent.identifier, node.identifier) | |
636 self.assertEqual(parent, graph.findNode(node.identifier)) | |
637 self.assertTrue(isinstance(parent, modulegraph.Package)) | |
638 | |
639 # XXX: Might be a usecase for some odd code in determine_parent... | |
640 #node = modulegraph.Package('encodings') | |
641 #node.packagepath = parent.packagepath | |
642 #m = graph._determine_parent(node) | |
643 #self.assertTrue(m is parent) | |
644 | |
645 m = graph.findNode('xml') | |
646 self.assertEqual(graph._determine_parent(m), m) | |
647 | |
648 m = graph.findNode('xml.dom') | |
649 self.assertEqual(graph._determine_parent(m), graph.findNode('xml.dom')) | |
650 | |
651 | |
652 @expectedFailure | |
653 def test_find_head_package(self): | |
654 self.fail("find_head_package") | |
655 | |
656 def test_load_tail(self): | |
657 # XXX: This test is dodgy! | |
658 graph = modulegraph.ModuleGraph() | |
659 | |
660 record = [] | |
661 def _import_module(partname, fqname, parent): | |
662 record.append((partname, fqname, parent)) | |
663 if partname == 'raises' or '.raises.' in fqname: | |
664 return None | |
665 return modulegraph.Node(fqname) | |
666 | |
667 graph._import_module = _import_module | |
668 | |
669 record = [] | |
670 root = modulegraph.Node('root') | |
671 m = graph._load_tail(root, '') | |
672 self.assertTrue(m is root) | |
673 self.assertEqual(record, [ | |
674 ]) | |
675 | |
676 record = [] | |
677 root = modulegraph.Node('root') | |
678 m = graph._load_tail(root, 'sub') | |
679 self.assertFalse(m is root) | |
680 self.assertEqual(record, [ | |
681 ('sub', 'root.sub', root), | |
682 ]) | |
683 | |
684 record = [] | |
685 root = modulegraph.Node('root') | |
686 m = graph._load_tail(root, 'sub.sub1') | |
687 self.assertFalse(m is root) | |
688 node = modulegraph.Node('root.sub') | |
689 self.assertEqual(record, [ | |
690 ('sub', 'root.sub', root), | |
691 ('sub1', 'root.sub.sub1', node), | |
692 ]) | |
693 | |
694 record = [] | |
695 root = modulegraph.Node('root') | |
696 m = graph._load_tail(root, 'sub.sub1.sub2') | |
697 self.assertFalse(m is root) | |
698 node = modulegraph.Node('root.sub') | |
699 node2 = modulegraph.Node('root.sub.sub1') | |
700 self.assertEqual(record, [ | |
701 ('sub', 'root.sub', root), | |
702 ('sub1', 'root.sub.sub1', node), | |
703 ('sub2', 'root.sub.sub1.sub2', node2), | |
704 ]) | |
705 | |
706 n = graph._load_tail(root, 'raises') | |
707 self.assertIsInstance(n, modulegraph.MissingModule) | |
708 self.assertEqual(n.identifier, 'root.raises') | |
709 | |
710 n = graph._load_tail(root, 'sub.raises') | |
711 self.assertIsInstance(n, modulegraph.MissingModule) | |
712 self.assertEqual(n.identifier, 'root.sub.raises') | |
713 | |
714 n = graph._load_tail(root, 'sub.raises.sub') | |
715 self.assertIsInstance(n, modulegraph.MissingModule) | |
716 self.assertEqual(n.identifier, 'root.sub.raises.sub') | |
717 | |
718 | |
719 | |
720 @expectedFailure | |
721 def test_ensure_fromlist(self): | |
722 # 1. basic 'from module import name, name' | |
723 # 2. 'from module import *' | |
724 # 3. from module import os | |
725 # (where 'os' is not a name in 'module', | |
726 # should create MissingModule node, and | |
727 # should *not* refer to the global os) | |
728 self.fail("ensure_fromlist") | |
729 | |
730 @expectedFailure | |
731 def test_find_all_submodules(self): | |
732 # 1. basic | |
733 # 2. no packagepath (basic module) | |
734 # 3. extensions, python modules | |
735 # 4. with/without zipfile | |
736 # 5. files that aren't python modules/extensions | |
737 self.fail("find_all_submodules") | |
738 | |
739 @expectedFailure | |
740 def test_import_module(self): | |
741 self.fail("import_module") | |
742 | |
743 @expectedFailure | |
744 def test_load_module(self): | |
745 self.fail("load_module") | |
746 | |
747 @expectedFailure | |
748 def test_safe_import_hook(self): | |
749 self.fail("safe_import_hook") | |
750 | |
751 @expectedFailure | |
752 def test_scan_code(self): | |
753 mod = modulegraph.Node('root') | |
754 | |
755 graph = modulegraph.ModuleGraph() | |
756 code = compile('', '<test>', 'exec', 0, False) | |
757 graph.scan_code(code, mod) | |
758 self.assertEqual(list(graph.nodes()), []) | |
759 | |
760 node_map = {} | |
761 def _safe_import(name, mod, fromlist, level): | |
762 if name in node_map: | |
763 node = node_map[name] | |
764 else: | |
765 node = modulegraph.Node(name) | |
766 node_map[name] = node | |
767 return [node] | |
768 | |
769 graph = modulegraph.ModuleGraph() | |
770 graph._safe_import_hook = _safe_import | |
771 | |
772 code = compile(textwrap.dedent('''\ | |
773 import sys | |
774 import os.path | |
775 | |
776 def testfunc(): | |
777 import shutil | |
778 '''), '<test>', 'exec', 0, False) | |
779 graph.scan_code(code, mod) | |
780 modules = [node.identifier for node in graph.nodes()] | |
781 self.assertEqual(set(node_map), set(['sys', 'os.path', 'shutil'])) | |
782 | |
783 | |
784 # from module import a, b, c | |
785 # from module import * | |
786 # both: | |
787 # -> with/without globals | |
788 # -> with/without modules in globals (e.g, | |
789 # from os import * adds dependency to os.path) | |
790 # from .module import a | |
791 # from ..module import a | |
792 # -> check levels | |
793 # import name | |
794 # import a.b | |
795 # -> should add dependency to a | |
796 # try to build case where commented out | |
797 # code would behave different than current code | |
798 # (Carbon.SomeMod contains 'import Sibling' seems | |
799 # to cause difference in real code) | |
800 | |
801 self.fail("actual test needed") | |
802 | |
803 | |
804 | |
805 @expectedFailure | |
806 def test_load_package(self): | |
807 self.fail("load_package") | |
808 | |
809 def test_find_module(self): | |
810 record = [] | |
811 def mock_finder(name, path): | |
812 record.append((name, path)) | |
813 return saved_finder(name, path) | |
814 | |
815 saved_finder = modulegraph.find_module | |
816 try: | |
817 modulegraph.find_module = mock_finder | |
818 | |
819 graph = modulegraph.ModuleGraph() | |
820 m = graph._find_module('sys', None) | |
821 self.assertEqual(record, []) | |
822 self.assertEqual(m, (None, None, ("", "", imp.C_BUILTIN))) | |
823 | |
824 modulegraph.find_module = saved_finder | |
825 xml = graph.import_hook("xml")[0] | |
826 self.assertEqual(xml.identifier, 'xml') | |
827 modulegraph.find_module = mock_finder | |
828 | |
829 self.assertRaises(ImportError, graph._find_module, 'xml', None) | |
830 | |
831 self.assertEqual(record, []) | |
832 m = graph._find_module('shutil', None) | |
833 self.assertEqual(record, [ | |
834 ('shutil', graph.path), | |
835 ]) | |
836 self.assertTrue(isinstance(m, tuple)) | |
837 self.assertEqual(len(m), 3) | |
838 self.assertTrue(hasattr(m[0], 'read')) | |
839 self.assertIsInstance(m[0].read(), str) | |
840 srcfn = shutil.__file__ | |
841 if srcfn.endswith('.pyc'): | |
842 srcfn = srcfn[:-1] | |
843 self.assertEqual(m[1], srcfn) | |
844 self.assertEqual(m[2], ('.py', 'rU', imp.PY_SOURCE)) | |
845 m[0].close() | |
846 | |
847 m2 = graph._find_module('shutil', None) | |
848 self.assertEqual(m[1:], m2[1:]) | |
849 m2[0].close() | |
850 | |
851 | |
852 record[:] = [] | |
853 m = graph._find_module('sax', xml.packagepath, xml) | |
854 self.assertEqual(m, | |
855 (None, os.path.join(os.path.dirname(xml.filename), 'sax'), | |
856 ('', '', imp.PKG_DIRECTORY))) | |
857 self.assertEqual(record, [ | |
858 ('sax', xml.packagepath), | |
859 ]) | |
860 if m[0] is not None: m[0].close() | |
861 | |
862 finally: | |
863 modulegraph.find_module = saved_finder | |
864 | |
865 @expectedFailure | |
866 def test_create_xref(self): | |
867 self.fail("create_xref") | |
868 | |
869 @expectedFailure | |
870 def test_itergraphreport(self): | |
871 self.fail("itergraphreport") | |
872 | |
873 def test_report(self): | |
874 graph = modulegraph.ModuleGraph() | |
875 | |
876 saved_stdout = sys.stdout | |
877 try: | |
878 fp = sys.stdout = StringIO() | |
879 graph.report() | |
880 lines = fp.getvalue().splitlines() | |
881 fp.close() | |
882 | |
883 self.assertEqual(len(lines), 3) | |
884 self.assertEqual(lines[0], '') | |
885 self.assertEqual(lines[1], 'Class Name
File') | |
886 self.assertEqual(lines[2], '----- ----
----') | |
887 | |
888 fp = sys.stdout = StringIO() | |
889 graph._safe_import_hook('os', None, ()) | |
890 graph._safe_import_hook('sys', None, ()) | |
891 graph._safe_import_hook('nomod', None, ()) | |
892 graph.report() | |
893 lines = fp.getvalue().splitlines() | |
894 fp.close() | |
895 | |
896 self.assertEqual(lines[0], '') | |
897 self.assertEqual(lines[1], 'Class Name
File') | |
898 self.assertEqual(lines[2], '----- ----
----') | |
899 expected = [] | |
900 for n in graph.flatten(): | |
901 if n.filename: | |
902 expected.append([type(n).__name__, n.identifier, n.filename]
) | |
903 else: | |
904 expected.append([type(n).__name__, n.identifier]) | |
905 | |
906 expected.sort() | |
907 actual = [item.split() for item in lines[3:]] | |
908 actual.sort() | |
909 self.assertEqual(expected, actual) | |
910 | |
911 | |
912 finally: | |
913 sys.stdout = saved_stdout | |
914 | |
915 def test_graphreport(self): | |
916 | |
917 def my_iter(flatpackages="packages"): | |
918 yield "line1\n" | |
919 yield str(flatpackages) + "\n" | |
920 yield "line2\n" | |
921 | |
922 graph = modulegraph.ModuleGraph() | |
923 graph.itergraphreport = my_iter | |
924 | |
925 fp = StringIO() | |
926 graph.graphreport(fp) | |
927 self.assertEqual(fp.getvalue(), "line1\n()\nline2\n") | |
928 | |
929 fp = StringIO() | |
930 graph.graphreport(fp, "deps") | |
931 self.assertEqual(fp.getvalue(), "line1\ndeps\nline2\n") | |
932 | |
933 saved_stdout = sys.stdout | |
934 try: | |
935 sys.stdout = fp = StringIO() | |
936 graph.graphreport() | |
937 self.assertEqual(fp.getvalue(), "line1\n()\nline2\n") | |
938 | |
939 finally: | |
940 sys.stdout = saved_stdout | |
941 | |
942 | |
943 def test_replace_paths_in_code(self): | |
944 graph = modulegraph.ModuleGraph(replace_paths=[ | |
945 ('path1', 'path2'), | |
946 ('path3/path5', 'path4'), | |
947 ]) | |
948 | |
949 co = compile(textwrap.dedent(""" | |
950 [x for x in range(4)] | |
951 """), "path4/index.py", 'exec', 0, 1) | |
952 co = graph._replace_paths_in_code(co) | |
953 self.assertEqual(co.co_filename, 'path4/index.py') | |
954 | |
955 co = compile(textwrap.dedent(""" | |
956 [x for x in range(4)] | |
957 (x for x in range(4)) | |
958 """), "path1/index.py", 'exec', 0, 1) | |
959 self.assertEqual(co.co_filename, 'path1/index.py') | |
960 co = graph._replace_paths_in_code(co) | |
961 self.assertEqual(co.co_filename, 'path2/index.py') | |
962 for c in co.co_consts: | |
963 if isinstance(c, type(co)): | |
964 self.assertEqual(c.co_filename, 'path2/index.py') | |
965 | |
966 co = compile(textwrap.dedent(""" | |
967 [x for x in range(4)] | |
968 """), "path3/path4/index.py", 'exec', 0, 1) | |
969 co = graph._replace_paths_in_code(co) | |
970 self.assertEqual(co.co_filename, 'path3/path4/index.py') | |
971 | |
972 co = compile(textwrap.dedent(""" | |
973 [x for x in range(4)] | |
974 """), "path3/path5.py", 'exec', 0, 1) | |
975 co = graph._replace_paths_in_code(co) | |
976 self.assertEqual(co.co_filename, 'path3/path5.py') | |
977 | |
978 co = compile(textwrap.dedent(""" | |
979 [x for x in range(4)] | |
980 """), "path3/path5/index.py", 'exec', 0, 1) | |
981 co = graph._replace_paths_in_code(co) | |
982 self.assertEqual(co.co_filename, 'path4/index.py') | |
983 | |
984 def test_createReference(self): | |
985 graph = modulegraph.ModuleGraph() | |
986 n1 = modulegraph.Node('n1') | |
987 n2 = modulegraph.Node('n2') | |
988 graph.addNode(n1) | |
989 graph.addNode(n2) | |
990 | |
991 graph.createReference(n1, n2) | |
992 outs, ins = map(list, graph.get_edges(n1)) | |
993 self.assertEqual(outs, [n2]) | |
994 self.assertEqual(ins, []) | |
995 outs, ins = map(list, graph.get_edges(n2)) | |
996 self.assertEqual(outs, []) | |
997 self.assertEqual(ins, [n1]) | |
998 | |
999 e = graph.graph.edge_by_node('n1', 'n2') | |
1000 self.assertIsInstance(e, int) | |
1001 self.assertEqual(graph.graph.edge_data(e), 'direct') | |
1002 | |
1003 def test_create_xref(self): | |
1004 # XXX: This test is far from optimal, it just ensures | |
1005 # that all code is exercised to catch small bugs and | |
1006 # py3k issues without verifying that the code actually | |
1007 # works.... | |
1008 graph = modulegraph.ModuleGraph() | |
1009 if __file__.endswith('.py'): | |
1010 graph.run_script(__file__) | |
1011 else: | |
1012 graph.run_script(__file__[:-1]) | |
1013 | |
1014 graph.import_hook('os') | |
1015 graph.import_hook('xml.etree') | |
1016 graph.import_hook('unittest') | |
1017 | |
1018 fp = StringIO() | |
1019 graph.create_xref(out=fp) | |
1020 | |
1021 data = fp.getvalue() | |
1022 r = ET.fromstring(data) | |
1023 | |
1024 def test_itergraphreport(self): | |
1025 # XXX: This test is far from optimal, it just ensures | |
1026 # that all code is exercised to catch small bugs and | |
1027 # py3k issues without verifying that the code actually | |
1028 # works.... | |
1029 graph = modulegraph.ModuleGraph() | |
1030 if __file__.endswith('.py'): | |
1031 graph.run_script(__file__) | |
1032 else: | |
1033 graph.run_script(__file__[:-1]) | |
1034 graph.import_hook('os') | |
1035 graph.import_hook('xml.etree') | |
1036 graph.import_hook('unittest') | |
1037 graph.import_hook('distutils.command.build') | |
1038 | |
1039 fp = StringIO() | |
1040 list(graph.itergraphreport()) | |
1041 | |
1042 # XXX: platpackages isn't implemented, and is undocumented hence | |
1043 # it is unclear what this is inteded to be... | |
1044 #list(graph.itergraphreport(flatpackages=...)) | |
1045 | |
1046 | |
1047 | |
1048 | |
1049 class CompatTests (unittest.TestCase): | |
1050 def test_Bchr(self): | |
1051 v = modulegraph._Bchr(ord('A')) | |
1052 if sys.version_info[0] == 2: | |
1053 self.assertTrue(isinstance(v, bytes)) | |
1054 self.assertEqual(v, b'A') | |
1055 else: | |
1056 self.assertTrue(isinstance(v, int)) | |
1057 self.assertEqual(v, ord('A')) | |
1058 | |
1059 if __name__ == "__main__": | |
1060 unittest.main() | |
OLD | NEW |