summaryrefslogtreecommitdiffstats
path: root/Lib/importlib/test/source/util.py
diff options
context:
space:
mode:
authorBrett Cannon <bcannon@gmail.com>2009-02-01 03:08:31 (GMT)
committerBrett Cannon <bcannon@gmail.com>2009-02-01 03:08:31 (GMT)
commit4ee2cdaf65971391b35ce7aaad5ce77ddcbb176e (patch)
tree2b78c7431d811433f09bfdc7a2994c8f7cc4dbcb /Lib/importlib/test/source/util.py
parent30b047dc35fe7a94036de374d13754bff6ac9afa (diff)
downloadcpython-4ee2cdaf65971391b35ce7aaad5ce77ddcbb176e.zip
cpython-4ee2cdaf65971391b35ce7aaad5ce77ddcbb176e.tar.gz
cpython-4ee2cdaf65971391b35ce7aaad5ce77ddcbb176e.tar.bz2
Split out support code that is specific to source tests out of
importlib.test.support to importlib.test.source.util.
Diffstat (limited to 'Lib/importlib/test/source/util.py')
-rw-r--r--Lib/importlib/test/source/util.py88
1 files changed, 88 insertions, 0 deletions
diff --git a/Lib/importlib/test/source/util.py b/Lib/importlib/test/source/util.py
new file mode 100644
index 0000000..5400c82
--- /dev/null
+++ b/Lib/importlib/test/source/util.py
@@ -0,0 +1,88 @@
+from .. import support as util
+import contextlib
+import imp
+import os
+import os.path
+import sys
+import tempfile
+from test import support as support
+
+
+def writes_bytecode(fxn):
+ """Decorator that returns the function if writing bytecode is enabled, else
+ a stub function that accepts anything and simply returns None."""
+ if sys.dont_write_bytecode:
+ return lambda *args, **kwargs: None
+ else:
+ return fxn
+
+
+def bytecode_path(source_path):
+ for suffix, _, type_ in imp.get_suffixes():
+ if type_ == imp.PY_COMPILED:
+ bc_suffix = suffix
+ break
+ else:
+ raise ValueError("no bytecode suffix is defined")
+ return os.path.splitext(source_path)[0] + bc_suffix
+
+
+@contextlib.contextmanager
+def create_modules(*names):
+ """Temporarily create each named module with an attribute (named 'attr')
+ that contains the name passed into the context manager that caused the
+ creation of the module.
+
+ All files are created in a temporary directory specified by
+ tempfile.gettempdir(). This directory is inserted at the beginning of
+ sys.path. When the context manager exits all created files (source and
+ bytecode) are explicitly deleted.
+
+ No magic is performed when creating packages! This means that if you create
+ a module within a package you must also create the package's __init__ as
+ well.
+
+ """
+ source = 'attr = {0!r}'
+ created_paths = []
+ mapping = {}
+ try:
+ temp_dir = tempfile.gettempdir()
+ mapping['.root'] = temp_dir
+ import_names = set()
+ for name in names:
+ if not name.endswith('__init__'):
+ import_name = name
+ else:
+ import_name = name[:-len('.__init__')]
+ import_names.add(import_name)
+ if import_name in sys.modules:
+ del sys.modules[import_name]
+ name_parts = name.split('.')
+ file_path = temp_dir
+ for directory in name_parts[:-1]:
+ file_path = os.path.join(file_path, directory)
+ if not os.path.exists(file_path):
+ os.mkdir(file_path)
+ created_paths.append(file_path)
+ file_path = os.path.join(file_path, name_parts[-1] + '.py')
+ with open(file_path, 'w') as file:
+ file.write(source.format(name))
+ created_paths.append(file_path)
+ mapping[name] = file_path
+ uncache_manager = util.uncache(*import_names)
+ uncache_manager.__enter__()
+ state_manager = util.import_state(path=[temp_dir])
+ state_manager.__enter__()
+ yield mapping
+ finally:
+ state_manager.__exit__(None, None, None)
+ uncache_manager.__exit__(None, None, None)
+ # Reverse the order for path removal to unroll directory creation.
+ for path in reversed(created_paths):
+ if file_path.endswith('.py'):
+ support.unlink(path)
+ support.unlink(path + 'c')
+ support.unlink(path + 'o')
+ else:
+ os.rmdir(path)