Пример #1
0
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)
Пример #2
0
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
Пример #3
0
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
Пример #4
0
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)
Пример #5
0
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)
Пример #6
0
    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
Пример #7
0
 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, [])
Пример #8
0
 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
Пример #9
0
 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, [])
Пример #10
0
 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
Пример #11
0
 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)
Пример #12
0
    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
Пример #13
0
    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
Пример #14
0
    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
Пример #15
0
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
Пример #16
0
    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
Пример #17
0
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
Пример #18
0
    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
Пример #19
0
    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