Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes15kdownloads
install_lib.py237 linesDownload Raw Back to command
1"""distutils.command.install_lib2 3Implements the Distutils 'install_lib' command4(install all Python modules)."""5 6from __future__ import annotations7 8import importlib.util9import os10import sys11from typing import Any, ClassVar12 13from ..core import Command14from ..errors import DistutilsOptionError15 16# Extension for Python source files.17PYTHON_SOURCE_EXTENSION = ".py"18 19 20class install_lib(Command):21    description = "install all Python modules (extensions and pure Python)"22 23    # The byte-compilation options are a tad confusing.  Here are the24    # possible scenarios:25    #   1) no compilation at all (--no-compile --no-optimize)26    #   2) compile .pyc only (--compile --no-optimize; default)27    #   3) compile .pyc and "opt-1" .pyc (--compile --optimize)28    #   4) compile "opt-1" .pyc only (--no-compile --optimize)29    #   5) compile .pyc and "opt-2" .pyc (--compile --optimize-more)30    #   6) compile "opt-2" .pyc only (--no-compile --optimize-more)31    #32    # The UI for this is two options, 'compile' and 'optimize'.33    # 'compile' is strictly boolean, and only decides whether to34    # generate .pyc files.  'optimize' is three-way (0, 1, or 2), and35    # decides both whether to generate .pyc files and what level of36    # optimization to use.37 38    user_options = [39        ('install-dir=', 'd', "directory to install to"),40        ('build-dir=', 'b', "build directory (where to install from)"),41        ('force', 'f', "force installation (overwrite existing files)"),42        ('compile', 'c', "compile .py to .pyc [default]"),43        ('no-compile', None, "don't compile .py files"),44        (45            'optimize=',46            'O',47            "also compile with optimization: -O1 for \"python -O\", "48            "-O2 for \"python -OO\", and -O0 to disable [default: -O0]",49        ),50        ('skip-build', None, "skip the build steps"),51    ]52 53    boolean_options: ClassVar[list[str]] = ['force', 'compile', 'skip-build']54    negative_opt: ClassVar[dict[str, str]] = {'no-compile': 'compile'}55 56    def initialize_options(self):57        # let the 'install' command dictate our installation directory58        self.install_dir = None59        self.build_dir = None60        self.force = False61        self.compile = None62        self.optimize = None63        self.skip_build = None64 65    def finalize_options(self) -> None:66        # Get all the information we need to install pure Python modules67        # from the umbrella 'install' command -- build (source) directory,68        # install (target) directory, and whether to compile .py files.69        self.set_undefined_options(70            'install',71            ('build_lib', 'build_dir'),72            ('install_lib', 'install_dir'),73            ('force', 'force'),74            ('compile', 'compile'),75            ('optimize', 'optimize'),76            ('skip_build', 'skip_build'),77        )78 79        if self.compile is None:80            self.compile = True81        if self.optimize is None:82            self.optimize = False83 84        if not isinstance(self.optimize, int):85            try:86                self.optimize = int(self.optimize)87            except ValueError:88                pass89            if self.optimize not in (0, 1, 2):90                raise DistutilsOptionError("optimize must be 0, 1, or 2")91 92    def run(self) -> None:93        # Make sure we have built everything we need first94        self.build()95 96        # Install everything: simply dump the entire contents of the build97        # directory to the installation directory (that's the beauty of98        # having a build directory!)99        outfiles = self.install()100 101        # (Optionally) compile .py to .pyc102        if outfiles is not None and self.distribution.has_pure_modules():103            self.byte_compile(outfiles)104 105    # -- Top-level worker functions ------------------------------------106    # (called from 'run()')107 108    def build(self) -> None:109        if not self.skip_build:110            if self.distribution.has_pure_modules():111                self.run_command('build_py')112            if self.distribution.has_ext_modules():113                self.run_command('build_ext')114 115    # Any: https://typing.readthedocs.io/en/latest/guides/writing_stubs.html#the-any-trick116    def install(self) -> list[str] | Any:117        if os.path.isdir(self.build_dir):118            outfiles = self.copy_tree(self.build_dir, self.install_dir)119        else:120            self.warn(121                f"'{self.build_dir}' does not exist -- no Python modules to install"122            )123            return124        return outfiles125 126    def byte_compile(self, files) -> None:127        if sys.dont_write_bytecode:128            self.warn('byte-compiling is disabled, skipping.')129            return130 131        from ..util import byte_compile132 133        # Get the "--root" directory supplied to the "install" command,134        # and use it as a prefix to strip off the purported filename135        # encoded in bytecode files.  This is far from complete, but it136        # should at least generate usable bytecode in RPM distributions.137        install_root = self.get_finalized_command('install').root138 139        if self.compile:140            byte_compile(141                files,142                optimize=0,143                force=self.force,144                prefix=install_root,145            )146        if self.optimize > 0:147            byte_compile(148                files,149                optimize=self.optimize,150                force=self.force,151                prefix=install_root,152                verbose=self.verbose,153            )154 155    # -- Utility methods -----------------------------------------------156 157    def _mutate_outputs(self, has_any, build_cmd, cmd_option, output_dir):158        if not has_any:159            return []160 161        build_cmd = self.get_finalized_command(build_cmd)162        build_files = build_cmd.get_outputs()163        build_dir = getattr(build_cmd, cmd_option)164 165        prefix_len = len(build_dir) + len(os.sep)166        outputs = [os.path.join(output_dir, file[prefix_len:]) for file in build_files]167 168        return outputs169 170    def _bytecode_filenames(self, py_filenames):171        bytecode_files = []172        for py_file in py_filenames:173            # Since build_py handles package data installation, the174            # list of outputs can contain more than just .py files.175            # Make sure we only report bytecode for the .py files.176            ext = os.path.splitext(os.path.normcase(py_file))[1]177            if ext != PYTHON_SOURCE_EXTENSION:178                continue179            if self.compile:180                bytecode_files.append(181                    importlib.util.cache_from_source(py_file, optimization='')182                )183            if self.optimize > 0:184                bytecode_files.append(185                    importlib.util.cache_from_source(186                        py_file, optimization=self.optimize187                    )188                )189 190        return bytecode_files191 192    # -- External interface --------------------------------------------193    # (called by outsiders)194 195    def get_outputs(self):196        """Return the list of files that would be installed if this command197        were actually run.  Not affected by the "dry-run" flag or whether198        modules have actually been built yet.199        """200        pure_outputs = self._mutate_outputs(201            self.distribution.has_pure_modules(),202            'build_py',203            'build_lib',204            self.install_dir,205        )206        if self.compile:207            bytecode_outputs = self._bytecode_filenames(pure_outputs)208        else:209            bytecode_outputs = []210 211        ext_outputs = self._mutate_outputs(212            self.distribution.has_ext_modules(),213            'build_ext',214            'build_lib',215            self.install_dir,216        )217 218        return pure_outputs + bytecode_outputs + ext_outputs219 220    def get_inputs(self):221        """Get the list of files that are input to this command, ie. the222        files that get installed as they are named in the build tree.223        The files in this list correspond one-to-one to the output224        filenames returned by 'get_outputs()'.225        """226        inputs = []227 228        if self.distribution.has_pure_modules():229            build_py = self.get_finalized_command('build_py')230            inputs.extend(build_py.get_outputs())231 232        if self.distribution.has_ext_modules():233            build_ext = self.get_finalized_command('build_ext')234            inputs.extend(build_ext.get_outputs())235 236        return inputs237 
codekingpro/portable-devtools · Team Ai