updated external tools. Added annoying *.whl for the needs of virtualenv.

This commit is contained in:
Ekaterina Tuzova
2014-01-24 18:10:38 +04:00
parent 7a8ad62630
commit 2a9b3e2505
9 changed files with 237 additions and 196 deletions
Regular → Executable
+89 -78
View File
@@ -45,7 +45,7 @@ W warnings
700 statements
900 syntax error
"""
__version__ = '1.4.5a0'
__version__ = '1.4.6'
import os
import sys
@@ -63,13 +63,13 @@ except ImportError:
from ConfigParser import RawConfigParser
DEFAULT_EXCLUDE = '.svn,CVS,.bzr,.hg,.git,__pycache__'
DEFAULT_IGNORE = 'E226,E24'
DEFAULT_IGNORE = 'E123,E226,E24'
if sys.platform == 'win32':
DEFAULT_CONFIG = os.path.expanduser(r'~\.pep8')
else:
DEFAULT_CONFIG = os.path.join(os.getenv('XDG_CONFIG_HOME') or
os.path.expanduser('~/.config'), 'pep8')
PROJECT_CONFIG = ('.pep8', 'tox.ini', 'setup.cfg')
PROJECT_CONFIG = ('setup.cfg', 'tox.ini', '.pep8')
TESTSUITE_PATH = os.path.join(os.path.dirname(__file__), 'testsuite')
MAX_LINE_LENGTH = 79
REPORT_FORMAT = {
@@ -92,7 +92,7 @@ SKIP_TOKENS = frozenset([tokenize.COMMENT, tokenize.NL, tokenize.NEWLINE,
BENCHMARK_KEYS = ['directories', 'files', 'logical lines', 'physical lines']
INDENT_REGEX = re.compile(r'([ \t]*)')
RAISE_COMMA_REGEX = re.compile(r'raise\s+\w+\s*(,)')
RAISE_COMMA_REGEX = re.compile(r'raise\s+\w+\s*,')
RERAISE_COMMA_REGEX = re.compile(r'raise\s+\w+\s*,\s*\w+\s*,\s*\w+')
ERRORCODE_REGEX = re.compile(r'\b[A-Z]\d{3}\b')
DOCSTRING_REGEX = re.compile(r'u?r?["\']')
@@ -215,9 +215,7 @@ def maximum_line_length(physical_line, max_line_length):
"""
line = physical_line.rstrip()
length = len(line)
if length > max_line_length:
if noqa(line):
return
if length > max_line_length and not noqa(line):
if hasattr(line, 'decode'): # Python 2
# The line could contain multi-byte characters
try:
@@ -383,7 +381,8 @@ def indentation(logical_line, previous_logical, indent_char,
yield 0, "E113 unexpected indentation"
def continuation_line_indentation(logical_line, tokens, indent_level, verbose):
def continued_indentation(logical_line, tokens, indent_level, hang_closing,
noqa, verbose):
r"""
Continuation lines should align wrapped elements either vertically using
Python's implicit line joining inside parentheses, brackets and braces, or
@@ -411,7 +410,7 @@ def continuation_line_indentation(logical_line, tokens, indent_level, verbose):
"""
first_row = tokens[0][2][0]
nrows = 1 + tokens[-1][2][0] - first_row
if nrows == 1 or noqa(tokens[0][4]):
if noqa or nrows == 1:
return
# indent_next tells us whether the next block is indented; assuming
@@ -459,17 +458,19 @@ def continuation_line_indentation(logical_line, tokens, indent_level, verbose):
# an unbracketed continuation line (ie, backslash)
open_row = 0
hang = rel_indent[row] - rel_indent[open_row]
visual_indent = indent_chances.get(start[1])
close_bracket = (token_type == tokenize.OP and text in ']})')
visual_indent = (not close_bracket and hang > 0 and
indent_chances.get(start[1]))
if token_type == tokenize.OP and text in ']})':
# this line starts with a closing bracket
if indent[depth]:
if start[1] != indent[depth]:
yield (start, "E124 closing bracket does not match "
"visual indentation")
elif hang:
yield (start, "E123 closing bracket does not match "
"indentation of opening bracket's line")
if close_bracket and indent[depth]:
# closing bracket for visual indent
if start[1] != indent[depth]:
yield (start, "E124 closing bracket does not match "
"visual indentation")
elif close_bracket and not hang:
# closing bracket matches indentation of opening bracket's line
if hang_closing:
yield start, "E133 closing bracket is missing indentation"
elif visual_indent is True:
# visual indent is verified
if not indent[depth]:
@@ -483,7 +484,9 @@ def continuation_line_indentation(logical_line, tokens, indent_level, verbose):
"under-indented for visual indent")
elif hang == 4 or (indent_next and rel_indent[row] == 8):
# hanging indent is verified
pass
if close_bracket and not hang_closing:
yield (start, "E123 closing bracket does not match "
"indentation of opening bracket's line")
else:
# indent is broken
if hang <= 0:
@@ -535,6 +538,7 @@ def continuation_line_indentation(logical_line, tokens, indent_level, verbose):
for idx in range(row, -1, -1):
if parens[idx]:
parens[idx] -= 1
rel_indent[row] = rel_indent[idx]
break
assert len(indent) == depth + 1
if start[1] not in indent_chances:
@@ -543,7 +547,7 @@ def continuation_line_indentation(logical_line, tokens, indent_level, verbose):
last_token_multiline = (start[0] != end[0])
if indent_next and rel_indent[-1] == 4:
if indent_next and expand_indent(line) == indent_level + 4:
yield (last_indent, "E125 continuation line does not distinguish "
"itself from next logical line")
@@ -565,11 +569,9 @@ def whitespace_before_parameters(logical_line, tokens):
E211: dict ['key'] = list[index]
E211: dict['key'] = list [index]
"""
prev_type = tokens[0][0]
prev_text = tokens[0][1]
prev_end = tokens[0][3]
prev_type, prev_text, __, prev_end, __ = tokens[0]
for index in range(1, len(tokens)):
token_type, text, start, end, line = tokens[index]
token_type, text, start, end, __ = tokens[index]
if (token_type == tokenize.OP and
text in '([' and
start != prev_end and
@@ -691,10 +693,7 @@ def missing_whitespace_around_operator(logical_line, tokens):
binary_usage = (prev_type not in SKIP_TOKENS)
if binary_usage:
if text in WS_OPTIONAL_OPERATORS:
need_space = None
else:
need_space = True
need_space = None
elif text in WS_OPTIONAL_OPERATORS:
need_space = None
@@ -847,19 +846,21 @@ def compound_statements(logical_line):
line = logical_line
last_char = len(line) - 1
found = line.find(':')
if -1 < found < last_char:
while -1 < found < last_char:
before = line[:found]
if (before.count('{') <= before.count('}') and # {'a': 1} (dict)
before.count('[') <= before.count(']') and # [1:2] (slice)
before.count('(') <= before.count(')') and # (Python 3 annotation)
not LAMBDA_REGEX.search(before)): # lambda x: x
yield found, "E701 multiple statements on one line (colon)"
found = line.find(':', found + 1)
found = line.find(';')
if -1 < found:
while -1 < found:
if found < last_char:
yield found, "E702 multiple statements on one line (semicolon)"
else:
yield found, "E703 statement ends with a semicolon"
found = line.find(';', found + 1)
def explicit_line_join(logical_line, tokens):
@@ -897,7 +898,7 @@ def explicit_line_join(logical_line, tokens):
parens -= 1
def comparison_to_singleton(logical_line):
def comparison_to_singleton(logical_line, noqa):
"""
Comparisons to singletons like None should always be done
with "is" or "is not", never the equality operators.
@@ -911,7 +912,7 @@ def comparison_to_singleton(logical_line):
set to some other value. The other value might have a type (such as a
container) that could be false in a boolean context!
"""
match = COMPARE_SINGLETON_REGEX.search(logical_line)
match = not noqa and COMPARE_SINGLETON_REGEX.search(logical_line)
if match:
same = (match.group(1) == '==')
singleton = match.group(2)
@@ -947,7 +948,7 @@ def comparison_type(logical_line):
inst = match.group(1)
if inst and isidentifier(inst) and inst not in SINGLETONS:
return # Allow comparison for types which are not obvious
yield match.start(0), "E721 do not compare types, use 'isinstance()'"
yield match.start(), "E721 do not compare types, use 'isinstance()'"
def python_3000_has_key(logical_line):
@@ -978,7 +979,7 @@ def python_3000_raise_comma(logical_line):
"""
match = RAISE_COMMA_REGEX.match(logical_line)
if match and not RERAISE_COMMA_REGEX.match(logical_line):
yield match.start(1), "W602 deprecated form of raising exception"
yield match.end() - 1, "W602 deprecated form of raising exception"
def python_3000_not_equal(logical_line):
@@ -1021,7 +1022,6 @@ if '' == ''.encode():
return f.readlines()
finally:
f.close()
isidentifier = re.compile(r'[a-zA-Z_]\w*').match
stdin_get_value = sys.stdin.read
else:
@@ -1039,7 +1039,6 @@ else:
return f.readlines()
finally:
f.close()
isidentifier = str.isidentifier
def stdin_get_value():
@@ -1188,6 +1187,7 @@ class Checker(object):
self._logical_checks = options.logical_checks
self._ast_checks = options.ast_checks
self.max_line_length = options.max_line_length
self.hang_closing = options.hang_closing
self.verbose = options.verbose
self.filename = filename
if filename is None:
@@ -1205,14 +1205,24 @@ class Checker(object):
self.lines = []
else:
self.lines = lines
if self.lines:
ord0 = ord(self.lines[0][0])
if ord0 in (0xef, 0xfeff): # Strip the UTF-8 BOM
if ord0 == 0xfeff:
self.lines[0] = self.lines[0][1:]
elif self.lines[0][:3] == '\xef\xbb\xbf':
self.lines[0] = self.lines[0][3:]
self.report = report or options.report
self.report_error = self.report.error
def report_invalid_syntax(self):
exc_type, exc = sys.exc_info()[:2]
offset = exc.args[1]
if len(offset) > 2:
offset = offset[1:3]
if len(exc.args) > 1:
offset = exc.args[1]
if len(offset) > 2:
offset = offset[1:3]
else:
offset = (1, 0)
self.report_error(offset[0], offset[1] or 0,
'E901 %s: %s' % (exc_type.__name__, exc.args[0]),
self.report_invalid_syntax)
@@ -1265,10 +1275,14 @@ class Checker(object):
"""
self.mapping = []
logical = []
comments = []
length = 0
previous = None
for token in self.tokens:
token_type, text = token[0:2]
if token_type == tokenize.COMMENT:
comments.append(text)
continue
if token_type in SKIP_TOKENS:
continue
if token_type == tokenize.STRING:
@@ -1291,6 +1305,7 @@ class Checker(object):
length += len(text)
previous = token
self.logical_line = ''.join(logical)
self.noqa = comments and noqa(''.join(comments))
# With Python 2, if the line ends with '\r\r\n' the assertion fails
# assert self.logical_line.strip() == self.logical_line
@@ -1324,7 +1339,7 @@ class Checker(object):
def check_ast(self):
try:
tree = compile(''.join(self.lines), '', 'exec', PyCF_ONLY_AST)
except SyntaxError:
except (SyntaxError, TypeError):
return self.report_invalid_syntax()
for name, cls, _ in self._ast_checks:
checker = cls(tree, self.filename)
@@ -1574,9 +1589,14 @@ class StyleGuide(object):
for index, value in enumerate(options.exclude):
options.exclude[index] = value.rstrip('/')
# Ignore all checks which are not explicitly selected
options.select = tuple(options.select or ())
options.ignore = tuple(options.ignore or options.select and ('',))
if not (options.select or options.ignore or
options.testsuite or options.doctest) and DEFAULT_IGNORE:
# The default choice: ignore controversial checks
options.ignore = tuple(DEFAULT_IGNORE.split(','))
else:
# Ignore all checks which are not explicitly selected
options.ignore = ('',) if options.select else tuple(options.ignore)
options.benchmark_keys = BENCHMARK_KEYS[:]
options.ignore_code = self.ignore_code
options.physical_checks = self.get_checks('physical_line')
@@ -1629,23 +1649,26 @@ class StyleGuide(object):
print('directory ' + root)
counters['directories'] += 1
for subdir in sorted(dirs):
if self.excluded(os.path.join(root, subdir)):
if self.excluded(subdir, root):
dirs.remove(subdir)
for filename in sorted(files):
# contain a pattern that matches?
if ((filename_match(filename, filepatterns) and
not self.excluded(filename))):
not self.excluded(filename, root))):
runner(os.path.join(root, filename))
def excluded(self, filename):
def excluded(self, filename, parent=None):
"""
Check if options.exclude contains a pattern that matches filename.
"""
if not self.options.exclude:
return False
basename = os.path.basename(filename)
return any((filename_match(filename, self.options.exclude,
default=False),
filename_match(basename, self.options.exclude,
default=False)))
if filename_match(basename, self.options.exclude):
return True
if parent:
filename = os.path.join(parent, filename)
return filename_match(filename, self.options.exclude)
def ignore_code(self, code):
"""
@@ -1675,8 +1698,9 @@ def get_parser(prog='pep8', version=__version__):
parser = OptionParser(prog=prog, version=version,
usage="%prog [options] input ...")
parser.config_options = [
'exclude', 'filename', 'select', 'ignore', 'max-line-length', 'count',
'format', 'quiet', 'show-pep8', 'show-source', 'statistics', 'verbose']
'exclude', 'filename', 'select', 'ignore', 'max-line-length',
'hang-closing', 'count', 'format', 'quiet', 'show-pep8',
'show-source', 'statistics', 'verbose']
parser.add_option('-v', '--verbose', default=0, action='count',
help="print status messages, or debug with -vv")
parser.add_option('-q', '--quiet', default=0, action='count',
@@ -1711,6 +1735,9 @@ def get_parser(prog='pep8', version=__version__):
default=MAX_LINE_LENGTH,
help="set maximum allowed line length "
"(default: %default)")
parser.add_option('--hang-closing', action='store_true',
help="hang closing bracket instead of matching "
"indentation of opening bracket's line")
parser.add_option('--format', metavar='format', default='default',
help="set the error format [default|pylint|<custom>]")
parser.add_option('--diff', action='store_true',
@@ -1739,17 +1766,11 @@ def read_config(options, args, arglist, parser):
parent = tail = args and os.path.abspath(os.path.commonprefix(args))
while tail:
for name in PROJECT_CONFIG:
local_conf = os.path.join(parent, name)
if os.path.isfile(local_conf):
break
else:
parent, tail = os.path.split(parent)
continue
if options.verbose:
print('local configuration: %s' % local_conf)
config.read(local_conf)
break
if config.read([os.path.join(parent, fn) for fn in PROJECT_CONFIG]):
if options.verbose:
print('local configuration: in %s' % parent)
break
parent, tail = os.path.split(parent)
pep8_section = parser.prog
if config.has_section(pep8_section):
@@ -1817,18 +1838,10 @@ def process_options(arglist=None, parse_argv=False, config_file=None,
options = read_config(options, args, arglist, parser)
options.reporter = parse_argv and options.quiet == 1 and FileReport
if options.filename:
options.filename = options.filename.split(',')
options.filename = options.filename and options.filename.split(',')
options.exclude = options.exclude.split(',')
if options.select:
options.select = options.select.split(',')
if options.ignore:
options.ignore = options.ignore.split(',')
elif not (options.select or
options.testsuite or options.doctest) and DEFAULT_IGNORE:
# The default choice: ignore controversial checks
# (for doctest and testsuite, all checks are required)
options.ignore = DEFAULT_IGNORE.split(',')
options.select = options.select and options.select.split(',')
options.ignore = options.ignore and options.ignore.split(',')
if options.diff:
options.reporter = DiffReport
@@ -1844,10 +1857,8 @@ def _main():
pep8style = StyleGuide(parse_argv=True, config_file=True)
options = pep8style.options
if options.doctest or options.testsuite:
sys.path[:0] = [TESTSUITE_PATH]
from test_pep8 import run_tests
del sys.path[0]
report = run_tests(pep8style, options.doctest, options.testsuite)
from testsuite.support import run_tests
report = run_tests(pep8style)
else:
report = pep8style.check_files()
if options.statistics:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Regular → Executable
+146 -116
View File
@@ -2,7 +2,7 @@
"""Create a "virtual" Python installation
"""
__version__ = "1.10.1"
__version__ = "1.11.1"
virtualenv_version = __version__ # legacy
import base64
@@ -130,7 +130,7 @@ elif majver == 3:
'reprlib'])
if minver >= 2:
REQUIRED_FILES[-1] = 'config-%s' % majver
if minver == 3:
if minver >= 3:
import sysconfig
platdir = sysconfig.get_config_var('PLATDIR')
REQUIRED_FILES.append(platdir)
@@ -285,6 +285,12 @@ elif majver == 3:
#"xmlrpc",
#"zipfile",
])
if minver >= 4:
REQUIRED_MODULES.extend([
'operator',
'_collections_abc',
'_bootlocale',
])
if is_pypy:
# these are needed to correctly display the exceptions that may happen
@@ -646,14 +652,14 @@ def main():
action='count',
dest='verbose',
default=0,
help="Increase verbosity")
help="Increase verbosity.")
parser.add_option(
'-q', '--quiet',
action='count',
dest='quiet',
default=0,
help='Decrease verbosity')
help='Decrease verbosity.')
parser.add_option(
'-p', '--python',
@@ -667,49 +673,47 @@ def main():
'--clear',
dest='clear',
action='store_true',
help="Clear out the non-root install and start from scratch")
help="Clear out the non-root install and start from scratch.")
parser.set_defaults(system_site_packages=False)
parser.add_option(
'--no-site-packages',
dest='system_site_packages',
action='store_false',
help="Don't give access to the global site-packages dir to the "
"virtual environment (default)")
help="DEPRECATED. Retained only for backward compatibility. "
"Not having access to global site-packages is now the default behavior.")
parser.add_option(
'--system-site-packages',
dest='system_site_packages',
action='store_true',
help="Give access to the global site-packages dir to the "
"virtual environment")
help="Give the virtual environment access to the global site-packages.")
parser.add_option(
'--always-copy',
dest='symlink',
action='store_false',
default=True,
help="Always copy files rather than symlinking")
help="Always copy files rather than symlinking.")
parser.add_option(
'--unzip-setuptools',
dest='unzip_setuptools',
action='store_true',
help="Unzip Setuptools when installing it")
help="Unzip Setuptools when installing it.")
parser.add_option(
'--relocatable',
dest='relocatable',
action='store_true',
help='Make an EXISTING virtualenv environment relocatable. '
'This fixes up scripts and makes all .pth files relative')
help='Make an EXISTING virtualenv environment relocatable. '
'This fixes up scripts and makes all .pth files relative.')
parser.add_option(
'--no-setuptools',
dest='no_setuptools',
action='store_true',
help='Do not install setuptools (or pip) '
'in the new virtualenv.')
help='Do not install setuptools (or pip) in the new virtualenv.')
parser.add_option(
'--no-pip',
@@ -722,36 +726,35 @@ def main():
'--extra-search-dir',
dest="search_dirs",
action="append",
metavar='DIR',
default=default_search_dirs,
help="Directory to look for setuptools/pip distributions in. "
"You can add any number of additional --extra-search-dir paths.")
"This option can be used multiple times.")
parser.add_option(
'--never-download',
dest="never_download",
action="store_true",
default=True,
help="Never download anything from the network. This is now always "
"the case. The option is only retained for backward compatibility, "
"and does nothing. Virtualenv will fail if local distributions "
"of setuptools/pip are not present.")
help="DEPRECATED. Retained only for backward compatibility. This option has no effect. "
"Virtualenv never downloads pip or setuptools.")
parser.add_option(
'--prompt',
dest='prompt',
help='Provides an alternative prompt prefix for this environment')
help='Provides an alternative prompt prefix for this environment.')
parser.add_option(
'--setuptools',
dest='setuptools',
action='store_true',
help="Backward compatibility. Does nothing.")
help="DEPRECATED. Retained only for backward compatibility. This option has no effect.")
parser.add_option(
'--distribute',
dest='distribute',
action='store_true',
help="Backward compatibility. Does nothing.")
help="DEPRECATED. Retained only for backward compatibility. This option has no effect.")
if 'extend_parser' in globals():
extend_parser(parser)
@@ -907,34 +910,59 @@ def filter_install_output(line):
return Logger.INFO
return Logger.DEBUG
def install_sdist(project_name, sdist, py_executable, search_dirs=None):
def find_wheels(projects, search_dirs):
"""Find wheels from which we can import PROJECTS.
Scan through SEARCH_DIRS for a wheel for each PROJECT in turn. Return
a list of the first wheel found for each PROJECT
"""
wheels = []
# Look through SEARCH_DIRS for the first suitable wheel. Don't bother
# about version checking here, as this is simply to get something we can
# then use to install the correct version.
for project in projects:
for dirname in search_dirs:
# This relies on only having "universal" wheels available.
# The pattern could be tightened to require -py2.py3-none-any.whl.
files = glob.glob(os.path.join(dirname, project + '-*.whl'))
if files:
wheels.append(os.path.abspath(files[0]))
break
else:
# We're out of luck, so quit with a suitable error
logger.fatal('Cannot find a wheel for %s' % (project,))
return wheels
def install_wheel(project_names, py_executable, search_dirs=None):
if search_dirs is None:
search_dirs = file_search_dirs()
found, sdist_path = _find_file(sdist, search_dirs)
if not found:
logger.fatal("Cannot find sdist %s" % (sdist,))
return
tmpdir = tempfile.mkdtemp()
wheels = find_wheels(['setuptools', 'pip'], search_dirs)
pythonpath = os.pathsep.join(wheels)
findlinks = ' '.join(search_dirs)
cmd = [
py_executable, '-c',
'import sys, pip; sys.exit(pip.main(["install", "--ignore-installed"] + sys.argv[1:]))',
] + project_names
logger.start_progress('Installing %s...' % (', '.join(project_names)))
logger.indent += 2
try:
tar = tarfile.open(sdist_path)
tar.extractall(tmpdir)
tar.close()
srcdir = os.path.join(tmpdir, os.listdir(tmpdir)[0])
cmd = [py_executable, 'setup.py', 'install',
'--single-version-externally-managed',
'--record', 'record']
logger.start_progress('Installing %s...' % project_name)
logger.indent += 2
try:
call_subprocess(cmd, show_stdout=False, cwd=srcdir,
filter_stdout=filter_install_output)
finally:
logger.indent -= 2
logger.end_progress()
call_subprocess(cmd, show_stdout=False,
extra_env = {
'PYTHONPATH': pythonpath,
'PIP_FIND_LINKS': findlinks,
'PIP_USE_WHEEL': '1',
'PIP_PRE': '1',
'PIP_NO_INDEX': '1'
}
)
finally:
shutil.rmtree(tmpdir)
logger.indent -= 2
logger.end_progress()
def create_environment(home_dir, site_packages=False, clear=False,
unzip_setuptools=False,
@@ -958,9 +986,10 @@ def create_environment(home_dir, site_packages=False, clear=False,
install_distutils(home_dir)
if not no_setuptools:
install_sdist('Setuptools', 'setuptools-*.tar.gz', py_executable, search_dirs)
to_install = ['setuptools']
if not no_pip:
install_sdist('Pip', 'pip-*.tar.gz', py_executable, search_dirs)
to_install.append('pip')
install_wheel(to_install, py_executable, search_dirs)
install_activate(home_dir, bin_dir, prompt)
@@ -1221,7 +1250,7 @@ def install_python(home_dir, lib_dir, inc_dir, bin_dir, site_packages, clear, sy
# OS X framework builds cause validation to break
# https://github.com/pypa/virtualenv/issues/322
if os.environ.get('__PYVENV_LAUNCHER__'):
os.unsetenv('__PYVENV_LAUNCHER__')
del os.environ["__PYVENV_LAUNCHER__"]
if re.search(r'/Python(?:-32|-64)*$', py_executable):
# The name of the python executable is not quite what
# we want, rename it.
@@ -1374,7 +1403,7 @@ def install_python(home_dir, lib_dir, inc_dir, bin_dir, site_packages, clear, sy
if symlink:
os.symlink(py_executable_base, full_pth)
else:
shutil.copyfile(py_executable_base, full_pth)
copyfile(py_executable, full_pth, symlink)
if is_win and ' ' in py_executable:
# There's a bug with subprocess on Windows when using a first
@@ -1505,9 +1534,8 @@ def fix_local_scheme(home_dir, symlink=True):
for subdir_name in os.listdir(home_dir):
if subdir_name == 'local':
continue
cp_or_ln = (os.symlink if symlink else copyfile)
cp_or_ln(os.path.abspath(os.path.join(home_dir, subdir_name)), \
os.path.join(local_path, subdir_name))
copyfile(os.path.abspath(os.path.join(home_dir, subdir_name)), \
os.path.join(local_path, subdir_name), symlink)
def fix_lib64(lib_dir, symlink=True):
"""
@@ -1585,7 +1613,8 @@ def make_environment_relocatable(home_dir):
## FIXME: need to fix up distutils.cfg
OK_ABS_SCRIPTS = ['python', 'python%s' % sys.version[:3],
'activate', 'activate.bat', 'activate_this.py']
'activate', 'activate.bat', 'activate_this.py',
'activate.fish', 'activate.csh']
def fixup_scripts(home_dir, bin_dir):
if is_win:
@@ -1908,54 +1937,54 @@ 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
abV46zZtMMiZnWgPwBqF4P8ACHXrHw==
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
Qc7sRHsA1igE/wfVIOdx
""")
##file activate.sh
@@ -1979,21 +2008,22 @@ D/Ncozgn13vJvsznr7DnkJWXsyMH7e42ljdJ+aqNDF1bFnKWFLdj31xtaJYK6EXFgqmV/ymD/ROG
##file activate.fish
ACTIVATE_FISH = convert("""
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
32XS1ITj/qLjN72ob0hc5C9bzw8MhfmL
""")
##file activate.csh