|
""" |
|
There are a couple of classes documented in here: |
|
|
|
- :class:`.BaseName` as an abstact base class for almost everything. |
|
- :class:`.Name` used in a lot of places |
|
- :class:`.Completion` for completions |
|
- :class:`.BaseSignature` as a base class for signatures |
|
- :class:`.Signature` for :meth:`.Script.get_signatures` only |
|
- :class:`.ParamName` used for parameters of signatures |
|
- :class:`.Refactoring` for refactorings |
|
- :class:`.SyntaxError` for :meth:`.Script.get_syntax_errors` only |
|
|
|
These classes are the much biggest part of the API, because they contain |
|
the interesting information about all operations. |
|
""" |
|
import re |
|
from pathlib import Path |
|
from typing import Optional |
|
|
|
from parso.tree import search_ancestor |
|
|
|
from jedi import settings |
|
from jedi import debug |
|
from jedi.inference.utils import unite |
|
from jedi.cache import memoize_method |
|
from jedi.inference.compiled.mixed import MixedName |
|
from jedi.inference.names import ImportName, SubModuleName |
|
from jedi.inference.gradual.stub_value import StubModuleValue |
|
from jedi.inference.gradual.conversion import convert_names, convert_values |
|
from jedi.inference.base_value import ValueSet, HasNoContext |
|
from jedi.api.keywords import KeywordName |
|
from jedi.api import completion_cache |
|
from jedi.api.helpers import filter_follow_imports |
|
|
|
|
|
def _sort_names_by_start_pos(names): |
|
return sorted(names, key=lambda s: s.start_pos or (0, 0)) |
|
|
|
|
|
def defined_names(inference_state, value): |
|
""" |
|
List sub-definitions (e.g., methods in class). |
|
|
|
:type scope: Scope |
|
:rtype: list of Name |
|
""" |
|
try: |
|
context = value.as_context() |
|
except HasNoContext: |
|
return [] |
|
filter = next(context.get_filters()) |
|
names = [name for name in filter.values()] |
|
return [Name(inference_state, n) for n in _sort_names_by_start_pos(names)] |
|
|
|
|
|
def _values_to_definitions(values): |
|
return [Name(c.inference_state, c.name) for c in values] |
|
|
|
|
|
class BaseName: |
|
""" |
|
The base class for all definitions, completions and signatures. |
|
""" |
|
_mapping = { |
|
'posixpath': 'os.path', |
|
'riscospath': 'os.path', |
|
'ntpath': 'os.path', |
|
'os2emxpath': 'os.path', |
|
'macpath': 'os.path', |
|
'genericpath': 'os.path', |
|
'posix': 'os', |
|
'_io': 'io', |
|
'_functools': 'functools', |
|
'_collections': 'collections', |
|
'_socket': 'socket', |
|
'_sqlite3': 'sqlite3', |
|
} |
|
|
|
_tuple_mapping = dict((tuple(k.split('.')), v) for (k, v) in { |
|
'argparse._ActionsContainer': 'argparse.ArgumentParser', |
|
}.items()) |
|
|
|
def __init__(self, inference_state, name): |
|
self._inference_state = inference_state |
|
self._name = name |
|
""" |
|
An instance of :class:`parso.python.tree.Name` subclass. |
|
""" |
|
self.is_keyword = isinstance(self._name, KeywordName) |
|
|
|
@memoize_method |
|
def _get_module_context(self): |
|
|
|
|
|
|
|
return self._name.get_root_context() |
|
|
|
@property |
|
def module_path(self) -> Optional[Path]: |
|
""" |
|
Shows the file path of a module. e.g. ``/usr/lib/python3.9/os.py`` |
|
""" |
|
module = self._get_module_context() |
|
if module.is_stub() or not module.is_compiled(): |
|
|
|
|
|
path: Optional[Path] = self._get_module_context().py__file__() |
|
return path |
|
|
|
return None |
|
|
|
@property |
|
def name(self): |
|
""" |
|
Name of variable/function/class/module. |
|
|
|
For example, for ``x = None`` it returns ``'x'``. |
|
|
|
:rtype: str or None |
|
""" |
|
return self._name.get_public_name() |
|
|
|
@property |
|
def type(self): |
|
""" |
|
The type of the definition. |
|
|
|
Here is an example of the value of this attribute. Let's consider |
|
the following source. As what is in ``variable`` is unambiguous |
|
to Jedi, :meth:`jedi.Script.infer` should return a list of |
|
definition for ``sys``, ``f``, ``C`` and ``x``. |
|
|
|
>>> from jedi import Script |
|
>>> source = ''' |
|
... import keyword |
|
... |
|
... class C: |
|
... pass |
|
... |
|
... class D: |
|
... pass |
|
... |
|
... x = D() |
|
... |
|
... def f(): |
|
... pass |
|
... |
|
... for variable in [keyword, f, C, x]: |
|
... variable''' |
|
|
|
>>> script = Script(source) |
|
>>> defs = script.infer() |
|
|
|
Before showing what is in ``defs``, let's sort it by :attr:`line` |
|
so that it is easy to relate the result to the source code. |
|
|
|
>>> defs = sorted(defs, key=lambda d: d.line) |
|
>>> print(defs) # doctest: +NORMALIZE_WHITESPACE |
|
[<Name full_name='keyword', description='module keyword'>, |
|
<Name full_name='__main__.C', description='class C'>, |
|
<Name full_name='__main__.D', description='instance D'>, |
|
<Name full_name='__main__.f', description='def f'>] |
|
|
|
Finally, here is what you can get from :attr:`type`: |
|
|
|
>>> defs = [d.type for d in defs] |
|
>>> defs[0] |
|
'module' |
|
>>> defs[1] |
|
'class' |
|
>>> defs[2] |
|
'instance' |
|
>>> defs[3] |
|
'function' |
|
|
|
Valid values for type are ``module``, ``class``, ``instance``, ``function``, |
|
``param``, ``path``, ``keyword``, ``property`` and ``statement``. |
|
|
|
""" |
|
tree_name = self._name.tree_name |
|
resolve = False |
|
if tree_name is not None: |
|
|
|
definition = tree_name.get_definition() |
|
if definition is not None and definition.type == 'import_from' and \ |
|
tree_name.is_definition(): |
|
resolve = True |
|
|
|
if isinstance(self._name, SubModuleName) or resolve: |
|
for value in self._name.infer(): |
|
return value.api_type |
|
return self._name.api_type |
|
|
|
@property |
|
def module_name(self): |
|
""" |
|
The module name, a bit similar to what ``__name__`` is in a random |
|
Python module. |
|
|
|
>>> from jedi import Script |
|
>>> source = 'import json' |
|
>>> script = Script(source, path='example.py') |
|
>>> d = script.infer()[0] |
|
>>> print(d.module_name) # doctest: +ELLIPSIS |
|
json |
|
""" |
|
return self._get_module_context().py__name__() |
|
|
|
def in_builtin_module(self): |
|
""" |
|
Returns True, if this is a builtin module. |
|
""" |
|
value = self._get_module_context().get_value() |
|
if isinstance(value, StubModuleValue): |
|
return any(v.is_compiled() for v in value.non_stub_value_set) |
|
return value.is_compiled() |
|
|
|
@property |
|
def line(self): |
|
"""The line where the definition occurs (starting with 1).""" |
|
start_pos = self._name.start_pos |
|
if start_pos is None: |
|
return None |
|
return start_pos[0] |
|
|
|
@property |
|
def column(self): |
|
"""The column where the definition occurs (starting with 0).""" |
|
start_pos = self._name.start_pos |
|
if start_pos is None: |
|
return None |
|
return start_pos[1] |
|
|
|
def get_definition_start_position(self): |
|
""" |
|
The (row, column) of the start of the definition range. Rows start with |
|
1, columns start with 0. |
|
|
|
:rtype: Optional[Tuple[int, int]] |
|
""" |
|
if self._name.tree_name is None: |
|
return None |
|
definition = self._name.tree_name.get_definition() |
|
if definition is None: |
|
return self._name.start_pos |
|
return definition.start_pos |
|
|
|
def get_definition_end_position(self): |
|
""" |
|
The (row, column) of the end of the definition range. Rows start with |
|
1, columns start with 0. |
|
|
|
:rtype: Optional[Tuple[int, int]] |
|
""" |
|
if self._name.tree_name is None: |
|
return None |
|
definition = self._name.tree_name.get_definition() |
|
if definition is None: |
|
return self._name.tree_name.end_pos |
|
if self.type in ("function", "class"): |
|
last_leaf = definition.get_last_leaf() |
|
if last_leaf.type == "newline": |
|
return last_leaf.get_previous_leaf().end_pos |
|
return last_leaf.end_pos |
|
return definition.end_pos |
|
|
|
def docstring(self, raw=False, fast=True): |
|
r""" |
|
Return a document string for this completion object. |
|
|
|
Example: |
|
|
|
>>> from jedi import Script |
|
>>> source = '''\ |
|
... def f(a, b=1): |
|
... "Document for function f." |
|
... ''' |
|
>>> script = Script(source, path='example.py') |
|
>>> doc = script.infer(1, len('def f'))[0].docstring() |
|
>>> print(doc) |
|
f(a, b=1) |
|
<BLANKLINE> |
|
Document for function f. |
|
|
|
Notice that useful extra information is added to the actual |
|
docstring, e.g. function signatures are prepended to their docstrings. |
|
If you need the actual docstring, use ``raw=True`` instead. |
|
|
|
>>> print(script.infer(1, len('def f'))[0].docstring(raw=True)) |
|
Document for function f. |
|
|
|
:param fast: Don't follow imports that are only one level deep like |
|
``import foo``, but follow ``from foo import bar``. This makes |
|
sense for speed reasons. Completing `import a` is slow if you use |
|
the ``foo.docstring(fast=False)`` on every object, because it |
|
parses all libraries starting with ``a``. |
|
""" |
|
if isinstance(self._name, ImportName) and fast: |
|
return '' |
|
doc = self._get_docstring() |
|
if raw: |
|
return doc |
|
|
|
signature_text = self._get_docstring_signature() |
|
if signature_text and doc: |
|
return signature_text + '\n\n' + doc |
|
else: |
|
return signature_text + doc |
|
|
|
def _get_docstring(self): |
|
return self._name.py__doc__() |
|
|
|
def _get_docstring_signature(self): |
|
return '\n'.join( |
|
signature.to_string() |
|
for signature in self._get_signatures(for_docstring=True) |
|
) |
|
|
|
@property |
|
def description(self): |
|
""" |
|
A description of the :class:`.Name` object, which is heavily used |
|
in testing. e.g. for ``isinstance`` it returns ``def isinstance``. |
|
|
|
Example: |
|
|
|
>>> from jedi import Script |
|
>>> source = ''' |
|
... def f(): |
|
... pass |
|
... |
|
... class C: |
|
... pass |
|
... |
|
... variable = f if random.choice([0,1]) else C''' |
|
>>> script = Script(source) # line is maximum by default |
|
>>> defs = script.infer(column=3) |
|
>>> defs = sorted(defs, key=lambda d: d.line) |
|
>>> print(defs) # doctest: +NORMALIZE_WHITESPACE |
|
[<Name full_name='__main__.f', description='def f'>, |
|
<Name full_name='__main__.C', description='class C'>] |
|
>>> str(defs[0].description) |
|
'def f' |
|
>>> str(defs[1].description) |
|
'class C' |
|
|
|
""" |
|
typ = self.type |
|
tree_name = self._name.tree_name |
|
if typ == 'param': |
|
return typ + ' ' + self._name.to_string() |
|
if typ in ('function', 'class', 'module', 'instance') or tree_name is None: |
|
if typ == 'function': |
|
|
|
typ = 'def' |
|
return typ + ' ' + self._name.get_public_name() |
|
|
|
definition = tree_name.get_definition(include_setitem=True) or tree_name |
|
|
|
|
|
txt = definition.get_code(include_prefix=False) |
|
|
|
txt = re.sub(r'#[^\n]+\n', ' ', txt) |
|
|
|
txt = re.sub(r'\s+', ' ', txt).strip() |
|
return txt |
|
|
|
@property |
|
def full_name(self): |
|
""" |
|
Dot-separated path of this object. |
|
|
|
It is in the form of ``<module>[.<submodule>[...]][.<object>]``. |
|
It is useful when you want to look up Python manual of the |
|
object at hand. |
|
|
|
Example: |
|
|
|
>>> from jedi import Script |
|
>>> source = ''' |
|
... import os |
|
... os.path.join''' |
|
>>> script = Script(source, path='example.py') |
|
>>> print(script.infer(3, len('os.path.join'))[0].full_name) |
|
os.path.join |
|
|
|
Notice that it returns ``'os.path.join'`` instead of (for example) |
|
``'posixpath.join'``. This is not correct, since the modules name would |
|
be ``<module 'posixpath' ...>```. However most users find the latter |
|
more practical. |
|
""" |
|
if not self._name.is_value_name: |
|
return None |
|
|
|
names = self._name.get_qualified_names(include_module_names=True) |
|
if names is None: |
|
return None |
|
|
|
names = list(names) |
|
try: |
|
names[0] = self._mapping[names[0]] |
|
except KeyError: |
|
pass |
|
|
|
return '.'.join(names) |
|
|
|
def is_stub(self): |
|
""" |
|
Returns True if the current name is defined in a stub file. |
|
""" |
|
if not self._name.is_value_name: |
|
return False |
|
|
|
return self._name.get_root_context().is_stub() |
|
|
|
def is_side_effect(self): |
|
""" |
|
Checks if a name is defined as ``self.foo = 3``. In case of self, this |
|
function would return False, for foo it would return True. |
|
""" |
|
tree_name = self._name.tree_name |
|
if tree_name is None: |
|
return False |
|
return tree_name.is_definition() and tree_name.parent.type == 'trailer' |
|
|
|
@debug.increase_indent_cm('goto on name') |
|
def goto(self, *, follow_imports=False, follow_builtin_imports=False, |
|
only_stubs=False, prefer_stubs=False): |
|
|
|
""" |
|
Like :meth:`.Script.goto` (also supports the same params), but does it |
|
for the current name. This is typically useful if you are using |
|
something like :meth:`.Script.get_names()`. |
|
|
|
:param follow_imports: The goto call will follow imports. |
|
:param follow_builtin_imports: If follow_imports is True will try to |
|
look up names in builtins (i.e. compiled or extension modules). |
|
:param only_stubs: Only return stubs for this goto call. |
|
:param prefer_stubs: Prefer stubs to Python objects for this goto call. |
|
:rtype: list of :class:`Name` |
|
""" |
|
if not self._name.is_value_name: |
|
return [] |
|
|
|
names = self._name.goto() |
|
if follow_imports: |
|
names = filter_follow_imports(names, follow_builtin_imports) |
|
names = convert_names( |
|
names, |
|
only_stubs=only_stubs, |
|
prefer_stubs=prefer_stubs, |
|
) |
|
return [self if n == self._name else Name(self._inference_state, n) |
|
for n in names] |
|
|
|
@debug.increase_indent_cm('infer on name') |
|
def infer(self, *, only_stubs=False, prefer_stubs=False): |
|
""" |
|
Like :meth:`.Script.infer`, it can be useful to understand which type |
|
the current name has. |
|
|
|
Return the actual definitions. I strongly recommend not using it for |
|
your completions, because it might slow down |jedi|. If you want to |
|
read only a few objects (<=20), it might be useful, especially to get |
|
the original docstrings. The basic problem of this function is that it |
|
follows all results. This means with 1000 completions (e.g. numpy), |
|
it's just very, very slow. |
|
|
|
:param only_stubs: Only return stubs for this goto call. |
|
:param prefer_stubs: Prefer stubs to Python objects for this type |
|
inference call. |
|
:rtype: list of :class:`Name` |
|
""" |
|
assert not (only_stubs and prefer_stubs) |
|
|
|
if not self._name.is_value_name: |
|
return [] |
|
|
|
|
|
|
|
|
|
names = convert_names([self._name], prefer_stubs=True) |
|
values = convert_values( |
|
ValueSet.from_sets(n.infer() for n in names), |
|
only_stubs=only_stubs, |
|
prefer_stubs=prefer_stubs, |
|
) |
|
resulting_names = [c.name for c in values] |
|
return [self if n == self._name else Name(self._inference_state, n) |
|
for n in resulting_names] |
|
|
|
def parent(self): |
|
""" |
|
Returns the parent scope of this identifier. |
|
|
|
:rtype: Name |
|
""" |
|
if not self._name.is_value_name: |
|
return None |
|
|
|
if self.type in ('function', 'class', 'param') and self._name.tree_name is not None: |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
cls_or_func_node = self._name.tree_name.get_definition() |
|
parent = search_ancestor(cls_or_func_node, 'funcdef', 'classdef', 'file_input') |
|
context = self._get_module_context().create_value(parent).as_context() |
|
else: |
|
context = self._name.parent_context |
|
|
|
if context is None: |
|
return None |
|
while context.name is None: |
|
|
|
context = context.parent_context |
|
|
|
return Name(self._inference_state, context.name) |
|
|
|
def __repr__(self): |
|
return "<%s %sname=%r, description=%r>" % ( |
|
self.__class__.__name__, |
|
'full_' if self.full_name else '', |
|
self.full_name or self.name, |
|
self.description, |
|
) |
|
|
|
def get_line_code(self, before=0, after=0): |
|
""" |
|
Returns the line of code where this object was defined. |
|
|
|
:param before: Add n lines before the current line to the output. |
|
:param after: Add n lines after the current line to the output. |
|
|
|
:return str: Returns the line(s) of code or an empty string if it's a |
|
builtin. |
|
""" |
|
if not self._name.is_value_name: |
|
return '' |
|
|
|
lines = self._name.get_root_context().code_lines |
|
if lines is None: |
|
|
|
return '' |
|
|
|
index = self._name.start_pos[0] - 1 |
|
start_index = max(index - before, 0) |
|
return ''.join(lines[start_index:index + after + 1]) |
|
|
|
def _get_signatures(self, for_docstring=False): |
|
if self._name.api_type == 'property': |
|
return [] |
|
if for_docstring and self._name.api_type == 'statement' and not self.is_stub(): |
|
|
|
|
|
return [] |
|
|
|
if isinstance(self._name, MixedName): |
|
|
|
|
|
|
|
return self._name.infer_compiled_value().get_signatures() |
|
|
|
names = convert_names([self._name], prefer_stubs=True) |
|
return [sig for name in names for sig in name.infer().get_signatures()] |
|
|
|
def get_signatures(self): |
|
""" |
|
Returns all potential signatures for a function or a class. Multiple |
|
signatures are typical if you use Python stubs with ``@overload``. |
|
|
|
:rtype: list of :class:`BaseSignature` |
|
""" |
|
return [ |
|
BaseSignature(self._inference_state, s) |
|
for s in self._get_signatures() |
|
] |
|
|
|
def execute(self): |
|
""" |
|
Uses type inference to "execute" this identifier and returns the |
|
executed objects. |
|
|
|
:rtype: list of :class:`Name` |
|
""" |
|
return _values_to_definitions(self._name.infer().execute_with_values()) |
|
|
|
def get_type_hint(self): |
|
""" |
|
Returns type hints like ``Iterable[int]`` or ``Union[int, str]``. |
|
|
|
This method might be quite slow, especially for functions. The problem |
|
is finding executions for those functions to return something like |
|
``Callable[[int, str], str]``. |
|
|
|
:rtype: str |
|
""" |
|
return self._name.infer().get_type_hint() |
|
|
|
|
|
class Completion(BaseName): |
|
""" |
|
``Completion`` objects are returned from :meth:`.Script.complete`. They |
|
provide additional information about a completion. |
|
""" |
|
def __init__(self, inference_state, name, stack, like_name_length, |
|
is_fuzzy, cached_name=None): |
|
super().__init__(inference_state, name) |
|
|
|
self._like_name_length = like_name_length |
|
self._stack = stack |
|
self._is_fuzzy = is_fuzzy |
|
self._cached_name = cached_name |
|
|
|
|
|
|
|
self._same_name_completions = [] |
|
|
|
def _complete(self, like_name): |
|
append = '' |
|
if settings.add_bracket_after_function \ |
|
and self.type == 'function': |
|
append = '(' |
|
|
|
name = self._name.get_public_name() |
|
if like_name: |
|
name = name[self._like_name_length:] |
|
return name + append |
|
|
|
@property |
|
def complete(self): |
|
""" |
|
Only works with non-fuzzy completions. Returns None if fuzzy |
|
completions are used. |
|
|
|
Return the rest of the word, e.g. completing ``isinstance``:: |
|
|
|
isinstan# <-- Cursor is here |
|
|
|
would return the string 'ce'. It also adds additional stuff, depending |
|
on your ``settings.py``. |
|
|
|
Assuming the following function definition:: |
|
|
|
def foo(param=0): |
|
pass |
|
|
|
completing ``foo(par`` would give a ``Completion`` which ``complete`` |
|
would be ``am=``. |
|
""" |
|
if self._is_fuzzy: |
|
return None |
|
return self._complete(True) |
|
|
|
@property |
|
def name_with_symbols(self): |
|
""" |
|
Similar to :attr:`.name`, but like :attr:`.name` returns also the |
|
symbols, for example assuming the following function definition:: |
|
|
|
def foo(param=0): |
|
pass |
|
|
|
completing ``foo(`` would give a ``Completion`` which |
|
``name_with_symbols`` would be "param=". |
|
|
|
""" |
|
return self._complete(False) |
|
|
|
def docstring(self, raw=False, fast=True): |
|
""" |
|
Documented under :meth:`BaseName.docstring`. |
|
""" |
|
if self._like_name_length >= 3: |
|
|
|
|
|
fast = False |
|
|
|
return super().docstring(raw=raw, fast=fast) |
|
|
|
def _get_docstring(self): |
|
if self._cached_name is not None: |
|
return completion_cache.get_docstring( |
|
self._cached_name, |
|
self._name.get_public_name(), |
|
lambda: self._get_cache() |
|
) |
|
return super()._get_docstring() |
|
|
|
def _get_docstring_signature(self): |
|
if self._cached_name is not None: |
|
return completion_cache.get_docstring_signature( |
|
self._cached_name, |
|
self._name.get_public_name(), |
|
lambda: self._get_cache() |
|
) |
|
return super()._get_docstring_signature() |
|
|
|
def _get_cache(self): |
|
return ( |
|
super().type, |
|
super()._get_docstring_signature(), |
|
super()._get_docstring(), |
|
) |
|
|
|
@property |
|
def type(self): |
|
""" |
|
Documented under :meth:`BaseName.type`. |
|
""" |
|
|
|
if self._cached_name is not None: |
|
return completion_cache.get_type( |
|
self._cached_name, |
|
self._name.get_public_name(), |
|
lambda: self._get_cache() |
|
) |
|
|
|
return super().type |
|
|
|
def get_completion_prefix_length(self): |
|
""" |
|
Returns the length of the prefix being completed. |
|
For example, completing ``isinstance``:: |
|
|
|
isinstan# <-- Cursor is here |
|
|
|
would return 8, because len('isinstan') == 8. |
|
|
|
Assuming the following function definition:: |
|
|
|
def foo(param=0): |
|
pass |
|
|
|
completing ``foo(par`` would return 3. |
|
""" |
|
return self._like_name_length |
|
|
|
def __repr__(self): |
|
return '<%s: %s>' % (type(self).__name__, self._name.get_public_name()) |
|
|
|
|
|
class Name(BaseName): |
|
""" |
|
*Name* objects are returned from many different APIs including |
|
:meth:`.Script.goto` or :meth:`.Script.infer`. |
|
""" |
|
def __init__(self, inference_state, definition): |
|
super().__init__(inference_state, definition) |
|
|
|
@memoize_method |
|
def defined_names(self): |
|
""" |
|
List sub-definitions (e.g., methods in class). |
|
|
|
:rtype: list of :class:`Name` |
|
""" |
|
defs = self._name.infer() |
|
return sorted( |
|
unite(defined_names(self._inference_state, d) for d in defs), |
|
key=lambda s: s._name.start_pos or (0, 0) |
|
) |
|
|
|
def is_definition(self): |
|
""" |
|
Returns True, if defined as a name in a statement, function or class. |
|
Returns False, if it's a reference to such a definition. |
|
""" |
|
if self._name.tree_name is None: |
|
return True |
|
else: |
|
return self._name.tree_name.is_definition() |
|
|
|
def __eq__(self, other): |
|
return self._name.start_pos == other._name.start_pos \ |
|
and self.module_path == other.module_path \ |
|
and self.name == other.name \ |
|
and self._inference_state == other._inference_state |
|
|
|
def __ne__(self, other): |
|
return not self.__eq__(other) |
|
|
|
def __hash__(self): |
|
return hash((self._name.start_pos, self.module_path, self.name, self._inference_state)) |
|
|
|
|
|
class BaseSignature(Name): |
|
""" |
|
These signatures are returned by :meth:`BaseName.get_signatures` |
|
calls. |
|
""" |
|
def __init__(self, inference_state, signature): |
|
super().__init__(inference_state, signature.name) |
|
self._signature = signature |
|
|
|
@property |
|
def params(self): |
|
""" |
|
Returns definitions for all parameters that a signature defines. |
|
This includes stuff like ``*args`` and ``**kwargs``. |
|
|
|
:rtype: list of :class:`.ParamName` |
|
""" |
|
return [ParamName(self._inference_state, n) |
|
for n in self._signature.get_param_names(resolve_stars=True)] |
|
|
|
def to_string(self): |
|
""" |
|
Returns a text representation of the signature. This could for example |
|
look like ``foo(bar, baz: int, **kwargs)``. |
|
|
|
:rtype: str |
|
""" |
|
return self._signature.to_string() |
|
|
|
|
|
class Signature(BaseSignature): |
|
""" |
|
A full signature object is the return value of |
|
:meth:`.Script.get_signatures`. |
|
""" |
|
def __init__(self, inference_state, signature, call_details): |
|
super().__init__(inference_state, signature) |
|
self._call_details = call_details |
|
self._signature = signature |
|
|
|
@property |
|
def index(self): |
|
""" |
|
Returns the param index of the current cursor position. |
|
Returns None if the index cannot be found in the curent call. |
|
|
|
:rtype: int |
|
""" |
|
return self._call_details.calculate_index( |
|
self._signature.get_param_names(resolve_stars=True) |
|
) |
|
|
|
@property |
|
def bracket_start(self): |
|
""" |
|
Returns a line/column tuple of the bracket that is responsible for the |
|
last function call. The first line is 1 and the first column 0. |
|
|
|
:rtype: int, int |
|
""" |
|
return self._call_details.bracket_leaf.start_pos |
|
|
|
def __repr__(self): |
|
return '<%s: index=%r %s>' % ( |
|
type(self).__name__, |
|
self.index, |
|
self._signature.to_string(), |
|
) |
|
|
|
|
|
class ParamName(Name): |
|
def infer_default(self): |
|
""" |
|
Returns default values like the ``1`` of ``def foo(x=1):``. |
|
|
|
:rtype: list of :class:`.Name` |
|
""" |
|
return _values_to_definitions(self._name.infer_default()) |
|
|
|
def infer_annotation(self, **kwargs): |
|
""" |
|
:param execute_annotation: Default True; If False, values are not |
|
executed and classes are returned instead of instances. |
|
:rtype: list of :class:`.Name` |
|
""" |
|
return _values_to_definitions(self._name.infer_annotation(ignore_stars=True, **kwargs)) |
|
|
|
def to_string(self): |
|
""" |
|
Returns a simple representation of a param, like |
|
``f: Callable[..., Any]``. |
|
|
|
:rtype: str |
|
""" |
|
return self._name.to_string() |
|
|
|
@property |
|
def kind(self): |
|
""" |
|
Returns an enum instance of :mod:`inspect`'s ``Parameter`` enum. |
|
|
|
:rtype: :py:attr:`inspect.Parameter.kind` |
|
""" |
|
return self._name.get_kind() |
|
|