From ba81aa16a2a816dc97e6cce11f948e18f918afb8 Mon Sep 17 00:00:00 2001 From: Dave Halter Date: Thu, 28 Dec 2017 23:07:53 +0100 Subject: [PATCH] Use unicode in way more cases --- jedi/api/classes.py | 4 +-- jedi/evaluate/analysis.py | 4 +-- jedi/evaluate/compiled/context.py | 2 +- jedi/evaluate/compiled/subprocess/__init__.py | 7 +++-- jedi/evaluate/context/instance.py | 14 +++++----- jedi/evaluate/context/klass.py | 4 +-- jedi/evaluate/finder.py | 4 +-- jedi/evaluate/syntax_tree.py | 26 ++++++++++--------- 8 files changed, 35 insertions(+), 30 deletions(-) diff --git a/jedi/api/classes.py b/jedi/api/classes.py index 36e8aa9e..a2f5ffa3 100644 --- a/jedi/api/classes.py +++ b/jedi/api/classes.py @@ -324,9 +324,9 @@ class BaseDefinition(object): param_names = param_names[1:] elif isinstance(context, (instance.AbstractInstanceContext, ClassContext)): if isinstance(context, ClassContext): - search = '__init__' + search = u'__init__' else: - search = '__call__' + search = u'__call__' names = context.get_function_slot_names(search) if not names: return [] diff --git a/jedi/evaluate/analysis.py b/jedi/evaluate/analysis.py index 67dd5af0..0ae1c90b 100644 --- a/jedi/evaluate/analysis.py +++ b/jedi/evaluate/analysis.py @@ -117,8 +117,8 @@ def add_attribute_error(name_context, lookup_context, name): # instead of an error, if that happens. typ = Error if isinstance(lookup_context, AbstractInstanceContext): - slot_names = lookup_context.get_function_slot_names('__getattr__') + \ - lookup_context.get_function_slot_names('__getattribute__') + slot_names = lookup_context.get_function_slot_names(u'__getattr__') + \ + lookup_context.get_function_slot_names(u'__getattribute__') for n in slot_names: # TODO do we even get here? if isinstance(name, CompiledInstanceName) and \ diff --git a/jedi/evaluate/compiled/context.py b/jedi/evaluate/compiled/context.py index e3aa3df9..f4230e56 100644 --- a/jedi/evaluate/compiled/context.py +++ b/jedi/evaluate/compiled/context.py @@ -21,7 +21,7 @@ class CheckAttribute(object): def __init__(self, func): self.func = func # Remove the py in front of e.g. py__call__. - self.check_name = func.__name__[2:] + self.check_name = force_unicode(func.__name__[2:]) def __get__(self, instance, owner): if instance is None: diff --git a/jedi/evaluate/compiled/subprocess/__init__.py b/jedi/evaluate/compiled/subprocess/__init__.py index ec6802de..81c01204 100644 --- a/jedi/evaluate/compiled/subprocess/__init__.py +++ b/jedi/evaluate/compiled/subprocess/__init__.py @@ -14,7 +14,7 @@ import weakref import pickle from functools import partial -from jedi._compatibility import queue, is_py3 +from jedi._compatibility import queue, is_py3, force_unicode from jedi.cache import memoize_method from jedi.evaluate.compiled.subprocess import functions from jedi.evaluate.compiled.access import DirectObjectAccess, AccessPath, \ @@ -286,7 +286,7 @@ class AccessHandle(object): #if not is_py3: print >> sys.stderr, name #print('getattr', name, file=sys.stderr) - return partial(self._workaround, name) + return partial(self._workaround, force_unicode(name)) def _workaround(self, name, *args, **kwargs): """ @@ -294,6 +294,9 @@ class AccessHandle(object): happen. They are also the only unhashable objects that we're passing around. """ + # Python 2 compatibility + kwargs = {force_unicode(key): value for key, value in kwargs.items()} + if args and isinstance(args[0], slice): return self._subprocess.get_compiled_method_return(self.id, name, *args, **kwargs) return self._cached_results(name, *args, **kwargs) diff --git a/jedi/evaluate/context/instance.py b/jedi/evaluate/context/instance.py index f603ac90..90e00498 100644 --- a/jedi/evaluate/context/instance.py +++ b/jedi/evaluate/context/instance.py @@ -53,7 +53,7 @@ class AbstractInstanceContext(Context): @property def py__call__(self): - names = self.get_function_slot_names('__call__') + names = self.get_function_slot_names(u'__call__') if not names: # Means the Instance is not callable. raise AttributeError @@ -89,7 +89,7 @@ class AbstractInstanceContext(Context): def py__get__(self, obj): # Arguments in __get__ descriptors are obj, class. # `method` is the new parent of the array, don't know if that's good. - names = self.get_function_slot_names('__get__') + names = self.get_function_slot_names(u'__get__') if names: if isinstance(obj, AbstractInstanceContext): return self.execute_function_slots(names, obj, obj.class_context) @@ -118,7 +118,7 @@ class AbstractInstanceContext(Context): def py__getitem__(self, index): try: - names = self.get_function_slot_names('__getitem__') + names = self.get_function_slot_names(u'__getitem__') except KeyError: debug.warning('No __getitem__, cannot access the array.') return NO_CONTEXTS @@ -127,7 +127,7 @@ class AbstractInstanceContext(Context): return self.execute_function_slots(names, index_obj) def py__iter__(self): - iter_slot_names = self.get_function_slot_names('__iter__') + iter_slot_names = self.get_function_slot_names(u'__iter__') if not iter_slot_names: debug.warning('No __iter__ on %s.' % self) return @@ -136,9 +136,9 @@ class AbstractInstanceContext(Context): if isinstance(generator, AbstractInstanceContext): # `__next__` logic. if self.evaluator.environment.version_info.major == 2: - name = 'next' + name = u'next' else: - name = '__next__' + name = u'__next__' iter_slot_names = generator.get_function_slot_names(name) if iter_slot_names: yield LazyKnownContexts( @@ -166,7 +166,7 @@ class AbstractInstanceContext(Context): ) def create_init_executions(self): - for name in self.get_function_slot_names('__init__'): + for name in self.get_function_slot_names(u'__init__'): if isinstance(name, SelfName): yield self._create_init_execution(name.class_context, name.tree_name.parent) diff --git a/jedi/evaluate/context/klass.py b/jedi/evaluate/context/klass.py index 4a645f45..9eed9cd1 100644 --- a/jedi/evaluate/context/klass.py +++ b/jedi/evaluate/context/klass.py @@ -139,7 +139,7 @@ class ClassContext(use_metaclass(CachedMetaClass, TreeContext)): args = arguments.TreeArguments(self.evaluator, self, arglist) return [value for key, value in args.unpack() if key is None] else: - return [LazyKnownContext(compiled.builtin_from_name(self.evaluator, 'object'))] + return [LazyKnownContext(compiled.builtin_from_name(self.evaluator, u'object'))] def py__call__(self, params): from jedi.evaluate.context import TreeInstance @@ -182,7 +182,7 @@ class ClassContext(use_metaclass(CachedMetaClass, TreeContext)): return [] def get_param_names(self): - for name in self.get_function_slot_names('__init__'): + for name in self.get_function_slot_names(u'__init__'): for context_ in name.infer(): try: method = context_.get_param_names diff --git a/jedi/evaluate/finder.py b/jedi/evaluate/finder.py index d94add4a..21ae824f 100644 --- a/jedi/evaluate/finder.py +++ b/jedi/evaluate/finder.py @@ -149,8 +149,8 @@ class NameFinder(object): # We are inversing this, because a hand-crafted `__getattribute__` # could still call another hand-crafted `__getattr__`, but not the # other way around. - names = (inst.get_function_slot_names('__getattr__') or - inst.get_function_slot_names('__getattribute__')) + names = (inst.get_function_slot_names(u'__getattr__') or + inst.get_function_slot_names(u'__getattribute__')) return inst.execute_function_slots(names, name) def _names_to_types(self, names, attribute_lookup): diff --git a/jedi/evaluate/syntax_tree.py b/jedi/evaluate/syntax_tree.py index 654fad5d..512efbf4 100644 --- a/jedi/evaluate/syntax_tree.py +++ b/jedi/evaluate/syntax_tree.py @@ -5,6 +5,7 @@ import copy from parso.python import tree +from jedi._compatibility import force_unicode from jedi import debug from jedi import parser_utils from jedi.evaluate.base_context import ContextSet, NO_CONTEXTS, ContextualizedNode, \ @@ -367,40 +368,41 @@ def _bool_to_context(evaluator, bool_): def _eval_comparison_part(evaluator, context, left, operator, right): l_is_num = is_number(left) r_is_num = is_number(right) - if operator == '*': + str_operator = force_unicode(str(operator.value)) + if str_operator == '*': # for iterables, ignore * operations if isinstance(left, iterable.AbstractIterable) or is_string(left): return ContextSet(left) elif isinstance(right, iterable.AbstractIterable) or is_string(right): return ContextSet(right) - elif operator == '+': + elif str_operator == '+': if l_is_num and r_is_num or is_string(left) and is_string(right): - return ContextSet(left.execute_operation(right, operator)) + return ContextSet(left.execute_operation(right, str_operator)) elif _is_tuple(left) and _is_tuple(right) or _is_list(left) and _is_list(right): return ContextSet(iterable.MergedArray(evaluator, (left, right))) - elif operator == '-': + elif str_operator == '-': if l_is_num and r_is_num: - return ContextSet(left.execute_operation(right, operator)) - elif operator == '%': + return ContextSet(left.execute_operation(right, str_operator)) + elif str_operator == '%': # With strings and numbers the left type typically remains. Except for # `int() % float()`. return ContextSet(left) - elif operator in COMPARISON_OPERATORS: + elif str_operator in COMPARISON_OPERATORS: if is_compiled(left) and is_compiled(right): # Possible, because the return is not an option. Just compare. try: - return ContextSet(left.execute_operation(right, operator)) + return ContextSet(left.execute_operation(right, str_operator)) except TypeError: # Could be True or False. pass else: - if operator in ('is', '!=', '==', 'is not'): - operation = COMPARISON_OPERATORS[operator] + if str_operator in ('is', '!=', '==', 'is not'): + operation = COMPARISON_OPERATORS[str_operator] bool_ = operation(left, right) return ContextSet(_bool_to_context(evaluator, bool_)) return ContextSet(_bool_to_context(evaluator, True), _bool_to_context(evaluator, False)) - elif operator == 'in': + elif str_operator == 'in': return NO_CONTEXTS def check(obj): @@ -409,7 +411,7 @@ def _eval_comparison_part(evaluator, context, left, operator, right): obj.name.string_name in ('int', 'float') # Static analysis, one is a number, the other one is not. - if operator in ('+', '-') and l_is_num != r_is_num \ + if str_operator in ('+', '-') and l_is_num != r_is_num \ and not (check(left) or check(right)): message = "TypeError: unsupported operand type(s) for +: %s and %s" analysis.add(context, 'type-error-operation', operator,