Merge branch 'master' into typeshed

This commit is contained in:
Dave Halter
2018-08-04 23:42:17 +02:00
23 changed files with 210 additions and 140 deletions

View File

@@ -8,7 +8,6 @@ python:
env: env:
- JEDI_TEST_ENVIRONMENT=27 - JEDI_TEST_ENVIRONMENT=27
- JEDI_TEST_ENVIRONMENT=33
- JEDI_TEST_ENVIRONMENT=34 - JEDI_TEST_ENVIRONMENT=34
- JEDI_TEST_ENVIRONMENT=35 - JEDI_TEST_ENVIRONMENT=35
- JEDI_TEST_ENVIRONMENT=36 - JEDI_TEST_ENVIRONMENT=36
@@ -39,7 +38,6 @@ before_install:
- ./travis_install.sh - ./travis_install.sh
# Need to add the path to the Python versions in the end. This might add # Need to add the path to the Python versions in the end. This might add
# something twice, but it doesn't really matter, because they are appended. # something twice, but it doesn't really matter, because they are appended.
- export PATH=$PATH:/opt/python/3.3/bin
- export PATH=$PATH:/opt/python/3.5/bin - export PATH=$PATH:/opt/python/3.5/bin
# 3.6 was not installed manually, but already is on the system. However # 3.6 was not installed manually, but already is on the system. However
# it's not on path (unless 3.6 is selected). # it's not on path (unless 3.6 is selected).

View File

@@ -3,9 +3,11 @@
Changelog Changelog
--------- ---------
0.12.2 () 0.13.0 ()
+++++++++++++++++++ +++++++++++++++++++
- Remove Python 3.3 support. Python 3.3 support has been dropped by the Python
foundation.
- Added ``include_builtins`` as a parameter to usages. - Added ``include_builtins`` as a parameter to usages.
- ``goto_assignments`` has a new ``follow_builtin_imports`` parameter that - ``goto_assignments`` has a new ``follow_builtin_imports`` parameter that
changes the previous behavior slightly. changes the previous behavior slightly.

View File

@@ -111,8 +111,8 @@ understands, see: `Features
<https://jedi.readthedocs.org/en/latest/docs/features.html>`_. A list of <https://jedi.readthedocs.org/en/latest/docs/features.html>`_. A list of
caveats can be found on the same page. caveats can be found on the same page.
You can run Jedi on CPython 2.7 or 3.3+ but it should also You can run Jedi on CPython 2.7 or 3.4+ but it should also
understand/parse code older than those versions. Additonally you should be able understand/parse code older than those versions. Additionally you should be able
to use `Virtualenvs <https://jedi.readthedocs.org/en/latest/docs/api.html#environments>`_ to use `Virtualenvs <https://jedi.readthedocs.org/en/latest/docs/api.html#environments>`_
very well. very well.

View File

@@ -3,9 +3,6 @@ environment:
- TOXENV: py27 - TOXENV: py27
PYTHON_PATH: C:\Python27 PYTHON_PATH: C:\Python27
JEDI_TEST_ENVIRONMENT: 27 JEDI_TEST_ENVIRONMENT: 27
- TOXENV: py27
PYTHON_PATH: C:\Python27
JEDI_TEST_ENVIRONMENT: 33
- TOXENV: py27 - TOXENV: py27
PYTHON_PATH: C:\Python27 PYTHON_PATH: C:\Python27
JEDI_TEST_ENVIRONMENT: 34 JEDI_TEST_ENVIRONMENT: 34
@@ -19,9 +16,6 @@ environment:
- TOXENV: py34 - TOXENV: py34
PYTHON_PATH: C:\Python34 PYTHON_PATH: C:\Python34
JEDI_TEST_ENVIRONMENT: 27 JEDI_TEST_ENVIRONMENT: 27
- TOXENV: py34
PYTHON_PATH: C:\Python34
JEDI_TEST_ENVIRONMENT: 33
- TOXENV: py34 - TOXENV: py34
PYTHON_PATH: C:\Python34 PYTHON_PATH: C:\Python34
JEDI_TEST_ENVIRONMENT: 34 JEDI_TEST_ENVIRONMENT: 34
@@ -35,9 +29,6 @@ environment:
- TOXENV: py35 - TOXENV: py35
PYTHON_PATH: C:\Python35 PYTHON_PATH: C:\Python35
JEDI_TEST_ENVIRONMENT: 27 JEDI_TEST_ENVIRONMENT: 27
- TOXENV: py35
PYTHON_PATH: C:\Python35
JEDI_TEST_ENVIRONMENT: 33
- TOXENV: py35 - TOXENV: py35
PYTHON_PATH: C:\Python35 PYTHON_PATH: C:\Python35
JEDI_TEST_ENVIRONMENT: 34 JEDI_TEST_ENVIRONMENT: 34
@@ -51,9 +42,6 @@ environment:
- TOXENV: py36 - TOXENV: py36
PYTHON_PATH: C:\Python36 PYTHON_PATH: C:\Python36
JEDI_TEST_ENVIRONMENT: 27 JEDI_TEST_ENVIRONMENT: 27
- TOXENV: py36
PYTHON_PATH: C:\Python36
JEDI_TEST_ENVIRONMENT: 33
- TOXENV: py36 - TOXENV: py36
PYTHON_PATH: C:\Python36 PYTHON_PATH: C:\Python36
JEDI_TEST_ENVIRONMENT: 34 JEDI_TEST_ENVIRONMENT: 34

View File

@@ -6,8 +6,7 @@ from functools import partial
import pytest import pytest
import jedi import jedi
from jedi.api.environment import get_default_environment, \ from jedi.api.environment import get_system_environment, InterpreterEnvironment
get_system_environment, InterpreterEnvironment
from jedi._compatibility import py_version from jedi._compatibility import py_version
collect_ignore = [ collect_ignore = [
@@ -98,9 +97,6 @@ def environment(request):
if version is None: if version is None:
version = os.environ.get('JEDI_TEST_ENVIRONMENT', str(py_version)) version = os.environ.get('JEDI_TEST_ENVIRONMENT', str(py_version))
if int(version) == py_version:
return get_default_environment()
return get_system_environment(version[0] + '.' + version[1:]) return get_system_environment(version[0] + '.' + version[1:])

View File

@@ -20,7 +20,7 @@ make it work.
General Features General Features
---------------- ----------------
- Python 2.7 and 3.3+ support - Python 2.7 and 3.4+ support
- Ignores syntax errors and wrong indentation - Ignores syntax errors and wrong indentation
- Can deal with complex module / function / class structures - Can deal with complex module / function / class structures
- Great Virtualenv support - Great Virtualenv support

View File

@@ -16,8 +16,6 @@ except ImportError:
pass pass
is_py3 = sys.version_info[0] >= 3 is_py3 = sys.version_info[0] >= 3
is_py33 = is_py3 and sys.version_info[1] >= 3
is_py34 = is_py3 and sys.version_info[1] >= 4
is_py35 = is_py3 and sys.version_info[1] >= 5 is_py35 = is_py3 and sys.version_info[1] >= 5
py_version = int(str(sys.version_info[0]) + str(sys.version_info[1])) py_version = int(str(sys.version_info[0]) + str(sys.version_info[1]))
@@ -116,7 +114,7 @@ def find_module_py33(string, path=None, loader=None, full_name=None, is_global_s
return module_file, module_path, is_package return module_file, module_path, is_package
def find_module_pre_py33(string, path=None, full_name=None, is_global_search=True): def find_module_pre_py34(string, path=None, full_name=None, is_global_search=True):
# This import is here, because in other places it will raise a # This import is here, because in other places it will raise a
# DeprecationWarning. # DeprecationWarning.
import imp import imp
@@ -151,8 +149,7 @@ def find_module_pre_py33(string, path=None, full_name=None, is_global_search=Tru
raise ImportError("No module named {}".format(string)) raise ImportError("No module named {}".format(string))
find_module = find_module_py33 if is_py33 else find_module_pre_py33 find_module = find_module_py34 if is_py3 else find_module_pre_py34
find_module = find_module_py34 if is_py34 else find_module
find_module.__doc__ = """ find_module.__doc__ = """
Provides information about a module. Provides information about a module.
@@ -369,6 +366,7 @@ def print_to_stderr(*args):
eval("print(*args, file=sys.stderr)") eval("print(*args, file=sys.stderr)")
else: else:
print >> sys.stderr, args print >> sys.stderr, args
sys.stderr.flush()
def utf8_repr(func): def utf8_repr(func):
@@ -521,6 +519,9 @@ class GeneralizedPopen(subprocess.Popen):
except AttributeError: except AttributeError:
CREATE_NO_WINDOW = 0x08000000 CREATE_NO_WINDOW = 0x08000000
kwargs['creationflags'] = CREATE_NO_WINDOW kwargs['creationflags'] = CREATE_NO_WINDOW
# The child process doesn't need file descriptors except 0, 1, 2.
# This is unix only.
kwargs['close_fds'] = 'posix' in sys.builtin_module_names
super(GeneralizedPopen, self).__init__(*args, **kwargs) super(GeneralizedPopen, self).__init__(*args, **kwargs)

View File

@@ -5,7 +5,7 @@ from textwrap import dedent
import operator as op import operator as op
from collections import namedtuple from collections import namedtuple
from jedi._compatibility import unicode, is_py3, is_py34, builtins, \ from jedi._compatibility import unicode, is_py3, builtins, \
py_version, force_unicode, print_to_stderr py_version, force_unicode, print_to_stderr
from jedi.evaluate.compiled.getattr_static import getattr_static from jedi.evaluate.compiled.getattr_static import getattr_static
@@ -31,10 +31,9 @@ NOT_CLASS_TYPES = (
if is_py3: if is_py3:
NOT_CLASS_TYPES += ( NOT_CLASS_TYPES += (
types.MappingProxyType, types.MappingProxyType,
types.SimpleNamespace types.SimpleNamespace,
types.DynamicClassAttribute,
) )
if is_py34:
NOT_CLASS_TYPES += (types.DynamicClassAttribute,)
# Those types don't exist in typing. # Those types don't exist in typing.
@@ -141,7 +140,7 @@ def load_module(evaluator, dotted_name, sys_path):
__import__(dotted_name) __import__(dotted_name)
except ImportError: except ImportError:
# If a module is "corrupt" or not really a Python module or whatever. # If a module is "corrupt" or not really a Python module or whatever.
print_to_stderr('Module %s not importable.' % dotted_name) print_to_stderr('Module %s not importable in path %s.' % (dotted_name, sys_path))
return None return None
except Exception: except Exception:
# Since __import__ pretty much makes code execution possible, just # Since __import__ pretty much makes code execution possible, just

View File

@@ -447,8 +447,11 @@ def create_from_name(evaluator, compiled_object, name):
pass pass
access = compiled_object.access_handle.getattr(name, default=None) access = compiled_object.access_handle.getattr(name, default=None)
parent_context = compiled_object
if parent_context.is_class():
parent_context = parent_context.parent_context
return create_cached_compiled_object( return create_cached_compiled_object(
evaluator, access, parent_context=compiled_object, faked=faked evaluator, access, parent_context=parent_context, faked=faked
) )

View File

@@ -15,9 +15,15 @@ import errno
import weakref import weakref
import traceback import traceback
from functools import partial from functools import partial
from threading import Thread
try:
from queue import Queue, Empty
except ImportError:
from Queue import Queue, Empty # python 2.7
from jedi._compatibility import queue, is_py3, force_unicode, \ from jedi._compatibility import queue, is_py3, force_unicode, \
pickle_dump, pickle_load, GeneralizedPopen pickle_dump, pickle_load, GeneralizedPopen
from jedi import debug
from jedi.cache import memoize_method from jedi.cache import memoize_method
from jedi.evaluate.compiled.subprocess import functions from jedi.evaluate.compiled.subprocess import functions
from jedi.evaluate.compiled.access import DirectObjectAccess, AccessPath, \ from jedi.evaluate.compiled.access import DirectObjectAccess, AccessPath, \
@@ -28,6 +34,12 @@ from jedi.api.exceptions import InternalError
_MAIN_PATH = os.path.join(os.path.dirname(__file__), '__main__.py') _MAIN_PATH = os.path.join(os.path.dirname(__file__), '__main__.py')
def _enqueue_output(out, queue):
for line in iter(out.readline, b''):
queue.put(line)
out.close()
def _get_function(name): def _get_function(name):
return getattr(functions, name) return getattr(functions, name)
@@ -135,6 +147,7 @@ class CompiledSubprocess(object):
@property @property
@memoize_method @memoize_method
def _process(self): def _process(self):
debug.dbg('Start environment subprocess %s', self._executable)
parso_path = sys.modules['parso'].__file__ parso_path = sys.modules['parso'].__file__
args = ( args = (
self._executable, self._executable,
@@ -142,7 +155,7 @@ class CompiledSubprocess(object):
os.path.dirname(os.path.dirname(parso_path)), os.path.dirname(os.path.dirname(parso_path)),
'.'.join(str(x) for x in sys.version_info[:3]), '.'.join(str(x) for x in sys.version_info[:3]),
) )
return GeneralizedPopen( process = GeneralizedPopen(
args, args,
stdin=subprocess.PIPE, stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stdout=subprocess.PIPE,
@@ -151,6 +164,14 @@ class CompiledSubprocess(object):
# (this is already the case on Python 3). # (this is already the case on Python 3).
bufsize=-1 bufsize=-1
) )
self._stderr_queue = Queue()
self._stderr_thread = t = Thread(
target=_enqueue_output,
args=(process.stderr, self._stderr_queue)
)
t.daemon = True
t.start()
return process
def run(self, evaluator, function, args=(), kwargs={}): def run(self, evaluator, function, args=(), kwargs={}):
# Delete old evaluators. # Delete old evaluators.
@@ -219,6 +240,16 @@ class CompiledSubprocess(object):
stderr, stderr,
)) ))
while True:
# Try to do some error reporting from the subprocess and print its
# stderr contents.
try:
line = self._stderr_queue.get_nowait()
line = line.decode('utf-8', 'replace')
debug.warning('stderr output: %s' % line.rstrip('\n'))
except Empty:
break
if is_exception: if is_exception:
# Replace the attribute error message with a the traceback. It's # Replace the attribute error message with a the traceback. It's
# way more informative. # way more informative.
@@ -282,11 +313,9 @@ class Listener(object):
def listen(self): def listen(self):
stdout = sys.stdout stdout = sys.stdout
# Mute stdout/stderr. Nobody should actually be able to write to those, # Mute stdout. Nobody should actually be able to write to it,
# because stdout is used for IPC and stderr will just be annoying if it # because stdout is used for IPC.
# leaks (on module imports).
sys.stdout = open(os.devnull, 'w') sys.stdout = open(os.devnull, 'w')
sys.stderr = open(os.devnull, 'w')
stdin = sys.stdin stdin = sys.stdin
if sys.version_info[0] > 2: if sys.version_info[0] > 2:
stdout = stdout.buffer stdout = stdout.buffer

View File

@@ -11,7 +11,7 @@ from jedi.evaluate.arguments import AbstractArguments, AnonymousArguments
from jedi.cache import memoize_method from jedi.cache import memoize_method
from jedi.evaluate.context.function import FunctionExecutionContext, \ from jedi.evaluate.context.function import FunctionExecutionContext, \
FunctionContext, AbstractFunction FunctionContext, AbstractFunction
from jedi.evaluate.context.klass import ClassContext, apply_py__get__ from jedi.evaluate.context.klass import ClassContext, apply_py__get__, ClassFilter
from jedi.evaluate.context import iterable from jedi.evaluate.context import iterable
from jedi.parser_utils import get_parent_scope from jedi.parser_utils import get_parent_scope
@@ -87,7 +87,7 @@ class AbstractInstanceContext(Context):
def execute_function_slots(self, names, *evaluated_args): def execute_function_slots(self, names, *evaluated_args):
return ContextSet.from_sets( return ContextSet.from_sets(
name.execute_evaluated(*evaluated_args) name.infer().execute_evaluated(*evaluated_args)
for name in names for name in names
) )
@@ -169,7 +169,7 @@ class AbstractInstanceContext(Context):
def create_init_executions(self): def create_init_executions(self):
for name in self.get_function_slot_names(u'__init__'): for name in self.get_function_slot_names(u'__init__'):
if isinstance(name, SelfName): if isinstance(name, LazyInstanceClassName):
function = FunctionContext.from_context( function = FunctionContext.from_context(
self.parent_context, self.parent_context,
name.tree_name.parent name.tree_name.parent
@@ -265,17 +265,23 @@ class AnonymousInstance(TreeInstance):
class CompiledInstanceName(compiled.CompiledName): class CompiledInstanceName(compiled.CompiledName):
def __init__(self, evaluator, instance, parent_context, name):
super(CompiledInstanceName, self).__init__(evaluator, parent_context, name) def __init__(self, evaluator, instance, klass, name):
super(CompiledInstanceName, self).__init__(
evaluator,
klass.parent_context,
name.string_name
)
self._instance = instance self._instance = instance
self._class = klass
self._class_member_name = name
@iterator_to_context_set @iterator_to_context_set
def infer(self): def infer(self):
for result_context in super(CompiledInstanceName, self).infer(): for result_context in self._class_member_name.infer():
is_function = result_context.api_type == 'function' is_function = result_context.api_type == 'function'
if result_context.tree_node is not None and is_function: if result_context.tree_node is not None and is_function:
yield BoundMethod(self._instance, self._class, result_context)
yield BoundMethod(self._instance, self.parent_context, result_context)
else: else:
if is_function: if is_function:
yield CompiledBoundMethod(result_context) yield CompiledBoundMethod(result_context)
@@ -283,20 +289,26 @@ class CompiledInstanceName(compiled.CompiledName):
yield result_context yield result_context
class CompiledInstanceClassFilter(compiled.CompiledObjectFilter): class CompiledInstanceClassFilter(filters.AbstractFilter):
name_class = CompiledInstanceName name_class = CompiledInstanceName
def __init__(self, evaluator, instance, compiled_object): def __init__(self, evaluator, instance, klass):
super(CompiledInstanceClassFilter, self).__init__( self._evaluator = evaluator
evaluator,
compiled_object,
is_instance=True,
)
self._instance = instance self._instance = instance
self._class = klass
self._class_filter = next(klass.get_filters(is_instance=True))
def _create_name(self, name): def get(self, name):
return self.name_class( return self._convert(self._class_filter.get(name))
self._evaluator, self._instance, self._compiled_object, name)
def values(self):
return self._convert(self._class_filter.values())
def _convert(self, names):
return [
CompiledInstanceName(self._evaluator, self._instance, self._class, n)
for n in names
]
class BoundMethod(AbstractFunction): class BoundMethod(AbstractFunction):
@@ -332,11 +344,6 @@ class CompiledBoundMethod(compiled.CompiledObject):
return list(super(CompiledBoundMethod, self).get_param_names())[1:] return list(super(CompiledBoundMethod, self).get_param_names())[1:]
class InstanceNameDefinition(filters.TreeNameDefinition):
def infer(self):
return super(InstanceNameDefinition, self).infer()
class SelfName(filters.TreeNameDefinition): class SelfName(filters.TreeNameDefinition):
""" """
This name calculates the parent_context lazily. This name calculates the parent_context lazily.
@@ -351,10 +358,15 @@ class SelfName(filters.TreeNameDefinition):
return self._instance.create_instance_context(self.class_context, self.tree_name) return self._instance.create_instance_context(self.class_context, self.tree_name)
class LazyInstanceClassName(SelfName): class LazyInstanceClassName(object):
def __init__(self, instance, class_context, class_member_name):
self._instance = instance
self.class_context = class_context
self._class_member_name = class_member_name
@iterator_to_context_set @iterator_to_context_set
def infer(self): def infer(self):
for result_context in super(LazyInstanceClassName, self).infer(): for result_context in self._class_member_name.infer():
if isinstance(result_context, FunctionContext): if isinstance(result_context, FunctionContext):
# Classes are never used to resolve anything within the # Classes are never used to resolve anything within the
# functions. Only other functions and modules will resolve # functions. Only other functions and modules will resolve
@@ -364,45 +376,51 @@ class LazyInstanceClassName(SelfName):
for c in apply_py__get__(result_context, self._instance): for c in apply_py__get__(result_context, self._instance):
yield c yield c
def __getattr__(self, name):
return getattr(self._class_member_name, name)
class InstanceClassFilter(filters.ParserTreeFilter):
name_class = LazyInstanceClassName
class InstanceClassFilter(filters.AbstractFilter):
"""
This filter is special in that it uses the class filter and wraps the
resulting names in LazyINstanceClassName. The idea is that the class name
filtering can be very flexible and always be reflected in instances.
"""
def __init__(self, evaluator, context, class_context, origin_scope): def __init__(self, evaluator, context, class_context, origin_scope):
super(InstanceClassFilter, self).__init__( self._instance = context
evaluator=evaluator,
context=context,
node_context=class_context,
origin_scope=origin_scope
)
self._class_context = class_context self._class_context = class_context
self._class_filter = next(class_context.get_filters(
search_global=False,
origin_scope=origin_scope,
is_instance=True,
))
def _equals_origin_scope(self): def get(self, name):
node = self._origin_scope return self._convert(self._class_filter.get(name))
while node is not None:
if node == self._parser_scope or node == self.context:
return True
node = get_parent_scope(node)
return False
def _access_possible(self, name): def values(self):
return not name.value.startswith('__') or name.value.endswith('__') \ return self._convert(self._class_filter.values())
or self._equals_origin_scope()
def _filter(self, names): def _convert(self, names):
names = super(InstanceClassFilter, self)._filter(names) return [LazyInstanceClassName(self._instance, self._class_context, n) for n in names]
return [name for name in names if self._access_possible(name)]
def _convert_names(self, names):
return [self.name_class(self.context, self._class_context, name) for name in names]
class SelfAttributeFilter(InstanceClassFilter): class SelfAttributeFilter(ClassFilter):
""" """
This class basically filters all the use cases where `self.*` was assigned. This class basically filters all the use cases where `self.*` was assigned.
""" """
name_class = SelfName name_class = SelfName
def __init__(self, evaluator, context, class_context, origin_scope):
super(SelfAttributeFilter, self).__init__(
evaluator=evaluator,
context=context,
node_context=class_context,
origin_scope=origin_scope,
is_instance=True,
)
self._class_context = class_context
def _filter(self, names): def _filter(self, names):
names = self._filter_self_names(names) names = self._filter_self_names(names)
if isinstance(self._parser_scope, compiled.CompiledObject) and False: if isinstance(self._parser_scope, compiled.CompiledObject) and False:
@@ -421,6 +439,9 @@ class SelfAttributeFilter(InstanceClassFilter):
if name.is_definition() and self._access_possible(name): if name.is_definition() and self._access_possible(name):
yield name yield name
def _convert_names(self, names):
return [self.name_class(self.context, self._class_context, name) for name in names]
def _check_flows(self, names): def _check_flows(self, names):
return names return names

View File

@@ -38,6 +38,7 @@ py__doc__(include_call_signature: Returns the docstring for a context.
""" """
from jedi._compatibility import use_metaclass from jedi._compatibility import use_metaclass
from jedi.parser_utils import get_parent_scope
from jedi.evaluate.cache import evaluator_method_cache, CachedMetaClass from jedi.evaluate.cache import evaluator_method_cache, CachedMetaClass
from jedi.evaluate import compiled from jedi.evaluate import compiled
from jedi.evaluate.lazy_context import LazyKnownContext from jedi.evaluate.lazy_context import LazyKnownContext
@@ -58,9 +59,10 @@ def apply_py__get__(context, base_context):
class ClassName(TreeNameDefinition): class ClassName(TreeNameDefinition):
def __init__(self, parent_context, tree_name, name_context): def __init__(self, parent_context, tree_name, name_context, apply_decorators):
super(ClassName, self).__init__(parent_context, tree_name) super(ClassName, self).__init__(parent_context, tree_name)
self._name_context = name_context self._name_context = name_context
self._apply_decorators = apply_decorators
@iterator_to_context_set @iterator_to_context_set
def infer(self): def infer(self):
@@ -70,16 +72,45 @@ class ClassName(TreeNameDefinition):
self.parent_context.evaluator, self._name_context, self.tree_name) self.parent_context.evaluator, self._name_context, self.tree_name)
for result_context in inferred: for result_context in inferred:
for c in apply_py__get__(result_context, self.parent_context): if self._apply_decorators:
yield c for c in apply_py__get__(result_context, self.parent_context):
yield c
else:
yield result_context
class ClassFilter(ParserTreeFilter): class ClassFilter(ParserTreeFilter):
name_class = ClassName name_class = ClassName
def __init__(self, *args, **kwargs):
self._is_instance = kwargs.pop('is_instance') # Python 2 :/
super(ClassFilter, self).__init__(*args, **kwargs)
def _convert_names(self, names): def _convert_names(self, names):
return [self.name_class(self.context, name, self._node_context) return [
for name in names] self.name_class(
parent_context=self.context,
tree_name=name,
name_context=self._node_context,
apply_decorators=not self._is_instance,
) for name in names
]
def _equals_origin_scope(self):
node = self._origin_scope
while node is not None:
if node == self._parser_scope or node == self.context:
return True
node = get_parent_scope(node)
return False
def _access_possible(self, name):
return not name.value.startswith('__') or name.value.endswith('__') \
or self._equals_origin_scope()
def _filter(self, names):
names = super(ClassFilter, self)._filter(names)
return [name for name in names if self._access_possible(name)]
class ClassContext(use_metaclass(CachedMetaClass, TreeContext)): class ClassContext(use_metaclass(CachedMetaClass, TreeContext)):
@@ -163,7 +194,9 @@ class ClassContext(use_metaclass(CachedMetaClass, TreeContext)):
else: else:
yield ClassFilter( yield ClassFilter(
self.evaluator, self, node_context=cls, self.evaluator, self, node_context=cls,
origin_scope=origin_scope) origin_scope=origin_scope,
is_instance=is_instance
)
def is_class(self): def is_class(self):
return True return True

View File

@@ -38,12 +38,6 @@ class AbstractNameDefinition(object):
return '<%s: %s>' % (self.__class__.__name__, self.string_name) return '<%s: %s>' % (self.__class__.__name__, self.string_name)
return '<%s: %s@%s>' % (self.__class__.__name__, self.string_name, self.start_pos) return '<%s: %s@%s>' % (self.__class__.__name__, self.string_name, self.start_pos)
def execute(self, arguments):
return self.infer().execute(arguments)
def execute_evaluated(self, *args, **kwargs):
return self.infer().execute_evaluated(*args, **kwargs)
def is_import(self): def is_import(self):
return False return False

View File

@@ -29,7 +29,7 @@ setup(name='jedi',
keywords='python completion refactoring vim', keywords='python completion refactoring vim',
long_description=readme, long_description=readme,
packages=find_packages(exclude=['test', 'test.*']), packages=find_packages(exclude=['test', 'test.*']),
python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*', python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*',
install_requires=install_requires, install_requires=install_requires,
extras_require={'dev': ['docopt']}, extras_require={'dev': ['docopt']},
package_data={'jedi': ['evaluate/compiled/fake/*.pym']}, package_data={'jedi': ['evaluate/compiled/fake/*.pym']},
@@ -43,7 +43,6 @@ setup(name='jedi',
'Programming Language :: Python :: 2', 'Programming Language :: Python :: 2',
'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.3',
'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.6',

View File

@@ -437,7 +437,7 @@ def test_func():
#? int() #? int()
tuple({1})[0] tuple({1})[0]
# python >= 3.3 # python >= 3.4
# ----------------- # -----------------
# PEP 3132 Extended Iterable Unpacking (star unpacking) # PEP 3132 Extended Iterable Unpacking (star unpacking)
# ----------------- # -----------------

View File

@@ -417,6 +417,9 @@ class PrivateVar():
def __private_func(self): def __private_func(self):
return 1 return 1
#? int()
__private_func()
def wrap_private(self): def wrap_private(self):
return self.__private_func() return self.__private_func()
#? [] #? []
@@ -425,6 +428,8 @@ PrivateVar().__var
PrivateVar().__var PrivateVar().__var
#? [] #? []
PrivateVar().__private_func PrivateVar().__private_func
#? []
PrivateVar.__private_func
#? int() #? int()
PrivateVar().wrap_private() PrivateVar().wrap_private()

View File

@@ -220,7 +220,7 @@ def x():
# yield from # yield from
# ----------------- # -----------------
# python >= 3.3 # python >= 3.4
def yield_from(): def yield_from():
yield from iter([1]) yield from iter([1])

View File

@@ -1,6 +1,6 @@
""" Pep-0484 type hinting """ """ Pep-0484 type hinting """
# python >= 3.2 # python >= 3.4
class A(): class A():

View File

@@ -243,7 +243,7 @@ for key in x.keys():
for value in x.values(): for value in x.values():
#? int() #? int()
value value
# python >= 3.2 # python >= 3.4
class TestDefaultDict(typing.DefaultDict[str, int]): class TestDefaultDict(typing.DefaultDict[str, int]):
def setdud(self): def setdud(self):
@@ -271,7 +271,7 @@ for key in x.keys():
for value in x.values(): for value in x.values():
#? int() #? int()
value value
# python >= 3.2 # python >= 3.4
""" """

View File

@@ -6,7 +6,7 @@ import pytest
from ..helpers import TestCase from ..helpers import TestCase
from jedi import cache from jedi import cache
from jedi._compatibility import is_py33 from jedi._compatibility import is_py3
def assert_signature(Script, source, expected_name, expected_index=0, line=None, column=None): def assert_signature(Script, source, expected_name, expected_index=0, line=None, column=None):
@@ -247,7 +247,7 @@ def _params(Script, source, line=None, column=None):
def test_param_name(Script): def test_param_name(Script):
if not is_py33: if not is_py3:
p = _params(Script, '''int(''') p = _params(Script, '''int(''')
# int is defined as: `int(x[, base])` # int is defined as: `int(x[, base])`
assert p[0].name == 'x' assert p[0].name == 'x'

View File

@@ -10,8 +10,10 @@ import os
import shutil import shutil
import sys import sys
import pytest
import jedi import jedi
from ..helpers import cwd_at from jedi.api.environment import SameEnvironment
SRC = """class Foo: SRC = """class Foo:
@@ -22,35 +24,44 @@ class Bar:
""" """
def generate_pyc(): @pytest.fixture
os.mkdir("dummy_package") def pyc_project_path(tmpdir):
with open("dummy_package/__init__.py", 'w'): path = tmpdir.strpath
dummy_package_path = os.path.join(path, "dummy_package")
os.mkdir(dummy_package_path)
with open(os.path.join(dummy_package_path, "__init__.py"), 'w'):
pass pass
with open("dummy_package/dummy.py", 'w') as f:
dummy_path = os.path.join(dummy_package_path, 'dummy.py')
with open(dummy_path, 'w') as f:
f.write(SRC) f.write(SRC)
import compileall import compileall
compileall.compile_file("dummy_package/dummy.py") compileall.compile_file(dummy_path)
os.remove("dummy_package/dummy.py") os.remove(dummy_path)
if sys.version_info[0] == 3: if sys.version_info.major == 3:
# Python3 specific: # Python3 specific:
# To import pyc modules, we must move them out of the __pycache__ # To import pyc modules, we must move them out of the __pycache__
# directory and rename them to remove ".cpython-%s%d" # directory and rename them to remove ".cpython-%s%d"
# see: http://stackoverflow.com/questions/11648440/python-does-not-detect-pyc-files # see: http://stackoverflow.com/questions/11648440/python-does-not-detect-pyc-files
for f in os.listdir("dummy_package/__pycache__"): pycache = os.path.join(dummy_package_path, "__pycache__")
for f in os.listdir(pycache):
dst = f.replace('.cpython-%s%s' % sys.version_info[:2], "") dst = f.replace('.cpython-%s%s' % sys.version_info[:2], "")
dst = os.path.join("dummy_package", dst) dst = os.path.join(dummy_package_path, dst)
shutil.copy(os.path.join("dummy_package/__pycache__", f), dst) shutil.copy(os.path.join(pycache, f), dst)
try:
yield path
finally:
shutil.rmtree(path)
@cwd_at('test/test_evaluate') def test_pyc(pyc_project_path):
def test_pyc(Script):
""" """
The list of completion must be greater than 2. The list of completion must be greater than 2.
""" """
try: path = os.path.join(pyc_project_path, 'blub.py')
generate_pyc() s = jedi.Script(
s = jedi.Script("from dummy_package import dummy; dummy.", path='blub.py') "from dummy_package import dummy; dummy.",
assert len(s.completions()) >= 2 path=path,
finally: environment=SameEnvironment())
shutil.rmtree("dummy_package") assert len(s.completions()) >= 2

View File

@@ -1,8 +1,8 @@
[tox] [tox]
envlist = py27, py33, py34, py35, py36 envlist = py27, py34, py35, py36
[testenv] [testenv]
deps = deps =
pytest>=2.3.5, < 3.3 pytest>=2.3.5
pytest-cache pytest-cache
# docopt for sith doctests # docopt for sith doctests
docopt docopt
@@ -19,7 +19,6 @@ setenv =
# To test Jedi in different versions than the same Python version, set a # To test Jedi in different versions than the same Python version, set a
# different test environment. # different test environment.
env27: JEDI_TEST_ENVIRONMENT=27 env27: JEDI_TEST_ENVIRONMENT=27
env33: JEDI_TEST_ENVIRONMENT=33
env34: JEDI_TEST_ENVIRONMENT=34 env34: JEDI_TEST_ENVIRONMENT=34
env35: JEDI_TEST_ENVIRONMENT=35 env35: JEDI_TEST_ENVIRONMENT=35
env36: JEDI_TEST_ENVIRONMENT=36 env36: JEDI_TEST_ENVIRONMENT=36
@@ -33,10 +32,6 @@ deps =
# numpydoc for typing scipy stack # numpydoc for typing scipy stack
numpydoc numpydoc
{[testenv]deps} {[testenv]deps}
[testenv:py33]
deps =
typing
{[testenv]deps}
[testenv:py34] [testenv:py34]
deps = deps =
typing typing

View File

@@ -8,10 +8,6 @@ set -e
sudo chown root: /opt/python/3.6/bin/python sudo chown root: /opt/python/3.6/bin/python
sudo chown root: /opt/python/3.6.3/bin/python sudo chown root: /opt/python/3.6.3/bin/python
if [[ $JEDI_TEST_ENVIRONMENT == "33" ]]; then
VERSION=3.3
DOWNLOAD=1
fi
if [[ $JEDI_TEST_ENVIRONMENT == "35" ]]; then if [[ $JEDI_TEST_ENVIRONMENT == "35" ]]; then
VERSION=3.5 VERSION=3.5
DOWNLOAD=1 DOWNLOAD=1