1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 """Verification tests for the relax library."""
24
25
26 from os import sep
27 from shutil import copytree, rmtree
28 from subprocess import PIPE, Popen
29 import sys
30 from tempfile import mkdtemp
31 from unittest import TestCase
32
33
34 from status import Status; status = Status()
35 from test_suite.clean_up import deletion
36
37
39 """Test the relax library."""
40
42 """Set up for all of the library tests."""
43
44
45 self.tmpdir = mkdtemp()
46
47
49 """Clean up after the library tests."""
50
51
52 deletion(obj=self, name='tmpdir', dir=True)
53
54
56 """Throughly check the independence of the relax library by importing it from a non-relax directory.
57
58 It will do this by copying just that package into a temporary directory, modifying the Python system path to include the directory, and then to recursively import all packages and modules. All import failures will be reported at the end.
59 """
60
61
62 tmplib = self.tmpdir + sep + 'lib'
63 copytree(status.install_path+sep+'lib', tmplib)
64
65
66 script_name = self.tmpdir + sep + 'test.py'
67 script = open(script_name, 'w')
68
69
70 lines = [
71 "",
72 "# Python module imports.",
73 "import pkgutil",
74 "import sys",
75 "",
76 "# Direct copy of the Python 2.7 importlib function.",
77 "def _resolve_name(name, package, level):",
78 " \"\"\"Return the absolute name of the module to be imported.\"\"\"",
79 " if not hasattr(package, 'rindex'):",
80 " raise ValueError(\"'package' not set to a string\")",
81 " dot = len(package)",
82 " for x in range(level, 1, -1):",
83 " try:",
84 " dot = package.rindex('.', 0, dot)",
85 " except ValueError:",
86 " raise ValueError(\"attempted relative import beyond top-level package\")",
87 " return \"%s.%s\" % (package[:dot], name)",
88 "",
89 "",
90 "# Direct copy of the Python 2.7 importlib function.",
91 "def import_module(name, package=None):",
92 " \"\"\"Import a module.",
93 "",
94 " The 'package' argument is required when performing a relative import. It",
95 " specifies the package to use as the anchor point from which to resolve the",
96 " relative import to an absolute import.",
97 "",
98 " \"\"\"",
99 " if name.startswith('.'):",
100 " if not package:",
101 " raise TypeError(\"relative imports require the 'package' argument\")",
102 " level = 0",
103 " for character in name:",
104 " if character != '.':",
105 " break",
106 " level += 1",
107 " name = _resolve_name(name[level:], package, level)",
108 " __import__(name)",
109 " return sys.modules[name]",
110 "",
111 "",
112 "# Initialise a structure for later reporting of failed imports.",
113 "failed = []",
114 "",
115 "# Import each part of the library.",
116 "import lib",
117 "for importer, name, is_pkg in pkgutil.iter_modules(lib.__path__):",
118 " # The full name.",
119 " full_name = 'lib.%s' % name",
120 "",
121 " # Printout.",
122 " if is_pkg:",
123 " print(\"Package '%s'.\" % full_name)",
124 " else:",
125 " print(\"Module '%s'.\" % full_name)",
126 "",
127 " # Import it.",
128 " module = None",
129 " try:",
130 " module = import_module(full_name)",
131 " except:",
132 " message = sys.exc_info()[1]",
133 " failed.append([full_name, message])",
134 "",
135 " # Nothing more to do.",
136 " if not is_pkg or module is None:",
137 " continue",
138 "",
139 " # First recursion.",
140 " for importer2, name2, is_pkg2 in pkgutil.iter_modules(module.__path__):",
141 " # The full name.",
142 " full_name2 = 'lib.%s.%s' % (name, name2)",
143 "",
144 " # Printout.",
145 " if is_pkg2:",
146 " print(\" Package '%s'.\" % full_name2)",
147 " else:",
148 " print(\" Module '%s'.\" % full_name2)",
149 "",
150 " # Import it.",
151 " module2 = None",
152 " try:",
153 " module2 = import_module(full_name2)",
154 " except:",
155 " message = sys.exc_info()[1]",
156 " failed.append([full_name2, message])",
157 "",
158 " # Nothing more to do.",
159 " if not is_pkg2 or module2 is None:",
160 " continue",
161 "",
162 " # 2nd recursion (the last for now).",
163 " for importer3, name3, is_pkg3 in pkgutil.iter_modules(module2.__path__):",
164 " # The full name.",
165 " full_name3 = 'lib.%s.%s.%s' % (name, name2, name3)",
166 "",
167 " # Printout.",
168 " if is_pkg3:",
169 " print(\" Package '%s'.\" % full_name3)",
170 " raise NameError(\"Recursion limit exceeded.\")",
171 " else:",
172 " print(\" Module '%s'.\" % full_name3)",
173 "",
174 " # Import it.",
175 " try:",
176 " module3 = import_module(full_name3)",
177 " except:",
178 " message = sys.exc_info()[1]",
179 " failed.append([full_name3, message])",
180 "",
181 "# Printout of all import failures.",
182 "if len(failed):",
183 " sys.stderr.write('\\n\\nImport failures:\\n')",
184 " for name, message in failed:",
185 " sys.stderr.write(\" %s: %s\\n\" % (name, message))",
186 " sys.stderr.write('\\n')",
187 ]
188 for line in lines:
189 script.write(line + '\n')
190
191
192 script.close()
193
194
195 cmd = "%s %s" % (sys.executable, script_name)
196 pipe = Popen(cmd, shell=True, stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=False)
197
198
199 pipe.stdin.close()
200
201
202 for line in pipe.stdout.readlines():
203
204 if hasattr(line, 'decode'):
205 line = line.decode()
206
207
208 sys.stdout.write(line)
209
210
211 err_lines = pipe.stderr.readlines()
212 for line in err_lines:
213
214 if hasattr(line, 'decode'):
215 line = line.decode()
216
217
218 sys.stderr.write(line)
219
220
221 if len(err_lines):
222 for line in err_lines:
223 print(line)
224 self.fail()
225