问题描述
我正在尝试理解 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
属性”。