forked from VimPlug/jedi
This removes the _infer_type_vars util in favour of a polymorphic implementation, removing the conditional checks on the type of the annotation instance. While for the moment this creates some circular imports, further refactoring to follow should be able to remove those.
114 lines
3.7 KiB
Python
114 lines
3.7 KiB
Python
class BaseValue(object):
|
|
def __init__(self, inference_state, parent_context=None):
|
|
self.inference_state = inference_state
|
|
self.parent_context = parent_context
|
|
|
|
def get_root_context(self):
|
|
value = self
|
|
while True:
|
|
if value.parent_context is None:
|
|
return value
|
|
value = value.parent_context
|
|
|
|
def infer_type_vars(self, value_set, is_class_value=False):
|
|
"""
|
|
When the current instance represents a type annotation, this method
|
|
tries to find information about undefined type vars and returns a dict
|
|
from type var name to value set.
|
|
|
|
This is for example important to understand what `iter([1])` returns.
|
|
According to typeshed, `iter` returns an `Iterator[_T]`:
|
|
|
|
def iter(iterable: Iterable[_T]) -> Iterator[_T]: ...
|
|
|
|
This functions would generate `int` for `_T` in this case, because it
|
|
unpacks the `Iterable`.
|
|
|
|
Parameters
|
|
----------
|
|
|
|
`self`: represents the annotation of the current parameter to infer the
|
|
value for. In the above example, this would initially be the
|
|
`Iterable[_T]` of the `iterable` parameter and then, when recursing,
|
|
just the `_T` generic parameter.
|
|
|
|
`value_set`: represents the actual argument passed to the parameter
|
|
we're inferrined for, or (for recursive calls) their types. In the
|
|
above example this would first be the representation of the list
|
|
`[1]` and then, when recursing, just of `1`.
|
|
|
|
`is_class_value`: tells us whether or not to treat the `value_set` as
|
|
representing the instances or types being passed, which is neccesary
|
|
to correctly cope with `Type[T]` annotations. When it is True, this
|
|
means that we are being called with a nested portion of an
|
|
annotation and that the `value_set` represents the types of the
|
|
arguments, rather than their actual instances. Note: not all
|
|
recursive calls will neccesarily set this to True.
|
|
"""
|
|
return {}
|
|
|
|
|
|
class BaseValueSet(object):
|
|
def __init__(self, iterable):
|
|
self._set = frozenset(iterable)
|
|
for value in iterable:
|
|
assert not isinstance(value, BaseValueSet)
|
|
|
|
@classmethod
|
|
def _from_frozen_set(cls, frozenset_):
|
|
self = cls.__new__(cls)
|
|
self._set = frozenset_
|
|
return self
|
|
|
|
@classmethod
|
|
def from_sets(cls, sets):
|
|
"""
|
|
Used to work with an iterable of set.
|
|
"""
|
|
aggregated = set()
|
|
for set_ in sets:
|
|
if isinstance(set_, BaseValueSet):
|
|
aggregated |= set_._set
|
|
else:
|
|
aggregated |= frozenset(set_)
|
|
return cls._from_frozen_set(frozenset(aggregated))
|
|
|
|
def __or__(self, other):
|
|
return self._from_frozen_set(self._set | other._set)
|
|
|
|
def __and__(self, other):
|
|
return self._from_frozen_set(self._set & other._set)
|
|
|
|
def __iter__(self):
|
|
for element in self._set:
|
|
yield element
|
|
|
|
def __bool__(self):
|
|
return bool(self._set)
|
|
|
|
def __len__(self):
|
|
return len(self._set)
|
|
|
|
def __repr__(self):
|
|
return 'S{%s}' % (', '.join(str(s) for s in self._set))
|
|
|
|
def filter(self, filter_func):
|
|
return self.__class__(filter(filter_func, self._set))
|
|
|
|
def __getattr__(self, name):
|
|
def mapper(*args, **kwargs):
|
|
return self.from_sets(
|
|
getattr(value, name)(*args, **kwargs)
|
|
for value in self._set
|
|
)
|
|
return mapper
|
|
|
|
def __eq__(self, other):
|
|
return self._set == other._set
|
|
|
|
def __ne__(self, other):
|
|
return not self.__eq__(other)
|
|
|
|
def __hash__(self):
|
|
return hash(self._set)
|