]>
crepu.dev Git - config.git/blob - djavu-asus/emacs/elpy/rpc-venv/lib/python3.11/site-packages/jedi/parser_utils.py
3 from ast
import literal_eval
4 from inspect
import cleandoc
5 from weakref
import WeakKeyDictionary
7 from parso
.python
import tree
8 from parso
.cache
import parser_cache
9 from parso
import split_lines
11 _EXECUTE_NODES
= {'funcdef', 'classdef', 'import_from', 'import_name', 'test',
12 'or_test', 'and_test', 'not_test', 'comparison', 'expr',
13 'xor_expr', 'and_expr', 'shift_expr', 'arith_expr',
14 'atom_expr', 'term', 'factor', 'power', 'atom'}
17 'try', 'except', 'finally', 'else', 'if', 'elif', 'with', 'for', 'while'
21 def get_executable_nodes(node
, last_added
=False):
28 next_leaf
= node
.get_next_leaf()
29 if last_added
is False and node
.parent
.type != 'param' and next_leaf
!= '=':
31 elif typ
== 'expr_stmt':
32 # I think inferring the statement (and possibly returned arrays),
33 # should be enough for static analysis.
35 for child
in node
.children
:
36 result
+= get_executable_nodes(child
, last_added
=True)
37 elif typ
== 'decorator':
39 if node
.children
[-2] == ')':
40 node
= node
.children
[-3]
42 result
+= get_executable_nodes(node
)
45 children
= node
.children
46 except AttributeError:
49 if node
.type in _EXECUTE_NODES
and not last_added
:
52 for child
in children
:
53 result
+= get_executable_nodes(child
, last_added
)
58 def get_sync_comp_fors(comp_for
):
60 last
= comp_for
.children
[-1]
62 if last
.type == 'comp_for':
63 yield last
.children
[1] # Ignore the async.
64 elif last
.type == 'sync_comp_for':
66 elif not last
.type == 'comp_if':
68 last
= last
.children
[-1]
71 def for_stmt_defines_one_name(for_stmt
):
73 Returns True if only one name is returned: ``for x in y``.
74 Returns False if the for loop is more complicated: ``for x, z in y``.
78 return for_stmt
.children
[1].type == 'name'
81 def get_flow_branch_keyword(flow_node
, node
):
82 start_pos
= node
.start_pos
83 if not (flow_node
.start_pos
< start_pos
<= flow_node
.end_pos
):
84 raise ValueError('The node is not part of the flow.')
87 for i
, child
in enumerate(flow_node
.children
):
88 if start_pos
< child
.start_pos
:
90 first_leaf
= child
.get_first_leaf()
91 if first_leaf
in _FLOW_KEYWORDS
:
96 def clean_scope_docstring(scope_node
):
97 """ Returns a cleaned version of the docstring token. """
98 node
= scope_node
.get_doc_node()
100 # TODO We have to check next leaves until there are no new
101 # leaves anymore that might be part of the docstring. A
102 # docstring can also look like this: ``'foo' 'bar'
103 # Returns a literal cleaned version of the ``Token``.
104 return cleandoc(safe_literal_eval(node
.value
))
108 def find_statement_documentation(tree_node
):
109 if tree_node
.type == 'expr_stmt':
110 tree_node
= tree_node
.parent
# simple_stmt
111 maybe_string
= tree_node
.get_next_sibling()
112 if maybe_string
is not None:
113 if maybe_string
.type == 'simple_stmt':
114 maybe_string
= maybe_string
.children
[0]
115 if maybe_string
.type == 'string':
116 return cleandoc(safe_literal_eval(maybe_string
.value
))
120 def safe_literal_eval(value
):
121 first_two
= value
[:2].lower()
122 if first_two
[0] == 'f' or first_two
in ('fr', 'rf'):
123 # literal_eval is not able to resovle f literals. We have to do that
124 # manually, but that's right now not implemented.
127 return literal_eval(value
)
130 def get_signature(funcdef
, width
=72, call_string
=None,
131 omit_first_param
=False, omit_return_annotation
=False):
133 Generate a string signature of a function.
135 :param width: Fold lines if a line is longer than this value.
137 :arg func_name: Override function name when given.
142 # Lambdas have no name.
143 if call_string
is None:
144 if funcdef
.type == 'lambdef':
145 call_string
= '<lambda>'
147 call_string
= funcdef
.name
.value
148 params
= funcdef
.get_params()
151 p
= '(' + ''.join(param
.get_code() for param
in params
).strip() + ')'
152 # TODO this is pretty bad, we should probably just normalize.
153 p
= re
.sub(r
'\s+', ' ', p
)
154 if funcdef
.annotation
and not omit_return_annotation
:
155 rtype
= " ->" + funcdef
.annotation
.get_code()
158 code
= call_string
+ p
+ rtype
160 return '\n'.join(textwrap
.wrap(code
, width
))
163 def move(node
, line_offset
):
165 Move the `Node` start_pos.
168 children
= node
.children
169 except AttributeError:
170 node
.line
+= line_offset
176 def get_following_comment_same_line(node
):
178 returns (as string) any comment that appears on the same line,
179 after the node, including the #
182 if node
.type == 'for_stmt':
183 whitespace
= node
.children
[5].get_first_leaf().prefix
184 elif node
.type == 'with_stmt':
185 whitespace
= node
.children
[3].get_first_leaf().prefix
186 elif node
.type == 'funcdef':
187 # actually on the next line
188 whitespace
= node
.children
[4].get_first_leaf().get_next_leaf().prefix
190 whitespace
= node
.get_last_leaf().get_next_leaf().prefix
191 except AttributeError:
194 # TODO in some particular cases, the tree doesn't seem to be linked
197 if "#" not in whitespace
:
199 comment
= whitespace
[whitespace
.index("#"):]
201 comment
= comment
[:comment
.index("\r")]
203 comment
= comment
[:comment
.index("\n")]
210 # Starting with Python 3.8, async is outside of the statement.
211 return node
.children
[1].type != 'sync_comp_for'
213 return t
in ('file_input', 'classdef', 'funcdef', 'lambdef', 'sync_comp_for')
216 def _get_parent_scope_cache(func
):
217 cache
= WeakKeyDictionary()
219 def wrapper(parso_cache_node
, node
, include_flows
=False):
220 if parso_cache_node
is None:
221 return func(node
, include_flows
)
224 for_module
= cache
[parso_cache_node
]
226 for_module
= cache
[parso_cache_node
] = {}
229 return for_module
[node
]
231 result
= for_module
[node
] = func(node
, include_flows
)
236 def get_parent_scope(node
, include_flows
=False):
238 Returns the underlying scope.
242 return None # It's a module already.
246 if scope
.type in ('classdef', 'funcdef', 'lambdef'):
247 index
= scope
.children
.index(':')
248 if scope
.children
[index
].start_pos
>= node
.start_pos
:
249 if node
.parent
.type == 'param' and node
.parent
.name
== node
:
251 elif node
.parent
.type == 'tfpdef' and node
.parent
.children
[0] == node
:
257 elif include_flows
and isinstance(scope
, tree
.Flow
):
258 # The cursor might be on `if foo`, so the parent scope will not be
259 # the if, but the parent of the if.
260 if not (scope
.type == 'if_stmt'
261 and any(n
.start_pos
<= node
.start_pos
< n
.end_pos
262 for n
in scope
.get_test_nodes())):
268 get_cached_parent_scope
= _get_parent_scope_cache(get_parent_scope
)
271 def get_cached_code_lines(grammar
, path
):
273 Basically access the cached code lines in parso. This is not the nicest way
274 to do this, but we avoid splitting all the lines again.
276 return get_parso_cache_node(grammar
, path
).lines
279 def get_parso_cache_node(grammar
, path
):
281 This is of course not public. But as long as I control parso, this
282 shouldn't be a problem. ~ Dave
284 The reason for this is mostly caching. This is obviously also a sign of a
285 broken caching architecture.
287 return parser_cache
[grammar
._hashed
][path
]
290 def cut_value_at_position(leaf
, position
):
292 Cuts of the value of the leaf at position
294 lines
= split_lines(leaf
.value
, keepends
=True)[:position
[0] - leaf
.line
+ 1]
296 if leaf
.line
== position
[0]:
297 column
-= leaf
.column
300 lines
[-1] = lines
[-1][:column
]
301 return ''.join(lines
)
304 def expr_is_dotted(node
):
306 Checks if a path looks like `name` or `name.foo.bar` and not `name()`.
308 if node
.type == 'atom':
309 if len(node
.children
) == 3 and node
.children
[0] == '(':
310 return expr_is_dotted(node
.children
[1])
312 if node
.type == 'atom_expr':
313 children
= node
.children
314 if children
[0] == 'await':
316 if not expr_is_dotted(children
[0]):
319 return all(c
.children
[0] == '.' for c
in children
[1:])
320 return node
.type == 'name'
323 def _function_is_x_method(*method_names
):
324 def wrapper(function_node
):
326 This is a heuristic. It will not hold ALL the times, but it will be
327 correct pretty much for anyone that doesn't try to beat it.
328 staticmethod/classmethod are builtins and unless overwritten, this will
331 for decorator
in function_node
.get_decorators():
332 dotted_name
= decorator
.children
[1]
333 if dotted_name
.get_code() in method_names
:
339 function_is_staticmethod
= _function_is_x_method('staticmethod')
340 function_is_classmethod
= _function_is_x_method('classmethod')
341 function_is_property
= _function_is_x_method('property', 'cached_property')