Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(774)

Side by Side Diff: third_party/google-endpoints/setuptools/command/test.py

Issue 2666783008: Add google-endpoints to third_party/. (Closed)
Patch Set: Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 import os
2 import operator
3 import sys
4 import contextlib
5 import itertools
6 from distutils.errors import DistutilsError, DistutilsOptionError
7 from distutils import log
8 from unittest import TestLoader
9
10 import six
11 from six.moves import map, filter
12
13 from pkg_resources import (resource_listdir, resource_exists, normalize_path,
14 working_set, _namespace_packages,
15 add_activation_listener, require, EntryPoint)
16 from setuptools import Command
17 from setuptools.py31compat import unittest_main
18
19
20 class ScanningLoader(TestLoader):
21 def loadTestsFromModule(self, module, pattern=None):
22 """Return a suite of all tests cases contained in the given module
23
24 If the module is a package, load tests from all the modules in it.
25 If the module has an ``additional_tests`` function, call it and add
26 the return value to the tests.
27 """
28 tests = []
29 tests.append(TestLoader.loadTestsFromModule(self, module))
30
31 if hasattr(module, "additional_tests"):
32 tests.append(module.additional_tests())
33
34 if hasattr(module, '__path__'):
35 for file in resource_listdir(module.__name__, ''):
36 if file.endswith('.py') and file != '__init__.py':
37 submodule = module.__name__ + '.' + file[:-3]
38 else:
39 if resource_exists(module.__name__, file + '/__init__.py'):
40 submodule = module.__name__ + '.' + file
41 else:
42 continue
43 tests.append(self.loadTestsFromName(submodule))
44
45 if len(tests) != 1:
46 return self.suiteClass(tests)
47 else:
48 return tests[0] # don't create a nested suite for only one return
49
50
51 # adapted from jaraco.classes.properties:NonDataProperty
52 class NonDataProperty(object):
53 def __init__(self, fget):
54 self.fget = fget
55
56 def __get__(self, obj, objtype=None):
57 if obj is None:
58 return self
59 return self.fget(obj)
60
61
62 class test(Command):
63 """Command to run unit tests after in-place build"""
64
65 description = "run unit tests after in-place build"
66
67 user_options = [
68 ('test-module=', 'm', "Run 'test_suite' in specified module"),
69 ('test-suite=', 's',
70 "Test suite to run (e.g. 'some_module.test_suite')"),
71 ('test-runner=', 'r', "Test runner to use"),
72 ]
73
74 def initialize_options(self):
75 self.test_suite = None
76 self.test_module = None
77 self.test_loader = None
78 self.test_runner = None
79
80 def finalize_options(self):
81
82 if self.test_suite and self.test_module:
83 msg = "You may specify a module or a suite, but not both"
84 raise DistutilsOptionError(msg)
85
86 if self.test_suite is None:
87 if self.test_module is None:
88 self.test_suite = self.distribution.test_suite
89 else:
90 self.test_suite = self.test_module + ".test_suite"
91
92 if self.test_loader is None:
93 self.test_loader = getattr(self.distribution, 'test_loader', None)
94 if self.test_loader is None:
95 self.test_loader = "setuptools.command.test:ScanningLoader"
96 if self.test_runner is None:
97 self.test_runner = getattr(self.distribution, 'test_runner', None)
98
99 @NonDataProperty
100 def test_args(self):
101 return list(self._test_args())
102
103 def _test_args(self):
104 if self.verbose:
105 yield '--verbose'
106 if self.test_suite:
107 yield self.test_suite
108
109 def with_project_on_sys_path(self, func):
110 """
111 Backward compatibility for project_on_sys_path context.
112 """
113 with self.project_on_sys_path():
114 func()
115
116 @contextlib.contextmanager
117 def project_on_sys_path(self, include_dists=[]):
118 with_2to3 = six.PY3 and getattr(self.distribution, 'use_2to3', False)
119
120 if with_2to3:
121 # If we run 2to3 we can not do this inplace:
122
123 # Ensure metadata is up-to-date
124 self.reinitialize_command('build_py', inplace=0)
125 self.run_command('build_py')
126 bpy_cmd = self.get_finalized_command("build_py")
127 build_path = normalize_path(bpy_cmd.build_lib)
128
129 # Build extensions
130 self.reinitialize_command('egg_info', egg_base=build_path)
131 self.run_command('egg_info')
132
133 self.reinitialize_command('build_ext', inplace=0)
134 self.run_command('build_ext')
135 else:
136 # Without 2to3 inplace works fine:
137 self.run_command('egg_info')
138
139 # Build extensions in-place
140 self.reinitialize_command('build_ext', inplace=1)
141 self.run_command('build_ext')
142
143 ei_cmd = self.get_finalized_command("egg_info")
144
145 old_path = sys.path[:]
146 old_modules = sys.modules.copy()
147
148 try:
149 project_path = normalize_path(ei_cmd.egg_base)
150 sys.path.insert(0, project_path)
151 working_set.__init__()
152 add_activation_listener(lambda dist: dist.activate())
153 require('%s==%s' % (ei_cmd.egg_name, ei_cmd.egg_version))
154 with self.paths_on_pythonpath([project_path]):
155 yield
156 finally:
157 sys.path[:] = old_path
158 sys.modules.clear()
159 sys.modules.update(old_modules)
160 working_set.__init__()
161
162 @staticmethod
163 @contextlib.contextmanager
164 def paths_on_pythonpath(paths):
165 """
166 Add the indicated paths to the head of the PYTHONPATH environment
167 variable so that subprocesses will also see the packages at
168 these paths.
169
170 Do this in a context that restores the value on exit.
171 """
172 nothing = object()
173 orig_pythonpath = os.environ.get('PYTHONPATH', nothing)
174 current_pythonpath = os.environ.get('PYTHONPATH', '')
175 try:
176 prefix = os.pathsep.join(paths)
177 to_join = filter(None, [prefix, current_pythonpath])
178 new_path = os.pathsep.join(to_join)
179 if new_path:
180 os.environ['PYTHONPATH'] = new_path
181 yield
182 finally:
183 if orig_pythonpath is nothing:
184 os.environ.pop('PYTHONPATH', None)
185 else:
186 os.environ['PYTHONPATH'] = orig_pythonpath
187
188 @staticmethod
189 def install_dists(dist):
190 """
191 Install the requirements indicated by self.distribution and
192 return an iterable of the dists that were built.
193 """
194 ir_d = dist.fetch_build_eggs(dist.install_requires or [])
195 tr_d = dist.fetch_build_eggs(dist.tests_require or [])
196 return itertools.chain(ir_d, tr_d)
197
198 def run(self):
199 installed_dists = self.install_dists(self.distribution)
200
201 cmd = ' '.join(self._argv)
202 if self.dry_run:
203 self.announce('skipping "%s" (dry run)' % cmd)
204 return
205
206 self.announce('running "%s"' % cmd)
207
208 paths = map(operator.attrgetter('location'), installed_dists)
209 with self.paths_on_pythonpath(paths):
210 with self.project_on_sys_path():
211 self.run_tests()
212
213 def run_tests(self):
214 # Purge modules under test from sys.modules. The test loader will
215 # re-import them from the build location. Required when 2to3 is used
216 # with namespace packages.
217 if six.PY3 and getattr(self.distribution, 'use_2to3', False):
218 module = self.test_suite.split('.')[0]
219 if module in _namespace_packages:
220 del_modules = []
221 if module in sys.modules:
222 del_modules.append(module)
223 module += '.'
224 for name in sys.modules:
225 if name.startswith(module):
226 del_modules.append(name)
227 list(map(sys.modules.__delitem__, del_modules))
228
229 exit_kwarg = {} if sys.version_info < (2, 7) else {"exit": False}
230 test = unittest_main(
231 None, None, self._argv,
232 testLoader=self._resolve_as_ep(self.test_loader),
233 testRunner=self._resolve_as_ep(self.test_runner),
234 **exit_kwarg
235 )
236 if not test.result.wasSuccessful():
237 msg = 'Test failed: %s' % test.result
238 self.announce(msg, log.ERROR)
239 raise DistutilsError(msg)
240
241 @property
242 def _argv(self):
243 return ['unittest'] + self.test_args
244
245 @staticmethod
246 def _resolve_as_ep(val):
247 """
248 Load the indicated attribute value, called, as a as if it were
249 specified as an entry point.
250 """
251 if val is None:
252 return
253 parsed = EntryPoint.parse("x=" + val)
254 return parsed.resolve()()
OLDNEW
« no previous file with comments | « third_party/google-endpoints/setuptools/command/setopt.py ('k') | third_party/google-endpoints/setuptools/command/upload.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698