| 
									
										
										
										
											2011-05-19 13:07:25 +02:00
										 |  |  | """Support code for packaging test cases.
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-09-01 23:48:13 +02:00
										 |  |  | *This module should not be considered public: its content and API may | 
					
						
							|  |  |  | change in incompatible ways.* | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-05-19 13:07:25 +02:00
										 |  |  | A few helper classes are provided: LoggingCatcher, TempdirManager and | 
					
						
							|  |  |  | EnvironRestorer. They are written to be used as mixins:: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     from packaging.tests import unittest | 
					
						
							|  |  |  |     from packaging.tests.support import LoggingCatcher | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     class SomeTestCase(LoggingCatcher, unittest.TestCase): | 
					
						
							| 
									
										
										
										
											2011-09-01 23:48:13 +02:00
										 |  |  |         ... | 
					
						
							| 
									
										
										
										
											2011-05-19 13:07:25 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | If you need to define a setUp method on your test class, you have to | 
					
						
							|  |  |  | call the mixin class' setUp method or it won't work (same thing for | 
					
						
							|  |  |  | tearDown): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def setUp(self): | 
					
						
							|  |  |  |             super(SomeTestCase, self).setUp() | 
					
						
							| 
									
										
										
										
											2011-09-01 23:48:13 +02:00
										 |  |  |             ...  # other setup code | 
					
						
							| 
									
										
										
										
											2011-05-19 13:07:25 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | Also provided is a DummyCommand class, useful to mock commands in the | 
					
						
							| 
									
										
										
										
											2011-09-01 23:48:13 +02:00
										 |  |  | tests of another command that needs them, for example to fake | 
					
						
							|  |  |  | compilation in build_ext (this requires that the mock build_ext command | 
					
						
							|  |  |  | be injected into the distribution object's command_obj dictionary). | 
					
						
							| 
									
										
										
										
											2011-05-19 13:07:25 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-09-01 23:48:13 +02:00
										 |  |  | For tests that need to compile an extension module, use the | 
					
						
							|  |  |  | copy_xxmodule_c and fixup_build_ext functions. | 
					
						
							| 
									
										
										
										
											2011-05-19 13:07:25 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | Each class or function has a docstring to explain its purpose and usage. | 
					
						
							| 
									
										
										
										
											2011-09-01 23:48:13 +02:00
										 |  |  | Existing tests should also be used as examples. | 
					
						
							| 
									
										
										
										
											2011-05-19 13:07:25 +02:00
										 |  |  | """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import os | 
					
						
							| 
									
										
										
										
											2011-08-21 17:38:36 +02:00
										 |  |  | import sys | 
					
						
							| 
									
										
										
										
											2011-05-19 13:07:25 +02:00
										 |  |  | import shutil | 
					
						
							|  |  |  | import logging | 
					
						
							|  |  |  | import weakref | 
					
						
							|  |  |  | import tempfile | 
					
						
							| 
									
										
										
										
											2011-08-20 07:27:47 +02:00
										 |  |  | import sysconfig | 
					
						
							| 
									
										
										
										
											2011-05-19 13:07:25 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | from packaging.dist import Distribution | 
					
						
							| 
									
										
										
										
											2011-11-06 07:01:18 +01:00
										 |  |  | from packaging.util import resolve_name | 
					
						
							|  |  |  | from packaging.command import set_command, _COMMANDS | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-05-19 13:07:25 +02:00
										 |  |  | from packaging.tests import unittest | 
					
						
							| 
									
										
										
										
											2011-06-17 12:20:46 +02:00
										 |  |  | from test.support import requires_zlib, unlink | 
					
						
							| 
									
										
										
										
											2011-05-19 13:07:25 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-09-01 23:48:13 +02:00
										 |  |  | # define __all__ to make pydoc more useful | 
					
						
							|  |  |  | __all__ = [ | 
					
						
							|  |  |  |     # TestCase mixins | 
					
						
							|  |  |  |     'LoggingCatcher', 'TempdirManager', 'EnvironRestorer', | 
					
						
							|  |  |  |     # mocks | 
					
						
							| 
									
										
										
										
											2011-11-06 11:32:47 +01:00
										 |  |  |     'DummyCommand', 'TestDistribution', 'Inputs', | 
					
						
							| 
									
										
										
										
											2011-09-01 23:48:13 +02:00
										 |  |  |     # misc. functions and decorators | 
					
						
							| 
									
										
										
										
											2011-11-06 07:01:18 +01:00
										 |  |  |     'fake_dec', 'create_distribution', 'use_command', | 
					
						
							|  |  |  |     'copy_xxmodule_c', 'fixup_build_ext', | 
					
						
							| 
									
										
										
										
											2012-02-09 21:30:25 +01:00
										 |  |  |     'skip_2to3_optimize', | 
					
						
							| 
									
										
										
										
											2011-09-01 23:48:13 +02:00
										 |  |  |     # imported from this module for backport purposes | 
					
						
							| 
									
										
										
										
											2012-02-09 21:30:25 +01:00
										 |  |  |     'unittest', 'requires_zlib', 'skip_unless_symlink', | 
					
						
							| 
									
										
										
										
											2011-09-01 23:48:13 +02:00
										 |  |  | ] | 
					
						
							| 
									
										
										
										
											2011-05-19 13:07:25 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-15 17:49:20 +02:00
										 |  |  | logger = logging.getLogger('packaging') | 
					
						
							|  |  |  | logger2to3 = logging.getLogger('RefactoringTool') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-05-19 13:07:25 +02:00
										 |  |  | class _TestHandler(logging.handlers.BufferingHandler): | 
					
						
							|  |  |  |     # stolen and adapted from test.support | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self): | 
					
						
							| 
									
										
										
										
											2011-10-14 17:04:39 +02:00
										 |  |  |         super(_TestHandler, self).__init__(0) | 
					
						
							| 
									
										
										
										
											2011-05-19 13:07:25 +02:00
										 |  |  |         self.setLevel(logging.DEBUG) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def shouldFlush(self): | 
					
						
							|  |  |  |         return False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def emit(self, record): | 
					
						
							|  |  |  |         self.buffer.append(record) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class LoggingCatcher: | 
					
						
							|  |  |  |     """TestCase-compatible mixin to receive logging calls.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Upon setUp, instances of this classes get a BufferingHandler that's | 
					
						
							|  |  |  |     configured to record all messages logged to the 'packaging' logger. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Use get_logs to retrieve messages and self.loghandler.flush to discard | 
					
						
							| 
									
										
										
										
											2011-10-19 08:37:22 +02:00
										 |  |  |     them.  get_logs automatically flushes the logs, unless you pass | 
					
						
							|  |  |  |     *flush=False*, for example to make multiple calls to the method with | 
					
						
							|  |  |  |     different level arguments.  If your test calls some code that generates | 
					
						
							|  |  |  |     logging message and then you don't call get_logs, you will need to flush | 
					
						
							|  |  |  |     manually before testing other code in the same test_* method, otherwise | 
					
						
							|  |  |  |     get_logs in the next lines will see messages from the previous lines. | 
					
						
							|  |  |  |     See example in test_command_check. | 
					
						
							| 
									
										
										
										
											2011-05-19 13:07:25 +02:00
										 |  |  |     """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def setUp(self): | 
					
						
							|  |  |  |         super(LoggingCatcher, self).setUp() | 
					
						
							|  |  |  |         self.loghandler = handler = _TestHandler() | 
					
						
							| 
									
										
										
										
											2011-07-15 17:49:20 +02:00
										 |  |  |         self._old_levels = logger.level, logger2to3.level | 
					
						
							| 
									
										
										
										
											2011-05-19 13:07:25 +02:00
										 |  |  |         logger.addHandler(handler) | 
					
						
							|  |  |  |         logger.setLevel(logging.DEBUG)  # we want all messages | 
					
						
							| 
									
										
										
										
											2011-07-15 17:49:20 +02:00
										 |  |  |         logger2to3.setLevel(logging.CRITICAL)  # we don't want 2to3 messages | 
					
						
							| 
									
										
										
										
											2011-05-19 13:07:25 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def tearDown(self): | 
					
						
							|  |  |  |         handler = self.loghandler | 
					
						
							|  |  |  |         # All this is necessary to properly shut down the logging system and | 
					
						
							|  |  |  |         # avoid a regrtest complaint.  Thanks to Vinay Sajip for the help. | 
					
						
							|  |  |  |         handler.close() | 
					
						
							|  |  |  |         logger.removeHandler(handler) | 
					
						
							|  |  |  |         for ref in weakref.getweakrefs(handler): | 
					
						
							|  |  |  |             logging._removeHandlerRef(ref) | 
					
						
							|  |  |  |         del self.loghandler | 
					
						
							| 
									
										
										
										
											2011-07-15 17:49:20 +02:00
										 |  |  |         logger.setLevel(self._old_levels[0]) | 
					
						
							|  |  |  |         logger2to3.setLevel(self._old_levels[1]) | 
					
						
							| 
									
										
										
										
											2011-05-19 13:07:25 +02:00
										 |  |  |         super(LoggingCatcher, self).tearDown() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-19 08:37:22 +02:00
										 |  |  |     def get_logs(self, level=logging.WARNING, flush=True): | 
					
						
							|  |  |  |         """Return all log messages with given level.
 | 
					
						
							| 
									
										
										
										
											2011-05-19 13:07:25 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-19 08:37:22 +02:00
										 |  |  |         *level* defaults to logging.WARNING. | 
					
						
							| 
									
										
										
										
											2011-06-02 14:53:59 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-19 08:37:22 +02:00
										 |  |  |         For log calls with arguments (i.e.  logger.info('bla bla %r', arg)), | 
					
						
							|  |  |  |         the messages will be formatted before being returned (e.g. "bla bla | 
					
						
							|  |  |  |         'thing'"). | 
					
						
							| 
									
										
										
										
											2011-05-19 13:07:25 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-19 08:37:22 +02:00
										 |  |  |         Returns a list.  Automatically flushes the loghandler after being | 
					
						
							|  |  |  |         called, unless *flush* is False (this is useful to get e.g. all | 
					
						
							|  |  |  |         warnings then all info messages). | 
					
						
							| 
									
										
										
										
											2011-05-19 13:07:25 +02:00
										 |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2011-10-19 08:37:22 +02:00
										 |  |  |         messages = [log.getMessage() for log in self.loghandler.buffer | 
					
						
							|  |  |  |                     if log.levelno == level] | 
					
						
							|  |  |  |         if flush: | 
					
						
							|  |  |  |             self.loghandler.flush() | 
					
						
							| 
									
										
										
										
											2011-06-02 14:53:59 +02:00
										 |  |  |         return messages | 
					
						
							| 
									
										
										
										
											2011-05-19 13:07:25 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class TempdirManager: | 
					
						
							|  |  |  |     """TestCase-compatible mixin to create temporary directories and files.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Directories and files created in a test_* method will be removed after it | 
					
						
							|  |  |  |     has run. | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def setUp(self): | 
					
						
							|  |  |  |         super(TempdirManager, self).setUp() | 
					
						
							| 
									
										
										
										
											2011-06-17 12:20:46 +02:00
										 |  |  |         self._olddir = os.getcwd() | 
					
						
							| 
									
										
										
										
											2011-05-19 13:07:25 +02:00
										 |  |  |         self._basetempdir = tempfile.mkdtemp() | 
					
						
							| 
									
										
										
										
											2011-05-21 10:37:58 +02:00
										 |  |  |         self._files = [] | 
					
						
							| 
									
										
										
										
											2011-05-19 13:07:25 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def tearDown(self): | 
					
						
							| 
									
										
										
										
											2011-05-21 10:37:58 +02:00
										 |  |  |         for handle, name in self._files: | 
					
						
							|  |  |  |             handle.close() | 
					
						
							| 
									
										
										
										
											2011-06-17 12:20:46 +02:00
										 |  |  |             unlink(name) | 
					
						
							| 
									
										
										
										
											2011-05-21 10:37:58 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-17 13:25:53 +02:00
										 |  |  |         os.chdir(self._olddir) | 
					
						
							|  |  |  |         shutil.rmtree(self._basetempdir) | 
					
						
							| 
									
										
										
										
											2011-05-19 13:07:25 +02:00
										 |  |  |         super(TempdirManager, self).tearDown() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def mktempfile(self): | 
					
						
							|  |  |  |         """Create a read-write temporary file and return it.""" | 
					
						
							|  |  |  |         fd, fn = tempfile.mkstemp(dir=self._basetempdir) | 
					
						
							|  |  |  |         os.close(fd) | 
					
						
							|  |  |  |         fp = open(fn, 'w+') | 
					
						
							| 
									
										
										
										
											2011-05-21 10:37:58 +02:00
										 |  |  |         self._files.append((fp, fn)) | 
					
						
							| 
									
										
										
										
											2011-05-19 13:07:25 +02:00
										 |  |  |         return fp | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def mkdtemp(self): | 
					
						
							|  |  |  |         """Create a temporary directory and return its path.""" | 
					
						
							|  |  |  |         d = tempfile.mkdtemp(dir=self._basetempdir) | 
					
						
							|  |  |  |         return d | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-05-19 18:45:32 +02:00
										 |  |  |     def write_file(self, path, content='xxx', encoding=None): | 
					
						
							| 
									
										
										
										
											2011-05-19 13:07:25 +02:00
										 |  |  |         """Write a file at the given path.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         path can be a string, a tuple or a list; if it's a tuple or list, | 
					
						
							|  |  |  |         os.path.join will be used to produce a path. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         if isinstance(path, (list, tuple)): | 
					
						
							|  |  |  |             path = os.path.join(*path) | 
					
						
							| 
									
										
										
										
											2011-05-19 18:45:32 +02:00
										 |  |  |         with open(path, 'w', encoding=encoding) as f: | 
					
						
							| 
									
										
										
										
											2011-05-19 13:07:25 +02:00
										 |  |  |             f.write(content) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def create_dist(self, **kw): | 
					
						
							|  |  |  |         """Create a stub distribution object and files.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         This function creates a Distribution instance (use keyword arguments | 
					
						
							|  |  |  |         to customize it) and a temporary directory with a project structure | 
					
						
							|  |  |  |         (currently an empty directory). | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         It returns the path to the directory and the Distribution instance. | 
					
						
							|  |  |  |         You can use self.write_file to write any file in that | 
					
						
							|  |  |  |         directory, e.g. setup scripts or Python modules. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         if 'name' not in kw: | 
					
						
							|  |  |  |             kw['name'] = 'foo' | 
					
						
							|  |  |  |         tmp_dir = self.mkdtemp() | 
					
						
							|  |  |  |         project_dir = os.path.join(tmp_dir, kw['name']) | 
					
						
							|  |  |  |         os.mkdir(project_dir) | 
					
						
							|  |  |  |         dist = Distribution(attrs=kw) | 
					
						
							|  |  |  |         return project_dir, dist | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def assertIsFile(self, *args): | 
					
						
							|  |  |  |         path = os.path.join(*args) | 
					
						
							|  |  |  |         dirname = os.path.dirname(path) | 
					
						
							|  |  |  |         file = os.path.basename(path) | 
					
						
							|  |  |  |         if os.path.isdir(dirname): | 
					
						
							|  |  |  |             files = os.listdir(dirname) | 
					
						
							|  |  |  |             msg = "%s not found in %s: %s" % (file, dirname, files) | 
					
						
							|  |  |  |             assert os.path.isfile(path), msg | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             raise AssertionError( | 
					
						
							|  |  |  |                     '%s not found. %s does not exist' % (file, dirname)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def assertIsNotFile(self, *args): | 
					
						
							|  |  |  |         path = os.path.join(*args) | 
					
						
							|  |  |  |         self.assertFalse(os.path.isfile(path), "%r exists" % path) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class EnvironRestorer: | 
					
						
							|  |  |  |     """TestCase-compatible mixin to restore or delete environment variables.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     The variables to restore (or delete if they were not originally present) | 
					
						
							|  |  |  |     must be explicitly listed in self.restore_environ.  It's better to be | 
					
						
							|  |  |  |     aware of what we're modifying instead of saving and restoring the whole | 
					
						
							|  |  |  |     environment. | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def setUp(self): | 
					
						
							|  |  |  |         super(EnvironRestorer, self).setUp() | 
					
						
							|  |  |  |         self._saved = [] | 
					
						
							|  |  |  |         self._added = [] | 
					
						
							|  |  |  |         for key in self.restore_environ: | 
					
						
							|  |  |  |             if key in os.environ: | 
					
						
							|  |  |  |                 self._saved.append((key, os.environ[key])) | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 self._added.append(key) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def tearDown(self): | 
					
						
							|  |  |  |         for key, value in self._saved: | 
					
						
							|  |  |  |             os.environ[key] = value | 
					
						
							|  |  |  |         for key in self._added: | 
					
						
							|  |  |  |             os.environ.pop(key, None) | 
					
						
							|  |  |  |         super(EnvironRestorer, self).tearDown() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class DummyCommand: | 
					
						
							|  |  |  |     """Class to store options for retrieval via set_undefined_options().
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Useful for mocking one dependency command in the tests for another | 
					
						
							|  |  |  |     command, see e.g. the dummy build command in test_build_scripts. | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2011-11-06 06:54:05 +01:00
										 |  |  |     # XXX does not work with dist.reinitialize_command, which typechecks | 
					
						
							| 
									
										
										
										
											2011-09-01 23:48:13 +02:00
										 |  |  |     # and wants a finalized attribute | 
					
						
							| 
									
										
										
										
											2011-05-19 13:07:25 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self, **kwargs): | 
					
						
							|  |  |  |         for kw, val in kwargs.items(): | 
					
						
							|  |  |  |             setattr(self, kw, val) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def ensure_finalized(self): | 
					
						
							|  |  |  |         pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class TestDistribution(Distribution): | 
					
						
							|  |  |  |     """Distribution subclasses that avoids the default search for
 | 
					
						
							|  |  |  |     configuration files. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     The ._config_files attribute must be set before | 
					
						
							|  |  |  |     .parse_config_files() is called. | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def find_config_files(self): | 
					
						
							|  |  |  |         return self._config_files | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-11-06 11:32:47 +01:00
										 |  |  | class Inputs: | 
					
						
							|  |  |  |     """Fakes user inputs.""" | 
					
						
							|  |  |  |     # TODO document usage | 
					
						
							|  |  |  |     # TODO use context manager or something for auto cleanup | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self, *answers): | 
					
						
							|  |  |  |         self.answers = answers | 
					
						
							|  |  |  |         self.index = 0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __call__(self, prompt=''): | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             return self.answers[self.index] | 
					
						
							|  |  |  |         finally: | 
					
						
							|  |  |  |             self.index += 1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-05-19 13:07:25 +02:00
										 |  |  | def create_distribution(configfiles=()): | 
					
						
							|  |  |  |     """Prepares a distribution with given config files parsed.""" | 
					
						
							|  |  |  |     d = TestDistribution() | 
					
						
							|  |  |  |     d.config.find_config_files = d.find_config_files | 
					
						
							|  |  |  |     d._config_files = configfiles | 
					
						
							|  |  |  |     d.parse_config_files() | 
					
						
							|  |  |  |     d.parse_command_line() | 
					
						
							|  |  |  |     return d | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-11-06 07:01:18 +01:00
										 |  |  | def use_command(testcase, fullname): | 
					
						
							|  |  |  |     """Register command at *fullname* for the duration of a test.""" | 
					
						
							|  |  |  |     set_command(fullname) | 
					
						
							|  |  |  |     # XXX maybe set_command should return the class object | 
					
						
							|  |  |  |     name = resolve_name(fullname).get_command_name() | 
					
						
							|  |  |  |     # XXX maybe we need a public API to remove commands | 
					
						
							|  |  |  |     testcase.addCleanup(_COMMANDS.__delitem__, name) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-05-25 23:46:09 +02:00
										 |  |  | def fake_dec(*args, **kw): | 
					
						
							|  |  |  |     """Fake decorator""" | 
					
						
							|  |  |  |     def _wrap(func): | 
					
						
							|  |  |  |         def __wrap(*args, **kw): | 
					
						
							|  |  |  |             return func(*args, **kw) | 
					
						
							|  |  |  |         return __wrap | 
					
						
							|  |  |  |     return _wrap | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-08-20 07:27:47 +02:00
										 |  |  | def copy_xxmodule_c(directory): | 
					
						
							|  |  |  |     """Helper for tests that need the xxmodule.c source file.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Example use: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def test_compile(self): | 
					
						
							|  |  |  |             copy_xxmodule_c(self.tmpdir) | 
					
						
							| 
									
										
										
										
											2011-08-21 17:38:36 +02:00
										 |  |  |             self.assertIn('xxmodule.c', os.listdir(self.tmpdir)) | 
					
						
							| 
									
										
										
										
											2011-08-20 07:27:47 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     If the source file can be found, it will be copied to *directory*.  If not, | 
					
						
							|  |  |  |     the test will be skipped.  Errors during copy are not caught. | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     filename = _get_xxmodule_path() | 
					
						
							|  |  |  |     if filename is None: | 
					
						
							| 
									
										
										
										
											2012-02-09 21:30:25 +01:00
										 |  |  |         raise unittest.SkipTest('cannot find xxmodule.c') | 
					
						
							| 
									
										
										
										
											2011-08-20 07:27:47 +02:00
										 |  |  |     shutil.copy(filename, directory) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def _get_xxmodule_path(): | 
					
						
							| 
									
										
										
										
											2012-02-09 21:30:25 +01:00
										 |  |  |     if sysconfig.is_python_build(): | 
					
						
							|  |  |  |         srcdir = sysconfig.get_config_var('projectbase') | 
					
						
							|  |  |  |         path = os.path.join(os.getcwd(), srcdir, 'Modules', 'xxmodule.c') | 
					
						
							|  |  |  |     else: | 
					
						
							| 
									
										
										
										
											2012-02-17 17:26:30 +01:00
										 |  |  |         path = os.path.join(os.path.dirname(__file__), 'xxmodule.c') | 
					
						
							| 
									
										
										
										
											2012-02-09 21:30:25 +01:00
										 |  |  |     if os.path.exists(path): | 
					
						
							|  |  |  |         return path | 
					
						
							| 
									
										
										
										
											2011-08-20 07:27:47 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-08-21 17:38:36 +02:00
										 |  |  | def fixup_build_ext(cmd): | 
					
						
							| 
									
										
										
										
											2011-08-23 21:38:13 +02:00
										 |  |  |     """Function needed to make build_ext tests pass.
 | 
					
						
							| 
									
										
										
										
											2011-08-21 17:38:36 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-09-01 23:48:13 +02:00
										 |  |  |     When Python was built with --enable-shared on Unix, -L. is not enough to | 
					
						
							|  |  |  |     find libpython<blah>.so, because regrtest runs in a tempdir, not in the | 
					
						
							| 
									
										
										
										
											2012-02-09 21:30:25 +01:00
										 |  |  |     source directory where the .so lives.  (Mac OS X embeds absolute paths | 
					
						
							|  |  |  |     to shared libraries into executables, so the fixup is a no-op on that | 
					
						
							|  |  |  |     platform.) | 
					
						
							| 
									
										
										
										
											2011-08-23 21:38:13 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     When Python was built with in debug mode on Windows, build_ext commands | 
					
						
							|  |  |  |     need their debug attribute set, and it is not done automatically for | 
					
						
							|  |  |  |     some reason. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-02-09 21:30:25 +01:00
										 |  |  |     This function handles both of these things, and also fixes | 
					
						
							|  |  |  |     cmd.distribution.include_dirs if the running Python is an uninstalled | 
					
						
							|  |  |  |     build.  Example use: | 
					
						
							| 
									
										
										
										
											2011-08-21 17:38:36 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         cmd = build_ext(dist) | 
					
						
							|  |  |  |         support.fixup_build_ext(cmd) | 
					
						
							|  |  |  |         cmd.ensure_finalized() | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2011-08-24 02:15:25 +02:00
										 |  |  |     if os.name == 'nt': | 
					
						
							|  |  |  |         cmd.debug = sys.executable.endswith('_d.exe') | 
					
						
							| 
									
										
										
										
											2011-08-23 21:38:13 +02:00
										 |  |  |     elif sysconfig.get_config_var('Py_ENABLE_SHARED'): | 
					
						
							|  |  |  |         # To further add to the shared builds fun on Unix, we can't just add | 
					
						
							|  |  |  |         # library_dirs to the Extension() instance because that doesn't get | 
					
						
							|  |  |  |         # plumbed through to the final compiler command. | 
					
						
							| 
									
										
										
										
											2011-08-21 17:38:36 +02:00
										 |  |  |         runshared = sysconfig.get_config_var('RUNSHARED') | 
					
						
							|  |  |  |         if runshared is None: | 
					
						
							|  |  |  |             cmd.library_dirs = ['.'] | 
					
						
							|  |  |  |         else: | 
					
						
							| 
									
										
										
										
											2012-02-03 02:46:37 +01:00
										 |  |  |             if sys.platform == 'darwin': | 
					
						
							|  |  |  |                 cmd.library_dirs = [] | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 name, equals, value = runshared.partition('=') | 
					
						
							|  |  |  |                 cmd.library_dirs = value.split(os.pathsep) | 
					
						
							| 
									
										
										
										
											2011-08-23 21:38:13 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-02-09 21:30:25 +01:00
										 |  |  |     # Allow tests to run with an uninstalled Python | 
					
						
							|  |  |  |     if sysconfig.is_python_build(): | 
					
						
							|  |  |  |         pysrcdir = sysconfig.get_config_var('projectbase') | 
					
						
							|  |  |  |         cmd.distribution.include_dirs.append(os.path.join(pysrcdir, 'Include')) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-05-19 13:07:25 +02:00
										 |  |  | try: | 
					
						
							|  |  |  |     from test.support import skip_unless_symlink | 
					
						
							|  |  |  | except ImportError: | 
					
						
							|  |  |  |     skip_unless_symlink = unittest.skip( | 
					
						
							|  |  |  |         'requires test.support.skip_unless_symlink') | 
					
						
							| 
									
										
										
										
											2011-11-03 05:08:28 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | skip_2to3_optimize = unittest.skipIf(sys.flags.optimize, | 
					
						
							|  |  |  |                                      "2to3 doesn't work under -O") |