Issue #13959: Re-implement imp.cache_from_source() in Lib/imp.py.
diff --git a/Lib/imp.py b/Lib/imp.py
index 03b832e..99d8ff7 100644
--- a/Lib/imp.py
+++ b/Lib/imp.py
@@ -10,11 +10,10 @@
                   load_dynamic, get_frozen_object, is_frozen_package,
                   init_builtin, init_frozen, is_builtin, is_frozen,
                   _fix_co_filename)
-# Can (probably) move to importlib
-from _imp import (get_tag, get_suffixes, cache_from_source,
-                  source_from_cache)
 # Could move out of _imp, but not worth the code
 from _imp import get_magic
+# Can (probably) move to importlib
+from _imp import (get_tag, get_suffixes, source_from_cache)
 # Should be re-implemented here (and mostly deprecated)
 from _imp import (find_module, NullImporter,
                   SEARCH_ERROR, PY_SOURCE, PY_COMPILED, C_EXTENSION,
@@ -22,6 +21,7 @@
                   PY_CODERESOURCE, IMP_HOOK)
 
 from importlib._bootstrap import _new_module as new_module
+from importlib._bootstrap import _cache_from_source as cache_from_source
 
 from importlib import _bootstrap
 import os
diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py
index 28db02a..44bac39 100644
--- a/Lib/importlib/_bootstrap.py
+++ b/Lib/importlib/_bootstrap.py
@@ -178,6 +178,31 @@
 
 # Finder/loader utility code ##################################################
 
+PYCACHE = '__pycache__'
+
+DEBUG_BYTECODE_SUFFIX = '.pyc'
+OPT_BYTECODE_SUFFIX = '.pyo'
+BYTECODE_SUFFIX = DEBUG_BYTECODE_SUFFIX if __debug__ else OPT_BYTECODE_SUFFIX
+
+def _cache_from_source(path, debug_override=None):
+    """Given the path to a .py file, return the path to its .pyc/.pyo file.
+
+    The .py file does not need to exist; this simply returns the path to the
+    .pyc/.pyo file calculated as if the .py file were imported.  The extension
+    will be .pyc unless __debug__ is not defined, then it will be .pyo.
+
+    If debug_override is not None, then it must be a boolean and is taken as
+    the value of __debug__ instead.
+
+    """
+    debug = __debug__ if debug_override is None else debug_override
+    suffix = DEBUG_BYTECODE_SUFFIX if debug else OPT_BYTECODE_SUFFIX
+    head, tail = _path_split(path)
+    base_filename, sep, _ = tail.partition('.')
+    filename = '{}{}{}{}'.format(base_filename, sep, _imp.get_tag(), suffix)
+    return _path_join(head, PYCACHE, filename)
+
+
 def verbose_message(message, *args):
     """Print the message to stderr if -v/PYTHONVERBOSE is turned on."""
     if sys.flags.verbose:
@@ -452,7 +477,7 @@
         code_object = self.get_code(name)
         module.__file__ = self.get_filename(name)
         if not sourceless:
-            module.__cached__ = _imp.cache_from_source(module.__file__)
+            module.__cached__ = _cache_from_source(module.__file__)
         else:
             module.__cached__ = module.__file__
         module.__package__ = name
@@ -515,7 +540,7 @@
 
         """
         source_path = self.get_filename(fullname)
-        bytecode_path = _imp.cache_from_source(source_path)
+        bytecode_path = _cache_from_source(source_path)
         source_mtime = None
         if bytecode_path is not None:
             try:
@@ -554,9 +579,6 @@
         verbose_message('code object from {}', source_path)
         if (not sys.dont_write_bytecode and bytecode_path is not None and
             source_mtime is not None):
-            # If e.g. Jython ever implements imp.cache_from_source to have
-            # their own cached file format, this block of code will most likely
-            # throw an exception.
             data = bytearray(_MAGIC_NUMBER)
             data.extend(_w_long(source_mtime))
             data.extend(_w_long(len(source_bytes)))