创建环境脚本

问题描述

我正在尝试理解 Python 文档页面上的脚本。

我不太明白,如何引入参数,我知道我必须把安装虚拟环境的目录的名称,以便参数dirs存储目录的元组,但是我不明白如何修改nopip等其他参数的参数。

代码

import os
import os.path
from subprocess import Popen,PIPE
import sys
from threading import Thread
from urllib.parse import urlparse
from urllib.request import urlretrieve
import venv

class ExtendedEnvBuilder(venv.EnvBuilder):
    """
    This builder installs setuptools and pip so that you can pip or
    easy_install other packages into the created virtual environment.

    :param nodist: If true,setuptools and pip are not installed into the
                   created virtual environment.
    :param nopip: If true,pip is not installed into the created
                  virtual environment.
    :param progress: If setuptools or pip are installed,the progress of the
                     installation can be monitored by passing a progress
                     callable. If specified,it is called with two
                     arguments: a string indicating some progress,and a
                     context indicating where the string is coming from.
                     The context argument can have one of three values:
                     'main',indicating that it is called from virtualize()
                     itself,and 'stdout' and 'stderr',which are obtained
                     by reading lines from the output streams of a subprocess
                     which is used to install the app.

                     If a callable is not specified,default progress
                     information is output to sys.stderr.
    """
    def __init__(self,*args,**kwargs):
        self.nodist = kwargs.pop('nodist',False)
        self.nopip = kwargs.pop('nopip',False)
        self.progress = kwargs.pop('progress',None)
        self.verbose = kwargs.pop('verbose',False)
        super().__init__(*args,**kwargs)

    def post_setup(self,context):
        """
        Set up any packages which need to be pre-installed into the
        virtual environment being created.

        :param context: The information for the virtual environment
                        creation request being processed.
        """
        os.environ['VIRTUAL_ENV'] = context.env_dir
        if not self.nodist:
            self.install_setuptools(context)
        # Can't install pip without setuptools
        if not self.nopip and not self.nodist:
            self.install_pip(context)

    def reader(self,stream,context):
        """
        Read lines from a subprocess' output stream and either pass to a progress
        callable (if specified) or write progress information to sys.stderr.
        """
        progress = self.progress
        while True:
            s = stream.readline()
            if not s:
                break
            if progress is not None:
                progress(s,context)
            else:
                if not self.verbose:
                    sys.stderr.write('.')
                else:
                    sys.stderr.write(s.decode('utf-8'))
                sys.stderr.flush()
        stream.close()

    def install_script(self,context,name,url):
        _,_,path,_ = urlparse(url)
        fn = os.path.split(path)[-1]
        binpath = context.bin_path
        distpath = os.path.join(binpath,fn)
        # Download script into the virtual environment's binaries folder
        urlretrieve(url,distpath)
        progress = self.progress
        if self.verbose:
            term = '\n'
        else:
            term = ''
        if progress is not None:
            progress('Installing %s ...%s' % (name,term),'main')
        else:
            sys.stderr.write('Installing %s ...%s' % (name,term))
            sys.stderr.flush()
        # Install in the virtual environment
        args = [context.env_exe,fn]
        p = Popen(args,stdout=PIPE,stderr=PIPE,cwd=binpath)
        t1 = Thread(target=self.reader,args=(p.stdout,'stdout'))
        t1.start()
        t2 = Thread(target=self.reader,args=(p.stderr,'stderr'))
        t2.start()
        p.wait()
        t1.join()
        t2.join()
        if progress is not None:
            progress('done.','main')
        else:
            sys.stderr.write('done.\n')
        # Clean up - no longer needed
        os.unlink(distpath)

    def install_setuptools(self,context):
        """
        Install setuptools in the virtual environment.

        :param context: The information for the virtual environment
                        creation request being processed.
        """
        url = 'https://bitbucket.org/pypa/setuptools/downloads/ez_setup.py'
        self.install_script(context,'setuptools',url)
        # clear up the setuptools archive which gets downloaded
        pred = lambda o: o.startswith('setuptools-') and o.endswith('.tar.gz')
        files = filter(pred,os.listdir(context.bin_path))
        for f in files:
            f = os.path.join(context.bin_path,f)
            os.unlink(f)

    def install_pip(self,context):
        """
        Install pip in the virtual environment.

        :param context: The information for the virtual environment
                        creation request being processed.
        """
        url = 'https://raw.github.com/pypa/pip/master/contrib/get-pip.py'
        self.install_script(context,'pip',url)

def main(args=None):
    compatible = True
    if sys.version_info < (3,3):
        compatible = False
    elif not hasattr(sys,'base_prefix'):
        compatible = False
        
    if not compatible:
        raise ValueError('This script is only for use with '
                         'Python 3.3 or later')
    else:
        import argparse

        parser = argparse.ArgumentParser(prog=__name__,description='Creates virtual Python '
                                                     'environments in one or '
                                                     'more target '
                                                     'directories.')
        parser.add_argument('dirs',Metavar='ENV_DIR',nargs='+ Pruebas',help='A directory in which to create the'
                                 'virtual environment.')
        parser.add_argument('--no-setuptools',default=False,action='store_true',dest='nodist',help="Don't install setuptools or pip in the "
                                 "virtual environment.")
        parser.add_argument('--no-pip',dest='nopip',help="Don't install pip in the virtual "
                                 "environment.")
        parser.add_argument('--system-site-packages',dest='system_site',help='Give the virtual environment access to the '
                                 'system site-packages dir.')
        if os.name == 'nt':
            use_symlinks = False
        else:
            use_symlinks = True
        parser.add_argument('--symlinks',default=use_symlinks,dest='symlinks',help='Try to use symlinks rather than copies,'
                                 'when symlinks are not the default for '
                                 'the platform.')
        parser.add_argument('--clear',dest='clear',help='Delete the contents of the '
                                               'virtual environment '
                                               'directory if it already '
                                               'exists,before virtual '
                                               'environment creation.')
        parser.add_argument('--upgrade',dest='upgrade',help='Upgrade the virtual '
                                                 'environment directory to '
                                                 'use this version of '
                                                 'Python,assuming Python '
                                                 'has been upgraded '
                                                 'in-place.')
        parser.add_argument('--verbose',dest='verbose',help='display the output '
                                               'from the scripts which '
                                               'install setuptools and pip.')
        options = parser.parse_args(args)
        if options.upgrade and options.clear:
            raise ValueError('you cannot supply --upgrade and --clear together.')
        builder = ExtendedEnvBuilder(system_site_packages=options.system_site,clear=options.clear,symlinks=options.symlinks,upgrade=options.upgrade,nodist=options.nodist,nopip=options.nopip,verbose=options.verbose)
        for d in options.dirs:
            builder.create(d)

if __name__ == '__main__':
    rc = 1
    try:
        main()
        rc = 0
    except Exception as e:
        print('Error: %s' % e,file=sys.stderr)
    sys.exit(rc)

解决方法

所有其他选项都可以通过命令行参数进行修改。如果使用 --help 标志运行脚本,您可以看到可用选项:

python3 pyvenvex.py --help

输出:

Usage: __main__ [-h] [--no-setuptools] [--no-pip] [--system-site-packages]
                [--symlinks] [--clear] [--upgrade] [--verbose]
                ENV_DIR [ENV_DIR ...]

Creates virtual Python environments in one or more target directories.

positional arguments:
  ENV_DIR               A directory to create the environment in.

optional arguments:
  -h,--help            show this help message and exit
  --no-setuptools       Don't install setuptools or pip in the virtual
                        environment.
  --no-pip              Don't install pip in the virtual environment.
  --system-site-packages
                        Give the virtual environment access to the system
                        site-packages dir.
  --symlinks            Try to use symlinks rather than copies,when symlinks
                        are not the default for the platform.
  --clear               Delete the contents of the environment directory if it
                        already exists,before environment creation.
  --upgrade             Upgrade the environment directory to use this version
                        of Python,assuming Python has been upgraded in-place.
  --verbose             Display the output from the scripts which install
                        setuptools and pip.


此参数由标准库中的 argparse 模块处理。你可以在脚本中看到很多这样的样板代码:

parser.add_argument('--no-pip',default=False,action='store_true',dest='nopip',help="Don't install pip in the virtual "
                                 "environment.")

这里唯一棘手的是关键字参数 dest='nopip',这意味着“解析 --no-pip 参数并将结果放入 nopip 属性”。