示例#1
0
def load_matplotlib(finder: cx_Freeze.finder.ModuleFinder, module: cx_Freeze.module.Module) -> None:
    """The matplotlib package requires mpl-data subdirectory."""
    data_path = module.path[0] / "mpl-data"
    target_path = Path("lib", module.name, "mpl-data")
    # After matplotlib 3.4 mpl-data is guaranteed to be a subdirectory.
    if not data_path.is_dir():
        data_path = __import__("matplotlib").get_data_path()
        need_patch = True
    else:
        need_patch = not module.in_file_system
    finder.IncludeFiles(data_path, target_path, copy_dependent_files=False)
    finder.IncludePackage("matplotlib")
    finder.ExcludeModule("matplotlib.tests")
    finder.ExcludeModule("matplotlib.testing")
    if not need_patch or module.code is None:
        return
    CODE_STR = f"""
def _get_data_path():
    return os.path.join(os.path.dirname(sys.executable), "{target_path!s}")
"""
    for code_str in [CODE_STR, CODE_STR.replace("_get_data_", "get_data_")]:
        new_code = compile(code_str, str(module.file), "exec")
        co_func = new_code.co_consts[0]
        name = co_func.co_name
        code = module.code
        consts = list(code.co_consts)
        for i, c in enumerate(consts):
            if isinstance(c, type(code)) and c.co_name == name:
                consts[i] = co_func
                break
        module.code = code_object_replace(code, co_consts=consts)
示例#2
0
 def _replace_package_in_code(self, module: Module) -> CodeType:
     """
     Replace the value of __package__ directly in the code,
     when the module is in a package and will be stored in library.zip.
     """
     code = module.code
     # Check if module is in a package and will be stored in library.zip
     # and is not defined in the module, like 'six' do
     if (
         module.parent is None
         or module.in_file_system
         or "__package__" in module.global_names
         or code is None
     ):
         return code
     # Only if the code references it.
     if "__package__" in code.co_names:
         consts = list(code.co_consts)
         pkg_const_index = len(consts)
         pkg_name_index = code.co_names.index("__package__")
         if pkg_const_index > 255 or pkg_name_index > 255:
             # Don't touch modules with many constants or names;
             # This is good for now.
             return code
         # Insert a bytecode to represent the code:
         # __package__ = module.parent.name
         codes = [LOAD_CONST, pkg_const_index, STORE_NAME, pkg_name_index]
         codestring = bytes(codes) + code.co_code
         consts.append(module.parent.name)
         code = code_object_replace(
             code, co_code=codestring, co_consts=consts
         )
     return code
示例#3
0
    def _replace_paths_in_code(
        self, module: Module, code: Optional[CodeType] = None
    ) -> CodeType:
        """
        Replace paths in the code as directed, returning a new code object
        with the modified paths in place.
        """
        top_level_module = module  # type: Module
        while top_level_module.parent is not None:
            top_level_module = top_level_module.parent
        if code is None:
            code = module.code
        # Prepare the new filename.
        new_filename = original_filename = os.path.normpath(code.co_filename)
        for search_value, replace_value in self.replace_paths:
            if search_value == "*":
                if top_level_module.file is None:
                    continue
                search_value = os.path.dirname(top_level_module.file)
                if top_level_module.path:
                    search_value = os.path.dirname(search_value)
                if search_value:
                    search_value = search_value + os.path.sep
            if original_filename.startswith(search_value):
                new_filename = (
                    replace_value + original_filename[len(search_value) :]
                )
                break

        # Run on subordinate code objects from function & class definitions.
        consts = list(code.co_consts)
        for i in range(len(consts)):
            if isinstance(consts[i], type(code)):
                consts[i] = self._replace_paths_in_code(
                    top_level_module, consts[i]
                )

        return code_object_replace(
            code, co_consts=consts, co_filename=new_filename
        )