[Telemetry] Use ModuleGraph instead of modulefinder to get a detailed import
[chromium-blink-merge.git] / tools / telemetry / third_party / modulegraph / modulegraph_tests / test_modulegraph.py
blob0ee724bd63494c7f0b1cffbcffb77be7be0cf5a8
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
14 try:
15 bytes
16 except NameError:
17 bytes = str
19 try:
20 from StringIO import StringIO
21 except ImportError:
22 from io import StringIO
24 TESTDATA = os.path.join(
25 os.path.dirname(os.path.abspath(__file__)),
26 "testdata", "nspkg")
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
40 else:
41 self.fail("unexpected pass")
43 class TestDependencyInfo (unittest.TestCase):
44 def test_pickling(self):
45 info = modulegraph.DependencyInfo(function=True, conditional=False, tryexcept=True, fromlist=False)
46 for proto in range(pickle.HIGHEST_PROTOCOL + 1):
47 b = pickle.dumps(info, proto)
48 self.assertTrue(isinstance(b, bytes))
50 o = pickle.loads(b)
51 self.assertEqual(o, info)
53 def test_merging(self):
54 info1 = modulegraph.DependencyInfo(function=True, conditional=False, tryexcept=True, fromlist=False)
55 info2 = modulegraph.DependencyInfo(function=False, conditional=True, tryexcept=True, fromlist=False)
56 self.assertEqual(
57 info1._merged(info2), modulegraph.DependencyInfo(function=True, conditional=True, tryexcept=True, fromlist=False))
59 info2 = modulegraph.DependencyInfo(function=False, conditional=True, tryexcept=False, fromlist=False)
60 self.assertEqual(
61 info1._merged(info2), modulegraph.DependencyInfo(function=True, conditional=True, tryexcept=True, fromlist=False))
63 info2 = modulegraph.DependencyInfo(function=False, conditional=False, tryexcept=False, fromlist=False)
64 self.assertEqual(
65 info1._merged(info2), modulegraph.DependencyInfo(function=False, conditional=False, tryexcept=False, fromlist=False))
67 info1 = modulegraph.DependencyInfo(function=True, conditional=False, tryexcept=True, fromlist=True)
68 self.assertEqual(
69 info1._merged(info2), modulegraph.DependencyInfo(function=False, conditional=False, tryexcept=False, fromlist=False))
71 info2 = modulegraph.DependencyInfo(function=False, conditional=False, tryexcept=False, fromlist=True)
72 self.assertEqual(
73 info1._merged(info2), modulegraph.DependencyInfo(function=False, conditional=False, tryexcept=False, fromlist=True))
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))
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\")",
91 self.assertEqual(modulegraph._eval_str_tuple(v), eval(v))
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'))")
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
105 def has_metadata(self, key):
106 if key == 'namespace_packages.txt':
107 return self._namespace_packages is not None
109 raise ValueError("invalid lookup key")
111 def get_metadata(self, key):
112 if key == 'namespace_packages.txt':
113 if self._namespace_packages is None:
114 raise ValueError("no file")
116 return self._namespace_packages
118 raise ValueError("invalid lookup key")
120 class WS (object):
121 def __init__(self, path=None):
122 pass
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")
130 saved_ws = pkg_resources.WorkingSet
131 try:
132 pkg_resources.WorkingSet = WS
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", ["appdir/pkg"]), ["appdir/pkg", "/pkg/pkg3/bar/baz"])
138 finally:
139 pkg_resources.WorkingSet = saved_ws
141 def test_os_listdir(self):
142 root = os.path.join(
143 os.path.dirname(os.path.abspath(__file__)), 'testdata')
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, 'test.egg', 'bar'))
149 self.assertEqual(list(sorted(modulegraph.os_listdir(os.path.join(root, 'test.egg', 'foo')))),
150 [ 'bar', 'bar.txt', 'baz.txt' ])
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
158 data = modulegraph._code_to_file(code)
159 self.assertTrue(hasattr(data, 'read'))
161 content = data.read()
162 self.assertIsInstance(content, bytes)
163 data.close()
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'))
171 # Plain module
172 info = modulegraph.find_module('mymodule', path=[path] + sys.path)
174 fp = info[0]
175 filename = info[1]
176 description = info[2]
178 self.assertTrue(hasattr(fp, 'read'))
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))
186 else:
187 self.assertEqual(filename, os.path.join(path, 'mymodule.pyc'))
188 self.assertEqual(description, ('.pyc', 'rb', imp.PY_COMPILED))
190 else:
191 self.assertEqual(filename, os.path.join(path, 'mymodule.py'))
192 self.assertEqual(description, ('.py', 'rU', imp.PY_SOURCE))
194 # Compiled plain module, no source
195 if path.endswith('.zip') or path.endswith('.egg'):
196 self.assertRaises(ImportError, modulegraph.find_module, 'mymodule2', path=[path] + sys.path)
198 else:
199 info = modulegraph.find_module('mymodule2', path=[path] + sys.path)
201 fp = info[0]
202 filename = info[1]
203 description = info[2]
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))
209 fp.close()
211 # Compiled plain module, with source
212 # info = modulegraph.find_module('mymodule3', path=[path] + sys.path)
214 # fp = info[0]
215 # filename = info[1]
216 # description = info[2]
218 # self.assertTrue(hasattr(fp, 'read'))
220 # if sys.version_info[:2] >= (3,2):
221 # self.assertEqual(filename, os.path.join(path, '__pycache__', 'mymodule3.cpython-32.pyc'))
222 # else:
223 # self.assertEqual(filename, os.path.join(path, 'mymodule3.pyc'))
224 # self.assertEqual(description, ('.pyc', 'rb', imp.PY_COMPILED))
227 # Package
228 info = modulegraph.find_module('mypkg', path=[path] + sys.path)
229 fp = info[0]
230 filename = info[1]
231 description = info[2]
233 self.assertEqual(fp, None)
234 self.assertEqual(filename, os.path.join(path, 'mypkg'))
235 self.assertEqual(description, ('', '', imp.PKG_DIRECTORY))
237 # Extension
238 if path.endswith('.zip'):
239 self.assertRaises(ImportError, modulegraph.find_module, 'myext', path=[path] + sys.path)
241 else:
242 info = modulegraph.find_module('myext', path=[path] + sys.path)
243 fp = info[0]
244 filename = info[1]
245 description = info[2]
247 if sys.platform == 'win32':
248 ext = '.pyd'
249 else:
250 # This is a ly, but is good enough for now
251 ext = '.so'
253 self.assertEqual(filename, os.path.join(path, 'myext' + ext))
254 self.assertEqual(description, (ext, 'rb', imp.C_EXTENSION))
255 self.assertEqual(fp, None)
257 def test_moduleInfoForPath(self):
258 self.assertEqual(modulegraph.moduleInfoForPath("/somewhere/else/file.txt"), None)
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)
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)
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)
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)
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 = []
293 def log_add(*args, **kwds):
294 called.append(('add', args, kwds))
295 def log_replace(*args, **kwds):
296 called.append(('replace', args, kwds))
298 modulegraph.addPackagePath = log_add
299 modulegraph.replacePackage = log_replace
301 with warnings.catch_warnings(record=True) as w:
302 warnings.simplefilter("always")
303 modulegraph.ReplacePackage('a', 'b')
304 modulegraph.AddPackagePath('c', 'd')
306 self.assertEqual(len(w), 2)
307 self.assertTrue(w[-1].category is DeprecationWarning)
308 self.assertTrue(w[-2].category is DeprecationWarning)
310 self.assertEqual(called, [
311 ('replace', ('a', 'b'), {}),
312 ('add', ('c', 'd'), {}),
315 finally:
316 modulegraph.addPackagePath = saved_add
317 modulegraph.replacePackage = saved_replace
318 '''), locals(), globals())
320 def test_addPackage(self):
321 saved = modulegraph._packagePathMap
322 self.assertIsInstance(saved, dict)
323 try:
324 modulegraph._packagePathMap = {}
326 modulegraph.addPackagePath('foo', 'a')
327 self.assertEqual(modulegraph._packagePathMap, { 'foo': ['a'] })
329 modulegraph.addPackagePath('foo', 'b')
330 self.assertEqual(modulegraph._packagePathMap, { 'foo': ['a', 'b'] })
332 modulegraph.addPackagePath('bar', 'b')
333 self.assertEqual(modulegraph._packagePathMap, { 'foo': ['a', 'b'], 'bar': ['b'] })
335 finally:
336 modulegraph._packagePathMap = saved
339 def test_replacePackage(self):
340 saved = modulegraph._replacePackageMap
341 self.assertIsInstance(saved, dict)
342 try:
343 modulegraph._replacePackageMap = {}
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'})
352 finally:
353 modulegraph._replacePackageMap = saved
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())
370 def testMapping(self):
371 n = modulegraph.Node("foobar.xyz")
372 self.assertEqual(n._namespace, {})
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})
383 def testOrder(self):
384 n1 = modulegraph.Node("n1")
385 n2 = modulegraph.Node("n2")
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)
399 def testHashing(self):
400 n1a = modulegraph.Node('n1')
401 n1b = modulegraph.Node('n1')
402 n2 = modulegraph.Node('n2')
404 d = {}
405 d[n1a] = 'n1'
406 d[n2] = 'n2'
407 self.assertEqual(d[n1b], 'n1')
408 self.assertEqual(d[n2], 'n2')
410 def test_infoTuple(self):
411 n = modulegraph.Node('n1')
412 self.assertEqual(n.infoTuple(), ('n1',))
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, {})
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__']
437 for nm in methods:
438 self.assertTrue(nm in d, "%s doesn't have attribute %r"%(klass, nm))
439 del d[nm]
441 self.assertEqual(d, {})
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))
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)
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)
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']
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)
486 v = a1.infoTuple()
487 self.assertEqual(v, ('a1', 'n1'))
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')
496 v = s1.infoTuple()
497 self.assertEqual(v, ('do_import',))
499 # BaseModule adds some attributes and a custom infotuple
500 self.assertHasExactMethods(modulegraph.BaseModule, '__init__', 'infoTuple')
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)
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'])
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))
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)
526 # Stricter tests would be nice, but that requires
527 # better control over what's on sys.path
528 self.assertIsInstance(o.nspackages, dict)
530 g = Graph.Graph()
531 o = modulegraph.ModuleGraph(['a', 'b', 'c'], ['modA'], [
532 ('fromA', 'toB'), ('fromC', 'toD')],
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'],
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)
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)
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"),
562 self.assertFalse(os.path.exists(os.path.join(TESTDATA, subdir, "parent", "namedpkg", "__init__.py")))
563 self.assertFalse(os.path.exists(os.path.join(TESTDATA, subdir, "child", "namedpkg", "__init__.py")))
565 def testImpliedReference(self):
566 graph = modulegraph.ModuleGraph()
568 record = []
569 def import_hook(*args):
570 record.append(('import_hook',) + args)
571 return [graph.createNode(modulegraph.Node, args[0])]
573 def _safe_import_hook(*args):
574 record.append(('_safe_import_hook',) + args)
575 return [graph.createNode(modulegraph.Node, args[0])]
577 graph.import_hook = import_hook
578 graph._safe_import_hook = _safe_import_hook
580 n1 = graph.createNode(modulegraph.Node, 'n1')
581 n2 = graph.createNode(modulegraph.Node, 'n2')
583 graph.implyNodeReference(n1, n2)
584 outs, ins = map(list, graph.get_edges(n1))
585 self.assertEqual(outs, [n2])
586 self.assertEqual(ins, [])
588 self.assertEqual(record, [])
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)
601 @expectedFailure
602 def test_findNode(self):
603 self.fail("findNode")
605 def test_run_script(self):
606 script = os.path.join(os.path.dirname(TESTDATA), 'script')
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'),
617 @expectedFailure
618 def test_import_hook(self):
619 self.fail("import_hook")
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)
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'")
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))
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)
645 m = graph.findNode('xml')
646 self.assertEqual(graph._determine_parent(m), m)
648 m = graph.findNode('xml.dom')
649 self.assertEqual(graph._determine_parent(m), graph.findNode('xml.dom'))
652 @expectedFailure
653 def test_find_head_package(self):
654 self.fail("find_head_package")
656 def test_load_tail(self):
657 # XXX: This test is dodgy!
658 graph = modulegraph.ModuleGraph()
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)
667 graph._import_module = _import_module
669 record = []
670 root = modulegraph.Node('root')
671 m = graph._load_tail(root, '')
672 self.assertTrue(m is root)
673 self.assertEqual(record, [
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),
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),
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),
706 n = graph._load_tail(root, 'raises')
707 self.assertIsInstance(n, modulegraph.MissingModule)
708 self.assertEqual(n.identifier, 'root.raises')
710 n = graph._load_tail(root, 'sub.raises')
711 self.assertIsInstance(n, modulegraph.MissingModule)
712 self.assertEqual(n.identifier, 'root.sub.raises')
714 n = graph._load_tail(root, 'sub.raises.sub')
715 self.assertIsInstance(n, modulegraph.MissingModule)
716 self.assertEqual(n.identifier, 'root.sub.raises.sub')
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")
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")
739 @expectedFailure
740 def test_import_module(self):
741 self.fail("import_module")
743 @expectedFailure
744 def test_load_module(self):
745 self.fail("load_module")
747 @expectedFailure
748 def test_safe_import_hook(self):
749 self.fail("safe_import_hook")
751 @expectedFailure
752 def test_scan_code(self):
753 mod = modulegraph.Node('root')
755 graph = modulegraph.ModuleGraph()
756 code = compile('', '<test>', 'exec', 0, False)
757 graph.scan_code(code, mod)
758 self.assertEqual(list(graph.nodes()), [])
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]
769 graph = modulegraph.ModuleGraph()
770 graph._safe_import_hook = _safe_import
772 code = compile(textwrap.dedent('''\
773 import sys
774 import os.path
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']))
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)
801 self.fail("actual test needed")
805 @expectedFailure
806 def test_load_package(self):
807 self.fail("load_package")
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)
815 saved_finder = modulegraph.find_module
816 try:
817 modulegraph.find_module = mock_finder
819 graph = modulegraph.ModuleGraph()
820 m = graph._find_module('sys', None)
821 self.assertEqual(record, [])
822 self.assertEqual(m, (None, None, ("", "", imp.C_BUILTIN)))
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
829 self.assertRaises(ImportError, graph._find_module, 'xml', None)
831 self.assertEqual(record, [])
832 m = graph._find_module('shutil', None)
833 self.assertEqual(record, [
834 ('shutil', graph.path),
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()
847 m2 = graph._find_module('shutil', None)
848 self.assertEqual(m[1:], m2[1:])
849 m2[0].close()
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),
860 if m[0] is not None: m[0].close()
862 finally:
863 modulegraph.find_module = saved_finder
865 @expectedFailure
866 def test_create_xref(self):
867 self.fail("create_xref")
869 @expectedFailure
870 def test_itergraphreport(self):
871 self.fail("itergraphreport")
873 def test_report(self):
874 graph = modulegraph.ModuleGraph()
876 saved_stdout = sys.stdout
877 try:
878 fp = sys.stdout = StringIO()
879 graph.report()
880 lines = fp.getvalue().splitlines()
881 fp.close()
883 self.assertEqual(len(lines), 3)
884 self.assertEqual(lines[0], '')
885 self.assertEqual(lines[1], 'Class Name File')
886 self.assertEqual(lines[2], '----- ---- ----')
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()
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])
906 expected.sort()
907 actual = [item.split() for item in lines[3:]]
908 actual.sort()
909 self.assertEqual(expected, actual)
912 finally:
913 sys.stdout = saved_stdout
915 def test_graphreport(self):
917 def my_iter(flatpackages="packages"):
918 yield "line1\n"
919 yield str(flatpackages) + "\n"
920 yield "line2\n"
922 graph = modulegraph.ModuleGraph()
923 graph.itergraphreport = my_iter
925 fp = StringIO()
926 graph.graphreport(fp)
927 self.assertEqual(fp.getvalue(), "line1\n()\nline2\n")
929 fp = StringIO()
930 graph.graphreport(fp, "deps")
931 self.assertEqual(fp.getvalue(), "line1\ndeps\nline2\n")
933 saved_stdout = sys.stdout
934 try:
935 sys.stdout = fp = StringIO()
936 graph.graphreport()
937 self.assertEqual(fp.getvalue(), "line1\n()\nline2\n")
939 finally:
940 sys.stdout = saved_stdout
943 def test_replace_paths_in_code(self):
944 graph = modulegraph.ModuleGraph(replace_paths=[
945 ('path1', 'path2'),
946 ('path3/path5', 'path4'),
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')
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')
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')
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')
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')
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)
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])
999 e = graph.graph.edge_by_node('n1', 'n2')
1000 self.assertIsInstance(e, int)
1001 self.assertEqual(graph.graph.edge_data(e), 'direct')
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])
1014 graph.import_hook('os')
1015 graph.import_hook('xml.etree')
1016 graph.import_hook('unittest')
1018 fp = StringIO()
1019 graph.create_xref(out=fp)
1021 data = fp.getvalue()
1022 r = ET.fromstring(data)
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')
1039 fp = StringIO()
1040 list(graph.itergraphreport())
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=...))
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'))
1059 if __name__ == "__main__":
1060 unittest.main()