Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
py_compile.py213 linesDownload Raw Back to Lib
1"""Routine to "compile" a .py file to a .pyc file.2 3This module has intimate knowledge of the format of .pyc files.4"""5 6import enum7import importlib._bootstrap_external8import importlib.machinery9import importlib.util10import os11import os.path12import sys13import traceback14 15__all__ = ["compile", "main", "PyCompileError", "PycInvalidationMode"]16 17 18class PyCompileError(Exception):19    """Exception raised when an error occurs while attempting to20    compile the file.21 22    To raise this exception, use23 24        raise PyCompileError(exc_type,exc_value,file[,msg])25 26    where27 28        exc_type:   exception type to be used in error message29                    type name can be accesses as class variable30                    'exc_type_name'31 32        exc_value:  exception value to be used in error message33                    can be accesses as class variable 'exc_value'34 35        file:       name of file being compiled to be used in error message36                    can be accesses as class variable 'file'37 38        msg:        string message to be written as error message39                    If no value is given, a default exception message will be40                    given, consistent with 'standard' py_compile output.41                    message (or default) can be accesses as class variable42                    'msg'43 44    """45 46    def __init__(self, exc_type, exc_value, file, msg=''):47        exc_type_name = exc_type.__name__48        if exc_type is SyntaxError:49            tbtext = ''.join(traceback.format_exception_only(50                exc_type, exc_value))51            errmsg = tbtext.replace('File "<string>"', 'File "%s"' % file)52        else:53            errmsg = "Sorry: %s: %s" % (exc_type_name,exc_value)54 55        Exception.__init__(self,msg or errmsg,exc_type_name,exc_value,file)56 57        self.exc_type_name = exc_type_name58        self.exc_value = exc_value59        self.file = file60        self.msg = msg or errmsg61 62    def __str__(self):63        return self.msg64 65 66class PycInvalidationMode(enum.Enum):67    TIMESTAMP = 168    CHECKED_HASH = 269    UNCHECKED_HASH = 370 71 72def _get_default_invalidation_mode():73    if os.environ.get('SOURCE_DATE_EPOCH'):74        return PycInvalidationMode.CHECKED_HASH75    else:76        return PycInvalidationMode.TIMESTAMP77 78 79def compile(file, cfile=None, dfile=None, doraise=False, optimize=-1,80            invalidation_mode=None, quiet=0):81    """Byte-compile one Python source file to Python bytecode.82 83    :param file: The source file name.84    :param cfile: The target byte compiled file name.  When not given, this85        defaults to the PEP 3147/PEP 488 location.86    :param dfile: Purported file name, i.e. the file name that shows up in87        error messages.  Defaults to the source file name.88    :param doraise: Flag indicating whether or not an exception should be89        raised when a compile error is found.  If an exception occurs and this90        flag is set to False, a string indicating the nature of the exception91        will be printed, and the function will return to the caller. If an92        exception occurs and this flag is set to True, a PyCompileError93        exception will be raised.94    :param optimize: The optimization level for the compiler.  Valid values95        are -1, 0, 1 and 2.  A value of -1 means to use the optimization96        level of the current interpreter, as given by -O command line options.97    :param invalidation_mode:98    :param quiet: Return full output with False or 0, errors only with 1,99        and no output with 2.100 101    :return: Path to the resulting byte compiled file.102 103    Note that it isn't necessary to byte-compile Python modules for104    execution efficiency -- Python itself byte-compiles a module when105    it is loaded, and if it can, writes out the bytecode to the106    corresponding .pyc file.107 108    However, if a Python installation is shared between users, it is a109    good idea to byte-compile all modules upon installation, since110    other users may not be able to write in the source directories,111    and thus they won't be able to write the .pyc file, and then112    they would be byte-compiling every module each time it is loaded.113    This can slow down program start-up considerably.114 115    See compileall.py for a script/module that uses this module to116    byte-compile all installed files (or all files in selected117    directories).118 119    Do note that FileExistsError is raised if cfile ends up pointing at a120    non-regular file or symlink. Because the compilation uses a file renaming,121    the resulting file would be regular and thus not the same type of file as122    it was previously.123    """124    if invalidation_mode is None:125        invalidation_mode = _get_default_invalidation_mode()126    if cfile is None:127        if optimize >= 0:128            optimization = optimize if optimize >= 1 else ''129            cfile = importlib.util.cache_from_source(file,130                                                     optimization=optimization)131        else:132            cfile = importlib.util.cache_from_source(file)133    if os.path.islink(cfile):134        msg = ('{} is a symlink and will be changed into a regular file if '135               'import writes a byte-compiled file to it')136        raise FileExistsError(msg.format(cfile))137    elif os.path.exists(cfile) and not os.path.isfile(cfile):138        msg = ('{} is a non-regular file and will be changed into a regular '139               'one if import writes a byte-compiled file to it')140        raise FileExistsError(msg.format(cfile))141    loader = importlib.machinery.SourceFileLoader('<py_compile>', file)142    source_bytes = loader.get_data(file)143    try:144        code = loader.source_to_code(source_bytes, dfile or file,145                                     _optimize=optimize)146    except Exception as err:147        py_exc = PyCompileError(err.__class__, err, dfile or file)148        if quiet < 2:149            if doraise:150                raise py_exc151            else:152                sys.stderr.write(py_exc.msg + '\n')153        return154    try:155        dirname = os.path.dirname(cfile)156        if dirname:157            os.makedirs(dirname)158    except FileExistsError:159        pass160    if invalidation_mode == PycInvalidationMode.TIMESTAMP:161        source_stats = loader.path_stats(file)162        bytecode = importlib._bootstrap_external._code_to_timestamp_pyc(163            code, source_stats['mtime'], source_stats['size'])164    else:165        source_hash = importlib.util.source_hash(source_bytes)166        bytecode = importlib._bootstrap_external._code_to_hash_pyc(167            code,168            source_hash,169            (invalidation_mode == PycInvalidationMode.CHECKED_HASH),170        )171    mode = importlib._bootstrap_external._calc_mode(file)172    importlib._bootstrap_external._write_atomic(cfile, bytecode, mode)173    return cfile174 175 176def main():177    import argparse178 179    description = 'A simple command-line interface for py_compile module.'180    parser = argparse.ArgumentParser(description=description, color=True)181    parser.add_argument(182        '-q', '--quiet',183        action='store_true',184        help='Suppress error output',185    )186    parser.add_argument(187        'filenames',188        nargs='+',189        help='Files to compile',190    )191    args = parser.parse_args()192    if args.filenames == ['-']:193        filenames = [filename.rstrip('\n') for filename in sys.stdin.readlines()]194    else:195        filenames = args.filenames196    for filename in filenames:197        try:198            compile(filename, doraise=True)199        except PyCompileError as error:200            if args.quiet:201                parser.exit(1)202            else:203                parser.exit(1, error.msg)204        except OSError as error:205            if args.quiet:206                parser.exit(1)207            else:208                parser.exit(1, str(error))209 210 211if __name__ == "__main__":212    main()213 
codekingpro/portable-devtools · Team Ai