Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
core.py290 linesDownload Raw Back to _distutils
1"""distutils.core2 3The only module that needs to be imported to use the Distutils; provides4the 'setup' function (which is to be called from the setup script).  Also5indirectly provides the Distribution and Command classes, although they are6really defined in distutils.dist and distutils.cmd.7"""8 9from __future__ import annotations10 11import os12import sys13import tokenize14from collections.abc import Iterable15 16from .cmd import Command17from .debug import DEBUG18 19# Mainly import these so setup scripts can "from distutils.core import" them.20from .dist import Distribution21from .errors import (22    CCompilerError,23    DistutilsArgError,24    DistutilsError,25    DistutilsSetupError,26)27from .extension import Extension28 29__all__ = ['Distribution', 'Command', 'Extension', 'setup']30 31# This is a barebones help message generated displayed when the user32# runs the setup script with no arguments at all.  More useful help33# is generated with various --help options: global help, list commands,34# and per-command help.35USAGE = """\36usage: %(script)s [global_opts] cmd1 [cmd1_opts] [cmd2 [cmd2_opts] ...]37   or: %(script)s --help [cmd1 cmd2 ...]38   or: %(script)s --help-commands39   or: %(script)s cmd --help40"""41 42 43def gen_usage(script_name):44    script = os.path.basename(script_name)45    return USAGE % locals()46 47 48# Some mild magic to control the behaviour of 'setup()' from 'run_setup()'.49_setup_stop_after = None50_setup_distribution = None51 52# Legal keyword arguments for the setup() function53setup_keywords = (54    'distclass',55    'script_name',56    'script_args',57    'options',58    'name',59    'version',60    'author',61    'author_email',62    'maintainer',63    'maintainer_email',64    'url',65    'license',66    'description',67    'long_description',68    'keywords',69    'platforms',70    'classifiers',71    'download_url',72    'requires',73    'provides',74    'obsoletes',75)76 77# Legal keyword arguments for the Extension constructor78extension_keywords = (79    'name',80    'sources',81    'include_dirs',82    'define_macros',83    'undef_macros',84    'library_dirs',85    'libraries',86    'runtime_library_dirs',87    'extra_objects',88    'extra_compile_args',89    'extra_link_args',90    'swig_opts',91    'export_symbols',92    'depends',93    'language',94)95 96 97def setup(**attrs):  # noqa: C90198    """The gateway to the Distutils: do everything your setup script needs99    to do, in a highly flexible and user-driven way.  Briefly: create a100    Distribution instance; find and parse config files; parse the command101    line; run each Distutils command found there, customized by the options102    supplied to 'setup()' (as keyword arguments), in config files, and on103    the command line.104 105    The Distribution instance might be an instance of a class supplied via106    the 'distclass' keyword argument to 'setup'; if no such class is107    supplied, then the Distribution class (in dist.py) is instantiated.108    All other arguments to 'setup' (except for 'cmdclass') are used to set109    attributes of the Distribution instance.110 111    The 'cmdclass' argument, if supplied, is a dictionary mapping command112    names to command classes.  Each command encountered on the command line113    will be turned into a command class, which is in turn instantiated; any114    class found in 'cmdclass' is used in place of the default, which is115    (for command 'foo_bar') class 'foo_bar' in module116    'distutils.command.foo_bar'.  The command class must provide a117    'user_options' attribute which is a list of option specifiers for118    'distutils.fancy_getopt'.  Any command-line options between the current119    and the next command are used to set attributes of the current command120    object.121 122    When the entire command-line has been successfully parsed, calls the123    'run()' method on each command object in turn.  This method will be124    driven entirely by the Distribution object (which each command object125    has a reference to, thanks to its constructor), and the126    command-specific options that became attributes of each command127    object.128    """129 130    global _setup_stop_after, _setup_distribution131 132    # Determine the distribution class -- either caller-supplied or133    # our Distribution (see below).134    klass = attrs.get('distclass')135    if klass:136        attrs.pop('distclass')137    else:138        klass = Distribution139 140    if 'script_name' not in attrs:141        attrs['script_name'] = os.path.basename(sys.argv[0])142    if 'script_args' not in attrs:143        attrs['script_args'] = sys.argv[1:]144 145    # Create the Distribution instance, using the remaining arguments146    # (ie. everything except distclass) to initialize it147    try:148        _setup_distribution = dist = klass(attrs)149    except DistutilsSetupError as msg:150        if 'name' not in attrs:151            raise SystemExit(f"error in setup command: {msg}")152        else:153            raise SystemExit("error in {} setup command: {}".format(attrs['name'], msg))154 155    if _setup_stop_after == "init":156        return dist157 158    # Find and parse the config file(s): they will override options from159    # the setup script, but be overridden by the command line.160    dist.parse_config_files()161 162    if DEBUG:163        print("options (after parsing config files):")164        dist.dump_option_dicts()165 166    if _setup_stop_after == "config":167        return dist168 169    # Parse the command line and override config files; any170    # command-line errors are the end user's fault, so turn them into171    # SystemExit to suppress tracebacks.172    try:173        ok = dist.parse_command_line()174    except DistutilsArgError as msg:175        raise SystemExit(gen_usage(dist.script_name) + f"\nerror: {msg}")176 177    if DEBUG:178        print("options (after parsing command line):")179        dist.dump_option_dicts()180 181    if _setup_stop_after == "commandline":182        return dist183 184    # And finally, run all the commands found on the command line.185    if ok:186        return run_commands(dist)187 188    return dist189 190 191# setup ()192 193 194def run_commands(dist):195    """Given a Distribution object run all the commands,196    raising ``SystemExit`` errors in the case of failure.197 198    This function assumes that either ``sys.argv`` or ``dist.script_args``199    is already set accordingly.200    """201    try:202        dist.run_commands()203    except KeyboardInterrupt:204        raise SystemExit("interrupted")205    except OSError as exc:206        if DEBUG:207            sys.stderr.write(f"error: {exc}\n")208            raise209        else:210            raise SystemExit(f"error: {exc}")211 212    except (DistutilsError, CCompilerError) as msg:213        if DEBUG:214            raise215        else:216            raise SystemExit("error: " + str(msg))217 218    return dist219 220 221def run_setup(script_name, script_args: Iterable[str] | None = None, stop_after="run"):222    """Run a setup script in a somewhat controlled environment, and223    return the Distribution instance that drives things.  This is useful224    if you need to find out the distribution meta-data (passed as225    keyword args from 'script' to 'setup()', or the contents of the226    config files or command-line.227 228    'script_name' is a file that will be read and run with 'exec()';229    'sys.argv[0]' will be replaced with 'script' for the duration of the230    call.  'script_args' is a list of strings; if supplied,231    'sys.argv[1:]' will be replaced by 'script_args' for the duration of232    the call.233 234    'stop_after' tells 'setup()' when to stop processing; possible235    values:236      init237        stop after the Distribution instance has been created and238        populated with the keyword arguments to 'setup()'239      config240        stop after config files have been parsed (and their data241        stored in the Distribution instance)242      commandline243        stop after the command-line ('sys.argv[1:]' or 'script_args')244        have been parsed (and the data stored in the Distribution)245      run [default]246        stop after all commands have been run (the same as if 'setup()'247        had been called in the usual way248 249    Returns the Distribution instance, which provides all information250    used to drive the Distutils.251    """252    if stop_after not in ('init', 'config', 'commandline', 'run'):253        raise ValueError(f"invalid value for 'stop_after': {stop_after!r}")254 255    global _setup_stop_after, _setup_distribution256    _setup_stop_after = stop_after257 258    save_argv = sys.argv.copy()259    g = {'__file__': script_name, '__name__': '__main__'}260    try:261        try:262            sys.argv[0] = script_name263            if script_args is not None:264                sys.argv[1:] = script_args265            # tokenize.open supports automatic encoding detection266            with tokenize.open(script_name) as f:267                code = f.read().replace(r'\r\n', r'\n')268                exec(code, g)269        finally:270            sys.argv = save_argv271            _setup_stop_after = None272    except SystemExit:273        # Hmm, should we do something if exiting with a non-zero code274        # (ie. error)?275        pass276 277    if _setup_distribution is None:278        raise RuntimeError(279            "'distutils.core.setup()' was never called -- "280            f"perhaps '{script_name}' is not a Distutils setup script?"281        )282 283    # I wonder if the setup script's namespace -- g and l -- would be of284    # any interest to callers?285    # print "_setup_distribution:", _setup_distribution286    return _setup_distribution287 288 289# run_setup ()290 
codekingpro/portable-devtools · Team Ai