forked from VimPlug/jedi
111 lines
3.5 KiB
Python
111 lines
3.5 KiB
Python
"""An adapted copy of relevant site-packages functionality from Python stdlib.
|
|
|
|
This file contains some functions related to handling site-packages in Python
|
|
with jedi-specific modifications:
|
|
|
|
- the functions operate on sys_path argument rather than global sys.path
|
|
|
|
- in .pth files "import ..." lines that allow execution of arbitrary code are
|
|
skipped to prevent code injection into jedi interpreter
|
|
|
|
"""
|
|
|
|
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
|
|
# 2011, 2012, 2013, 2014, 2015 Python Software Foundation; All Rights Reserved
|
|
|
|
from __future__ import print_function
|
|
|
|
import sys
|
|
import os
|
|
|
|
|
|
def makepath(*paths):
|
|
dir = os.path.join(*paths)
|
|
try:
|
|
dir = os.path.abspath(dir)
|
|
except OSError:
|
|
pass
|
|
return dir, os.path.normcase(dir)
|
|
|
|
|
|
def _init_pathinfo(sys_path):
|
|
"""Return a set containing all existing directory entries from sys_path"""
|
|
d = set()
|
|
for dir in sys_path:
|
|
try:
|
|
if os.path.isdir(dir):
|
|
dir, dircase = makepath(dir)
|
|
d.add(dircase)
|
|
except TypeError:
|
|
continue
|
|
return d
|
|
|
|
|
|
def addpackage(sys_path, sitedir, name, known_paths):
|
|
"""Process a .pth file within the site-packages directory:
|
|
For each line in the file, either combine it with sitedir to a path
|
|
and add that to known_paths, or execute it if it starts with 'import '.
|
|
"""
|
|
if known_paths is None:
|
|
known_paths = _init_pathinfo(sys_path)
|
|
reset = 1
|
|
else:
|
|
reset = 0
|
|
fullname = os.path.join(sitedir, name)
|
|
try:
|
|
f = open(fullname, "r")
|
|
except OSError:
|
|
return
|
|
with f:
|
|
for n, line in enumerate(f):
|
|
if line.startswith("#"):
|
|
continue
|
|
try:
|
|
if line.startswith(("import ", "import\t")):
|
|
# Change by immerrr: don't evaluate import lines to prevent
|
|
# code injection into jedi through pth files.
|
|
#
|
|
# exec(line)
|
|
continue
|
|
line = line.rstrip()
|
|
dir, dircase = makepath(sitedir, line)
|
|
if not dircase in known_paths and os.path.exists(dir):
|
|
sys_path.append(dir)
|
|
known_paths.add(dircase)
|
|
except Exception:
|
|
print("Error processing line {:d} of {}:\n".format(n+1, fullname),
|
|
file=sys.stderr)
|
|
import traceback
|
|
for record in traceback.format_exception(*sys.exc_info()):
|
|
for line in record.splitlines():
|
|
print(' '+line, file=sys.stderr)
|
|
print("\nRemainder of file ignored", file=sys.stderr)
|
|
break
|
|
if reset:
|
|
known_paths = None
|
|
return known_paths
|
|
|
|
|
|
def addsitedir(sys_path, sitedir, known_paths=None):
|
|
"""Add 'sitedir' argument to sys_path if missing and handle .pth files in
|
|
'sitedir'"""
|
|
if known_paths is None:
|
|
known_paths = _init_pathinfo(sys_path)
|
|
reset = 1
|
|
else:
|
|
reset = 0
|
|
sitedir, sitedircase = makepath(sitedir)
|
|
if not sitedircase in known_paths:
|
|
sys_path.append(sitedir) # Add path component
|
|
known_paths.add(sitedircase)
|
|
try:
|
|
names = os.listdir(sitedir)
|
|
except OSError:
|
|
return
|
|
names = [name for name in names if name.endswith(".pth")]
|
|
for name in sorted(names):
|
|
addpackage(sys_path, sitedir, name, known_paths)
|
|
if reset:
|
|
known_paths = None
|
|
return known_paths
|