def _validate_timestamp_pyc(data, source_mtime, source_size, name, exc_details): """Validate a pyc against the source last-modified time. *data* is the contents of the pyc file. (Only the first 16 bytes are required.) *source_mtime* is the last modified timestamp of the source file. *source_size* is None or the size of the source file in bytes. *name* is the name of the module being imported. It is used for logging. *exc_details* is a dictionary passed to ImportError if it raised for improved debugging. An ImportError is raised if the bytecode is stale. """ if _r_long(data[8:12]) != (source_mtime & 0xFFFFFFFF): message = f'bytecode is stale for {name!r}' _bootstrap._verbose_message('{}', message) raise ImportError(message, **exc_details) if (source_size is not None and _r_long(data[12:16]) != (source_size & 0xFFFFFFFF)): raise ImportError(f'bytecode is stale for {name!r}', **exc_details)
def _classify_pyc(data, name, exc_details): """Perform basic validity checking of a pyc header and return the flags field, which determines how the pyc should be further validated against the source. *data* is the contents of the pyc file. (Only the first 16 bytes are required, though.) *name* is the name of the module being imported. It is used for logging. *exc_details* is a dictionary passed to ImportError if it raised for improved debugging. ImportError is raised when the magic number is incorrect or when the flags field is invalid. EOFError is raised when the data is found to be truncated. """ magic = data[:4] if magic != MAGIC_NUMBER: message = f'bad magic number in {name!r}: {magic!r}' _bootstrap._verbose_message('{}', message) raise ImportError(message, **exc_details) if len(data) < 16: message = f'reached EOF while reading pyc header of {name!r}' _bootstrap._verbose_message('{}', message) raise EOFError(message) flags = _r_long(data[4:8]) # Only the first two flags are defined. if flags & ~0b11: message = f'invalid flags {flags!r} in {name!r}' raise ImportError(message, **exc_details) return flags
def _unmarshal_code(pathname, data, mtime): if len(data) < 16: raise ZipImportError('bad pyc data') if data[:4] != _bootstrap_external.MAGIC_NUMBER: _bootstrap._verbose_message('{!r} has bad magic', pathname) return None # signal caller to try alternative flags = _unpack_uint32(data[4:8]) if flags != 0: # Hash-based pyc. We currently refuse to handle checked hash-based # pycs. We could validate hash-based pycs against the source, but it # seems likely that most people putting hash-based pycs in a zipfile # will use unchecked ones. if (_imp.check_hash_based_pycs != 'never' and (flags != 0x1 or _imp.check_hash_based_pycs == 'always')): return None elif mtime != 0 and not _eq_mtime(_unpack_uint32(data[8:12]), mtime): _bootstrap._verbose_message('{!r} has bad mtime', pathname) return None # signal caller to try alternative # XXX the pyc's size field is ignored; timestamp collisions are probably # unimportant with zip files. code = marshal.loads(data[16:]) if not isinstance(code, _code_type): raise TypeError(f'compiled module {pathname!r} is not a code object') return code
def _get_module_code(self, fullname): path = _get_module_path(self, fullname) for suffix, isbytecode, ispackage in _zip_searchorder: fullpath = path + suffix _bootstrap._verbose_message('trying {}{}{}', self.archive, path_sep, fullpath, verbosity=2) try: toc_entry = self._files[fullpath] except KeyError: pass else: modpath = toc_entry[0] data = _get_data(self.archive, toc_entry) if isbytecode: mtime = _get_mtime_of_source(self, fullpath) code = _unmarshal_code(modpath, data, mtime) else: code = _compile_source(modpath, data) if code is None: # bad magic number or non-matching mtime # in byte code, try next continue modpath = toc_entry[0] return code, ispackage, modpath else: raise ZipImportError(f"can't find module {fullname!r}", name=fullname)
def _compile_bytecode(data, name=None, bytecode_path=None, source_path=None): """Compile bytecode as found in a pyc.""" code = marshal.loads(data) if isinstance(code, _code_type): _bootstrap._verbose_message('code object from {!r}', bytecode_path) if source_path is not None: _imp._fix_co_filename(code, source_path) return code else: raise ImportError('Non-code object in {!r}'.format(bytecode_path), name=name, path=bytecode_path)
def get_code(self, fullname): """Concrete implementation of InspectLoader.get_code. Reading of bytecode requires path_stats to be implemented. To write bytecode, set_data must also be implemented. """ source_path = self.get_filename(fullname) source_mtime = None try: bytecode_path = cache_from_source(source_path) except NotImplementedError: bytecode_path = None else: try: st = self.path_stats(source_path) except NotImplementedError: pass else: source_mtime = int(st['mtime']) try: data = self.get_data(bytecode_path) except IOError: pass else: try: bytes_data = self._bytes_from_bytecode( fullname, data, bytecode_path, st) except (ImportError, EOFError): pass else: _verbose_message('{} matches {}', bytecode_path, source_path) found = marshal.loads(bytes_data) if isinstance(found, _code_type): _imp._fix_co_filename(found, source_path) _verbose_message('code object from {}', bytecode_path) return found else: msg = "Non-code object in {}" raise ImportError(msg.format(bytecode_path), name=fullname, path=bytecode_path) source_bytes = self.get_data(source_path) code_object = self.source_to_code(source_bytes, source_path) _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): data = bytearray(_MAGIC_BYTES) data.extend(_w_long(source_mtime)) data.extend(_w_long(len(source_bytes))) data.extend(marshal.dumps(code_object)) try: self._cache_bytecode(source_path, bytecode_path, data) _verbose_message('wrote {!r}', bytecode_path) except NotImplementedError: pass return code_object
def find_loader(self, fullname): """Try to find a loader for the specified module, or the namespace package portions. Returns (loader, list-of-portions).""" is_namespace = False tail_module = fullname.rpartition('.')[2] try: mtime = os.stat(self.path).st_mtime except OSError: mtime = -1 if mtime != self._path_mtime: self._fill_cache() self._path_mtime = mtime # tail_module keeps the original casing, for __file__ and friends if _relax_case(): cache = self._relaxed_path_cache cache_module = tail_module.lower() else: cache = self._path_cache cache_module = tail_module # Check if the module is the name of a directory (and thus a package). if cache_module in cache: base_path = os.path.join(self.path, tail_module) if os.path.isdir(base_path): for suffix, loader in self._loaders: init_filename = '__init__' + suffix full_path = os.path.join(base_path, init_filename) if os.path.isfile(full_path): return (loader(fullname, full_path), [base_path]) else: # A namespace package, return the path if we don't also # find a module in the next section. is_namespace = True # Check for a file w/ a proper suffix exists. for suffix, loader in self._loaders: full_path = os.path.join(self.path, tail_module + suffix) _verbose_message('trying {}'.format(full_path), verbosity=2) if cache_module + suffix in cache: if os.path.isfile(full_path): return (loader(fullname, full_path), []) if is_namespace: _verbose_message('possible namespace for {}'.format(base_path)) return (None, [base_path]) return (None, [])
def get_code(self, fullname): source_path = self.get_filename(fullname) source_mtime = None try: bytecode_path = cache_from_source(source_path) except NotImplementedError: bytecode_path = None else: try: st = self.path_stats(source_path) except NotImplementedError: pass else: source_mtime = int(st['mtime']) try: data = self.get_data(bytecode_path) except IOError: pass else: try: bytes_data = self._poly_bytes_from_bytecode( fullname, data, bytecode_path, st) except (ImportError, EOFError): pass else: _verbose_message('{} matches {}', bytecode_path, source_path) found = marshal.loads(bytes_data) if isinstance(found, _code_type): _imp._fix_co_filename(found, source_path) _verbose_message('code object from {}', bytecode_path) return found else: msg = "Non-code object in {}" raise ImportError(msg.format(bytecode_path), name=fullname, path=bytecode_path) source_bytes = self.get_data(source_path) code_object = self._compiler(source_bytes, source_path, fullname) _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): data = bytearray(MAGIC_NUMBER) data.extend(_w_long(source_mtime)) data.extend(_w_long(len(source_bytes))) data.extend(marshal.dumps(code_object)) try: self._cache_bytecode(source_path, bytecode_path, data) _verbose_message('wrote {!r}', bytecode_path) except NotImplementedError: pass return code_object
def get_code(self, fullname): source_path = self.get_filename(fullname) source_mtime = None try: bytecode_path = cache_from_source(source_path) except NotImplementedError: bytecode_path = None else: try: st = self.path_stats(source_path) except NotImplementedError: pass else: source_mtime = int(st['mtime']) try: data = self.get_data(bytecode_path) except IOError: pass else: try: bytes_data = self._poly_bytes_from_bytecode(fullname, data, bytecode_path, st) except (ImportError, EOFError): pass else: _verbose_message('{} matches {}', bytecode_path, source_path) found = marshal.loads(bytes_data) if isinstance(found, _code_type): _imp._fix_co_filename(found, source_path) _verbose_message('code object from {}', bytecode_path) return found else: msg = "Non-code object in {}" raise ImportError(msg.format(bytecode_path), name=fullname, path=bytecode_path) source_bytes = self.get_data(source_path) code_object = self._compiler(source_bytes, source_path, fullname) _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): data = bytearray(MAGIC_NUMBER) data.extend(_w_long(source_mtime)) data.extend(_w_long(len(source_bytes))) data.extend(marshal.dumps(code_object)) try: self._cache_bytecode(source_path, bytecode_path, data) _verbose_message('wrote {!r}', bytecode_path) except NotImplementedError: pass return code_object
def set_data(self, path, data, *, _mode=0o666): """Write bytes data to a file.""" parent, filename = os.path.split(path) path_parts = [] # Figure out what directories are missing. while parent and not os.path.isdir(parent): parent, part = os.path.split(parent) path_parts.append(part) # Create needed directories. for part in reversed(path_parts): parent = os.path.join(parent, part) try: os.mkdir(parent) except FileExistsError: # Probably another Python process already created the dir. continue except OSError as exc: # Could be a permission error, read-only filesystem: just forget # about writing the data. _bootstrap._verbose_message('could not create {!r}: {!r}', parent, exc) return try: _write_atomic(path, data, _mode) _bootstrap._verbose_message('created {!r}', path) except OSError as exc: # Same as above: just don't write the bytecode. _bootstrap._verbose_message('could not create {!r}: {!r}', path, exc)
def get_code(self, fullname): """Concrete implementation of InspectLoader.get_code. Reading of bytecode requires path_stats to be implemented. To write bytecode, set_data must also be implemented. """ source_path = self.get_filename(fullname) source_mtime = None try: # XXX: begin our change bytecode_path = da_cache_from_source(source_path) # XXX: end our change except NotImplementedError: bytecode_path = None else: # XXX: begin our change if not get_runtime_option('recompile', default=False): # XXX: end our change try: st = self.path_stats(source_path) except IOError: pass else: source_mtime = int(st['mtime']) try: data = self.get_data(bytecode_path) except OSError: pass else: try: bytes_data = _validate_bytecode_header( data, source_stats=st, name=fullname, path=bytecode_path) except (ImportError, EOFError): pass else: _verbose_message('{} matches {}', bytecode_path, source_path) return _compile_bytecode( bytes_data, name=fullname, bytecode_path=bytecode_path, source_path=source_path) source_bytes = self.get_data(source_path) code_object = self.source_to_code(source_bytes, source_path) _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): data = _code_to_bytecode(code_object, source_mtime, len(source_bytes)) try: self._cache_bytecode(source_path, bytecode_path, data) _verbose_message('wrote {!r}', bytecode_path) except NotImplementedError: pass return code_object
def load_module(self, fullname): """load_module(fullname) -> module. Load the module specified by 'fullname'. 'fullname' must be the fully qualified (dotted) module name. It returns the imported module, or raises ZipImportError if it wasn't found. """ code, ispackage, modpath = _get_module_code(self, fullname) mod = sys.modules.get(fullname) if mod is None or not isinstance(mod, _module_type): mod = _module_type(fullname) sys.modules[fullname] = mod mod.__loader__ = self try: if ispackage: # add __path__ to the module *before* the code gets # executed path = _get_module_path(self, fullname) fullpath = _bootstrap_external._path_join(self.archive, path) mod.__path__ = [fullpath] if not hasattr(mod, '__builtins__'): mod.__builtins__ = __builtins__ _bootstrap_external._fix_up_module(mod.__dict__, fullname, modpath) exec(code, mod.__dict__) except: del sys.modules[fullname] raise try: mod = sys.modules[fullname] except KeyError: raise ImportError( f'Loaded module {fullname!r} not found in sys.modules') _bootstrap._verbose_message('import {} # loaded from Zip {}', fullname, modpath) return mod
def get_code(self, fullname): """Concrete implementation of InspectLoader.get_code. Reading of bytecode requires path_stats to be implemented. To write bytecode, set_data must also be implemented. """ source_path = self.get_filename(fullname) source_mtime = None try: # XXX: begin our change bytecode_path = da_cache_from_source(source_path) # XXX: end our change except NotImplementedError: bytecode_path = None else: # XXX: begin our change if not common.get_runtime_option('recompile', default=False): # XXX: end our change try: st = self.path_stats(source_path) except IOError: pass else: source_mtime = int(st['mtime']) try: data = self.get_data(bytecode_path) except OSError: pass else: try: bytes_data = _validate_bytecode_header(data, source_stats=st, name=fullname, path=bytecode_path) except (ImportError, EOFError): pass else: _verbose_message('{} matches {}', bytecode_path, source_path) return _compile_bytecode(bytes_data, name=fullname, bytecode_path=bytecode_path, source_path=source_path) source_bytes = self.get_data(source_path) code_object = self.source_to_code(source_bytes, source_path) _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): data = _code_to_bytecode(code_object, source_mtime, len(source_bytes)) try: self._cache_bytecode(source_path, bytecode_path, data) _verbose_message('wrote {!r}', bytecode_path) except NotImplementedError: pass return code_object
def _get_decompress_func(): global _importing_zlib if _importing_zlib: # Someone has a zlib.py[co] in their Zip file # let's avoid a stack overflow. _bootstrap._verbose_message('zipimport: zlib UNAVAILABLE') raise ZipImportError("can't decompress data; zlib not available") _importing_zlib = True try: from zlib import decompress except Exception: _bootstrap._verbose_message('zipimport: zlib UNAVAILABLE') raise ZipImportError("can't decompress data; zlib not available") finally: _importing_zlib = False _bootstrap._verbose_message('zipimport: zlib available') return decompress
def get_code(self, fullname): """Concrete implementation of InspectLoader.get_code. Reading of bytecode requires path_stats to be implemented. To write bytecode, set_data must also be implemented. """ source_path = self.get_filename(fullname) source_mtime = None source_bytes = None source_hash = None hash_based = False check_source = True try: # XXX: begin our change bytecode_path = da_cache_from_source(source_path) # XXX: end our change except NotImplementedError: bytecode_path = None else: # XXX: begin our change if not common.get_runtime_option('recompile', default=False): # XXX: end our change try: st = self.path_stats(source_path) except OSError: pass else: source_mtime = int(st['mtime']) try: data = self.get_data(bytecode_path) except OSError: pass else: exc_details = { 'name': fullname, 'path': bytecode_path, } try: flags = _classify_pyc(data, fullname, exc_details) bytes_data = memoryview(data)[16:] hash_based = flags & 0b1 != 0 if hash_based: check_source = flags & 0b10 != 0 if (_imp.check_hash_based_pycs != 'never' and (check_source or _imp.check_hash_based_pycs == 'always')): source_bytes = self.get_data(source_path) source_hash = _imp.source_hash( _RAW_MAGIC_NUMBER, source_bytes, ) _validate_hash_pyc(data, source_hash, fullname, exc_details) else: _validate_timestamp_pyc( data, source_mtime, st['size'], fullname, exc_details, ) except (ImportError, EOFError): pass else: _verbose_message('{} matches {}', bytecode_path, source_path) return _compile_bytecode(bytes_data, name=fullname, bytecode_path=bytecode_path, source_path=source_path) if source_bytes is None: source_bytes = self.get_data(source_path) code_object = self.source_to_code(source_bytes, source_path) _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 hash_based: if source_hash is None: source_hash = _imp.source_hash(source_bytes) data = _code_to_hash_pyc(code_object, source_hash, check_source) else: data = _code_to_timestamp_pyc(code_object, source_mtime, len(source_bytes)) try: self._cache_bytecode(source_path, bytecode_path, data) _verbose_message('wrote {!r}', bytecode_path) except NotImplementedError: pass return code_object
def _read_directory(archive): try: fp = _io.open(archive, 'rb') except OSError: raise ZipImportError(f"can't open Zip file: {archive!r}", path=archive) with fp: try: fp.seek(-END_CENTRAL_DIR_SIZE, 2) header_position = fp.tell() buffer = fp.read(END_CENTRAL_DIR_SIZE) except OSError: raise ZipImportError(f"can't read Zip file: {archive!r}", path=archive) if len(buffer) != END_CENTRAL_DIR_SIZE: raise ZipImportError(f"can't read Zip file: {archive!r}", path=archive) if buffer[:4] != STRING_END_ARCHIVE: # Bad: End of Central Dir signature # Check if there's a comment. try: fp.seek(0, 2) file_size = fp.tell() except OSError: raise ZipImportError(f"can't read Zip file: {archive!r}", path=archive) max_comment_start = max( file_size - MAX_COMMENT_LEN - END_CENTRAL_DIR_SIZE, 0) try: fp.seek(max_comment_start) data = fp.read() except OSError: raise ZipImportError(f"can't read Zip file: {archive!r}", path=archive) pos = data.rfind(STRING_END_ARCHIVE) if pos < 0: raise ZipImportError(f'not a Zip file: {archive!r}', path=archive) buffer = data[pos:pos + END_CENTRAL_DIR_SIZE] if len(buffer) != END_CENTRAL_DIR_SIZE: raise ZipImportError(f"corrupt Zip file: {archive!r}", path=archive) header_position = file_size - len(data) + pos header_size = _unpack_uint32(buffer[12:16]) header_offset = _unpack_uint32(buffer[16:20]) if header_position < header_size: raise ZipImportError(f'bad central directory size: {archive!r}', path=archive) if header_position < header_offset: raise ZipImportError(f'bad central directory offset: {archive!r}', path=archive) header_position -= header_size arc_offset = header_position - header_offset if arc_offset < 0: raise ZipImportError( f'bad central directory size or offset: {archive!r}', path=archive) files = {} # Start of Central Directory count = 0 try: fp.seek(header_position) except OSError: raise ZipImportError(f"can't read Zip file: {archive!r}", path=archive) while True: buffer = fp.read(46) if len(buffer) < 4: raise EOFError('EOF read where not expected') # Start of file header if buffer[:4] != b'PK\x01\x02': break # Bad: Central Dir File Header if len(buffer) != 46: raise EOFError('EOF read where not expected') flags = _unpack_uint16(buffer[8:10]) compress = _unpack_uint16(buffer[10:12]) time = _unpack_uint16(buffer[12:14]) date = _unpack_uint16(buffer[14:16]) crc = _unpack_uint32(buffer[16:20]) data_size = _unpack_uint32(buffer[20:24]) file_size = _unpack_uint32(buffer[24:28]) name_size = _unpack_uint16(buffer[28:30]) extra_size = _unpack_uint16(buffer[30:32]) comment_size = _unpack_uint16(buffer[32:34]) file_offset = _unpack_uint32(buffer[42:46]) header_size = name_size + extra_size + comment_size if file_offset > header_offset: raise ZipImportError(f'bad local header offset: {archive!r}', path=archive) file_offset += arc_offset try: name = fp.read(name_size) except OSError: raise ZipImportError(f"can't read Zip file: {archive!r}", path=archive) if len(name) != name_size: raise ZipImportError(f"can't read Zip file: {archive!r}", path=archive) # On Windows, calling fseek to skip over the fields we don't use is # slower than reading the data because fseek flushes stdio's # internal buffers. See issue #8745. try: if len(fp.read(header_size - name_size)) != header_size - name_size: raise ZipImportError(f"can't read Zip file: {archive!r}", path=archive) except OSError: raise ZipImportError(f"can't read Zip file: {archive!r}", path=archive) if flags & 0x800: # UTF-8 file names extension name = name.decode() else: # Historical ZIP filename encoding try: name = name.decode('ascii') except UnicodeDecodeError: name = name.decode('latin1').translate(cp437_table) name = name.replace('/', path_sep) path = _bootstrap_external._path_join(archive, name) t = (path, compress, data_size, file_size, file_offset, time, date, crc) files[name] = t count += 1 _bootstrap._verbose_message('zipimport: found {} names in {!r}', count, archive) return files
def find_spec(self, fullname, target=None): """Try to find a spec for the specified module. Returns the matching spec, or None if not found. """ print(f"JinjaFinder.find_spec({fullname} path={self.path})") is_namespace = False tail_module = fullname.rpartition(".")[2] try: mtime = _path_stat(self.path or _os.getcwd()).st_mtime except OSError: mtime = -1 if mtime != self._path_mtime: self._fill_cache() self._path_mtime = mtime # tail_module keeps the original casing, for __file__ and friends if _relax_case(): cache = self._relaxed_path_cache cache_module = tail_module.lower() else: cache = self._path_cache cache_module = tail_module # Check if the module is the name of a directory (and thus a package). print( f"JinjaFinder.find_spec - looking in cache for {cache_module} {cache_module in cache}" ) if cache_module in cache: base_path = _path_join(self.path, tail_module) for suffix, loader_class in self._loaders: init_filename = "__init__" + suffix full_path = _path_join(base_path, init_filename) print(f" Looking for file {full_path}") if _path_isfile(full_path): return self._get_spec( loader_class, fullname, full_path, [base_path], target ) else: # If a namespace package, return the path if we don't # find a module in the next section. is_namespace = _path_isdir(base_path) # Check for a file w/ a proper suffix exists. for suffix, loader_class in self._loaders: full_path = _path_join(self.path, tail_module + suffix) print(f" -- full_path={full_path} loader_class={loader_class} ") if (cache_module + suffix) not in cache: print(f" {cache_module+suffix} not in cache {cache}") _bootstrap._verbose_message("trying {}", full_path, verbosity=2) if cache_module + suffix in cache: if _path_isfile(full_path): print( f" - about to call _get_spec({loader_class}, {fullname}, {full_path})" ) return self._get_spec( loader_class, fullname, full_path, None, target ) if is_namespace: _bootstrap._verbose_message("possible namespace for {}", base_path) spec = _bootstrap.ModuleSpec(fullname, None) spec.submodule_search_locations = [base_path] return spec return None
def get_code(self, fullname): """Concrete implementation of InspectLoader.get_code. Reading of bytecode requires path_stats to be implemented. To write bytecode, set_data must also be implemented. """ source_path = self.get_filename(fullname) source_mtime = None source_bytes = None source_hash = None hash_based = False check_source = True try: bytecode_path = cache_from_source(source_path) except NotImplementedError: bytecode_path = None else: try: st = self.path_stats(source_path) except OSError: pass else: source_mtime = int(st['mtime']) try: data = self.get_data(bytecode_path) except OSError: pass else: exc_details = { 'name': fullname, 'path': bytecode_path, } try: flags = _classify_pyc(data, fullname, exc_details) bytes_data = memoryview(data)[16:] hash_based = flags & 0b1 != 0 if hash_based: check_source = flags & 0b10 != 0 if (_imp.check_hash_based_pycs != 'never' and (check_source or _imp.check_hash_based_pycs == 'always')): source_bytes = self.get_data(source_path) source_hash = _imp.source_hash( _RAW_MAGIC_NUMBER, source_bytes, ) _validate_hash_pyc(data, source_hash, fullname, exc_details) else: _validate_timestamp_pyc( data, source_mtime, st['size'], fullname, exc_details, ) except (ImportError, EOFError): pass else: _bootstrap._verbose_message('{} matches {}', bytecode_path, source_path) return _compile_bytecode(bytes_data, name=fullname, bytecode_path=bytecode_path, source_path=source_path) if source_bytes is None: source_bytes = self.get_data(source_path) code_object = self.source_to_code(source_bytes, source_path) _bootstrap._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 hash_based: if source_hash is None: source_hash = _imp.source_hash(source_bytes) data = _code_to_hash_pyc(code_object, source_hash, check_source) else: data = _code_to_timestamp_pyc(code_object, source_mtime, len(source_bytes)) try: self._cache_bytecode(source_path, bytecode_path, data) _bootstrap._verbose_message('wrote {!r}', bytecode_path) except NotImplementedError: pass return code_object