FazBrowse GitHub Viewer
|
Trending
|
URL:
|
Home
Tools:
[Download Repo ZIP]
[View Raw Code]
[Original HTTPS Page]
pythonVSCode/pythonFiles/release/jedi/api/__init__.py at codeHealth · sbialobok/pythonVSCode · GitHub
sbialobok
/
pythonVSCode
Public
forked from
DonJayamanne/pythonVSCode
Notifications
You must be signed in to change notification settings
Fork
0
Star
0
Code
Pull requests
0
Actions
Projects
Wiki
Security and quality
0
Insights
Additional navigation options
Code
Pull requests
Actions
Projects
Wiki
Security and quality
Insights
Expand file tree
Breadcrumbs
pythonVSCode
/
pythonFiles
/
release
/
jedi
/
api
/
__init__.py
Copy path
More file actions
More file actions
Latest commit
History
History
History
executable file
·
713 lines (602 loc) · 28.4 KB
Breadcrumbs
pythonVSCode
/
pythonFiles
/
release
/
jedi
/
api
/
__init__.py
Copy path
File metadata and controls
executable file
·
713 lines (602 loc) · 28.4 KB
Raw
Copy raw file
Download raw file
Open symbols panel
Edit and raw actions
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
"""
The API basically only provides one class. You can create a :class:`Script` and
use its methods.
Additionally you can add a debug function with :func:`set_debug_function`.
.. warning:: Please, note that Jedi is **not thread safe**.
"""
import
re
import
os
import
warnings
import
sys
from
itertools
import
chain
from
jedi
.
_compatibility
import
unicode
,
builtins
from
jedi
.
parser
import
Parser
,
load_grammar
from
jedi
.
parser
.
tokenize
import
source_tokens
from
jedi
.
parser
import
tree
from
jedi
.
parser
.
user_context
import
UserContext
,
UserContextParser
from
jedi
import
debug
from
jedi
import
settings
from
jedi
import
common
from
jedi
import
cache
from
jedi
.
api
import
keywords
from
jedi
.
api
import
classes
from
jedi
.
api
import
interpreter
from
jedi
.
api
import
usages
from
jedi
.
api
import
helpers
from
jedi
.
evaluate
import
Evaluator
from
jedi
.
evaluate
import
representation
as
er
from
jedi
.
evaluate
import
compiled
from
jedi
.
evaluate
import
imports
from
jedi
.
evaluate
.
cache
import
memoize_default
from
jedi
.
evaluate
.
helpers
import
FakeName
,
get_module_names
from
jedi
.
evaluate
.
finder
import
global_names_dict_generator
,
filter_definition_names
from
jedi
.
evaluate
import
analysis
# Jedi uses lots and lots of recursion. By setting this a little bit higher, we
# can remove some "maximum recursion depth" errors.
sys
.
setrecursionlimit
(
2000
)
class
NotFoundError
(
Exception
):
"""A custom error to avoid catching the wrong exceptions.
.. deprecated:: 0.9.0
Not in use anymore, Jedi just returns no goto result if you're not on a
valid name.
.. todo:: Remove!
"""
class
Script
(
object
):
"""
A Script is the base for completions, goto or whatever you want to do with
|jedi|.
You can either use the ``source`` parameter or ``path`` to read a file.
Usually you're going to want to use both of them (in an editor).
:param source: The source code of the current file, separated by newlines.
:type source: str
:param line: The line to perform actions on (starting with 1).
:type line: int
:param col: The column of the cursor (starting with 0).
:type col: int
:param path: The path of the file in the file system, or ``''`` if
it hasn't been saved yet.
:type path: str or None
:param encoding: The encoding of ``source``, if it is not a
``unicode`` object (default ``'utf-8'``).
:type encoding: str
:param source_encoding: The encoding of ``source``, if it is not a
``unicode`` object (default ``'utf-8'``).
:type encoding: str
"""
def
__init__
(
self
,
source
=
None
,
line
=
None
,
column
=
None
,
path
=
None
,
encoding
=
'utf-8'
,
source_path
=
None
,
source_encoding
=
None
):
if
source_path
is
not
None
:
warnings
.
warn
(
"Use path instead of source_path."
,
DeprecationWarning
)
path
=
source_path
if
source_encoding
is
not
None
:
warnings
.
warn
(
"Use encoding instead of source_encoding."
,
DeprecationWarning
)
encoding
=
source_encoding
self
.
_orig_path
=
path
self
.
path
=
None
if
path
is
None
else
os
.
path
.
abspath
(
path
)
if
source
is
None
:
try
:
with
open
(
path
)
as
f
:
source
=
f
.
read
()
except
UnicodeDecodeError
:
with
open
(
path
,
encoding
=
encoding
)
as
f
:
source
=
f
.
read
()
self
.
source
=
common
.
source_to_unicode
(
source
,
encoding
)
lines
=
common
.
splitlines
(
self
.
source
)
line
=
max
(
len
(
lines
),
1
)
if
line
is
None
else
line
if
not
(
0
<
line
<=
len
(
lines
)):
raise
ValueError
(
'`line` parameter is not in a valid range.'
)
line_len
=
len
(
lines
[
line
-
1
])
column
=
line_len
if
column
is
None
else
column
if
not
(
0
<=
column
<=
line_len
):
raise
ValueError
(
'`column` parameter is not in a valid range.'
)
self
.
_pos
=
line
,
column
cache
.
clear_time_caches
()
debug
.
reset_time
()
self
.
_grammar
=
load_grammar
(
'grammar%s.%s'
%
sys
.
version_info
[:
2
])
self
.
_user_context
=
UserContext
(
self
.
source
,
self
.
_pos
)
self
.
_parser
=
UserContextParser
(
self
.
_grammar
,
self
.
source
,
path
,
self
.
_pos
,
self
.
_user_context
,
self
.
_parsed_callback
)
self
.
_evaluator
=
Evaluator
(
self
.
_grammar
)
debug
.
speed
(
'init'
)
def
_parsed_callback
(
self
,
parser
):
module
=
self
.
_evaluator
.
wrap
(
parser
.
module
)
imports
.
add_module
(
self
.
_evaluator
,
unicode
(
module
.
name
),
module
)
@
property
def
source_path
(
self
):
"""
.. deprecated:: 0.7.0
Use :attr:`.path` instead.
.. todo:: Remove!
"""
warnings
.
warn
(
"Use path instead of source_path."
,
DeprecationWarning
)
return
self
.
path
def
__repr__
(
self
):
return
'<%s: %s>'
%
(
self
.
__class__
.
__name__
,
repr
(
self
.
_orig_path
))
def
completions
(
self
):
"""
Return :class:`classes.Completion` objects. Those objects contain
information about the completions, more than just names.
:return: Completion objects, sorted by name and __ comes last.
:rtype: list of :class:`classes.Completion`
"""
def
get_completions
(
user_stmt
,
bs
):
# TODO this closure is ugly. it also doesn't work with
# simple_complete (used for Interpreter), somehow redo.
module
=
self
.
_evaluator
.
wrap
(
self
.
_parser
.
module
())
names
,
level
,
only_modules
,
unfinished_dotted
=
\
helpers
.
check_error_statements
(
module
,
self
.
_pos
)
completion_names
=
[]
if
names
is
not
None
:
imp_names
=
tuple
(
str
(
n
)
for
n
in
names
if
n
.
end_pos
<
self
.
_pos
)
i
=
imports
.
Importer
(
self
.
_evaluator
,
imp_names
,
module
,
level
)
completion_names
=
i
.
completion_names
(
self
.
_evaluator
,
only_modules
)
# TODO this paragraph is necessary, but not sure it works.
context
=
self
.
_user_context
.
get_context
()
if
not
next
(
context
).
startswith
(
'.'
):
# skip the path
if
next
(
context
)
==
'from'
:
# completion is just "import" if before stands from ..
if
unfinished_dotted
:
return
completion_names
else
:
return
keywords
.
keyword_names
(
'import'
)
if
isinstance
(
user_stmt
,
tree
.
Import
):
module
=
self
.
_parser
.
module
()
completion_names
+=
imports
.
completion_names
(
self
.
_evaluator
,
user_stmt
,
self
.
_pos
)
return
completion_names
if
names
is
None
and
not
isinstance
(
user_stmt
,
tree
.
Import
):
if
not
path
and
not
dot
:
# add keywords
completion_names
+=
keywords
.
keyword_names
(
all
=
True
)
# TODO delete? We should search for valid parser
# transformations.
completion_names
+=
self
.
_simple_complete
(
path
,
dot
,
like
)
return
completion_names
debug
.
speed
(
'completions start'
)
path
=
self
.
_user_context
.
get_path_until_cursor
()
# Dots following an int are not the start of a completion but a float
# literal.
if
re
.
search
(
r'^\d\.$'
,
path
):
return
[]
path
,
dot
,
like
=
helpers
.
completion_parts
(
path
)
user_stmt
=
self
.
_parser
.
user_stmt_with_whitespace
()
b
=
compiled
.
builtin
completion_names
=
get_completions
(
user_stmt
,
b
)
if
not
dot
:
# add named params
for
call_sig
in
self
.
call_signatures
():
# Allow protected access, because it's a public API.
module
=
call_sig
.
_name
.
get_parent_until
()
# Compiled modules typically don't allow keyword arguments.
if
not
isinstance
(
module
,
compiled
.
CompiledObject
):
for
p
in
call_sig
.
params
:
# Allow access on _definition here, because it's a
# public API and we don't want to make the internal
# Name object public.
if
p
.
_definition
.
stars
==
0
:
# no *args/**kwargs
completion_names
.
append
(
p
.
_name
)
needs_dot
=
not
dot
and
path
comps
=
[]
comp_dct
=
{}
for
c
in
set
(
completion_names
):
n
=
str
(
c
)
if
settings
.
case_insensitive_completion
\
and
n
.
lower
().
startswith
(
like
.
lower
()) \
or
n
.
startswith
(
like
):
if
isinstance
(
c
.
parent
, (
tree
.
Function
,
tree
.
Class
)):
# TODO I think this is a hack. It should be an
# er.Function/er.Class before that.
c
=
self
.
_evaluator
.
wrap
(
c
.
parent
).
name
new
=
classes
.
Completion
(
self
.
_evaluator
,
c
,
needs_dot
,
len
(
like
))
k
=
(
new
.
name
,
new
.
complete
)
# key
if
k
in
comp_dct
and
settings
.
no_completion_duplicates
:
comp_dct
[
k
].
_same_name_completions
.
append
(
new
)
else
:
comp_dct
[
k
]
=
new
comps
.
append
(
new
)
debug
.
speed
(
'completions end'
)
return
sorted
(
comps
,
key
=
lambda
x
: (
x
.
name
.
startswith
(
'__'
),
x
.
name
.
startswith
(
'_'
),
x
.
name
.
lower
()))
def
_simple_complete
(
self
,
path
,
dot
,
like
):
if
not
path
and
not
dot
:
scope
=
self
.
_parser
.
user_scope
()
if
not
scope
.
is_scope
():
# Might be a flow (if/while/etc).
scope
=
scope
.
get_parent_scope
()
names_dicts
=
global_names_dict_generator
(
self
.
_evaluator
,
self
.
_evaluator
.
wrap
(
scope
),
self
.
_pos
)
completion_names
=
[]
for
names_dict
,
pos
in
names_dicts
:
names
=
list
(
chain
.
from_iterable
(
names_dict
.
values
()))
if
not
names
:
continue
completion_names
+=
filter_definition_names
(
names
,
self
.
_parser
.
user_stmt
(),
pos
)
elif
self
.
_get_under_cursor_stmt
(
path
)
is
None
:
return
[]
else
:
scopes
=
list
(
self
.
_prepare_goto
(
path
,
True
))
completion_names
=
[]
debug
.
dbg
(
'possible completion scopes: %s'
,
scopes
)
for
s
in
scopes
:
names
=
[]
for
names_dict
in
s
.
names_dicts
(
search_global
=
False
):
names
+=
chain
.
from_iterable
(
names_dict
.
values
())
completion_names
+=
filter_definition_names
(
names
,
self
.
_parser
.
user_stmt
())
return
completion_names
def
_prepare_goto
(
self
,
goto_path
,
is_completion
=
False
):
"""
Base for completions/goto. Basically it returns the resolved scopes
under cursor.
"""
debug
.
dbg
(
'start: %s in %s'
,
goto_path
,
self
.
_parser
.
user_scope
())
user_stmt
=
self
.
_parser
.
user_stmt_with_whitespace
()
if
not
user_stmt
and
len
(
goto_path
.
split
(
'
\n
'
))
>
1
:
# If the user_stmt is not defined and the goto_path is multi line,
# something's strange. Most probably the backwards tokenizer
# matched to much.
return
[]
if
isinstance
(
user_stmt
,
tree
.
Import
):
i
,
_
=
helpers
.
get_on_import_stmt
(
self
.
_evaluator
,
self
.
_user_context
,
user_stmt
,
is_completion
)
if
i
is
None
:
return
[]
scopes
=
[
i
]
else
:
# just parse one statement, take it and evaluate it
eval_stmt
=
self
.
_get_under_cursor_stmt
(
goto_path
)
if
eval_stmt
is
None
:
return
[]
module
=
self
.
_evaluator
.
wrap
(
self
.
_parser
.
module
())
names
,
level
,
_
,
_
=
helpers
.
check_error_statements
(
module
,
self
.
_pos
)
if
names
:
names
=
[
str
(
n
)
for
n
in
names
]
i
=
imports
.
Importer
(
self
.
_evaluator
,
names
,
module
,
level
)
return
i
.
follow
()
scopes
=
self
.
_evaluator
.
eval_element
(
eval_stmt
)
return
scopes
@
memoize_default
()
def
_get_under_cursor_stmt
(
self
,
cursor_txt
,
start_pos
=
None
):
tokenizer
=
source_tokens
(
cursor_txt
)
r
=
Parser
(
self
.
_grammar
,
cursor_txt
,
tokenizer
=
tokenizer
)
try
:
# Take the last statement available that is not an endmarker.
# And because it's a simple_stmt, we need to get the first child.
stmt
=
r
.
module
.
children
[
-
2
].
children
[
0
]
except
(
AttributeError
,
IndexError
):
return
None
user_stmt
=
self
.
_parser
.
user_stmt
()
if
user_stmt
is
None
:
# Set the start_pos to a pseudo position, that doesn't exist but
# works perfectly well (for both completions in docstrings and
# statements).
pos
=
start_pos
or
self
.
_pos
else
:
pos
=
user_stmt
.
start_pos
stmt
.
move
(
pos
[
0
]
-
1
,
pos
[
1
])
# Moving the offset.
stmt
.
parent
=
self
.
_parser
.
user_scope
()
return
stmt
def
goto_definitions
(
self
):
"""
Return the definitions of a the path under the cursor. goto function!
This follows complicated paths and returns the end, not the first
definition. The big difference between :meth:`goto_assignments` and
:meth:`goto_definitions` is that :meth:`goto_assignments` doesn't
follow imports and statements. Multiple objects may be returned,
because Python itself is a dynamic language, which means depending on
an option you can have two different versions of a function.
:rtype: list of :class:`classes.Definition`
"""
def
resolve_import_paths
(
scopes
):
for
s
in
scopes
.
copy
():
if
isinstance
(
s
,
imports
.
ImportWrapper
):
scopes
.
remove
(
s
)
scopes
.
update
(
resolve_import_paths
(
set
(
s
.
follow
())))
return
scopes
goto_path
=
self
.
_user_context
.
get_path_under_cursor
()
context
=
self
.
_user_context
.
get_context
()
definitions
=
set
()
if
next
(
context
)
in
(
'class'
,
'def'
):
definitions
=
set
([
self
.
_evaluator
.
wrap
(
self
.
_parser
.
user_scope
())])
else
:
# Fetch definition of callee, if there's no path otherwise.
if
not
goto_path
:
definitions
=
set
(
signature
.
_definition
for
signature
in
self
.
call_signatures
())
if
re
.
match
(
'\w[\w\d_]*$'
,
goto_path
)
and
not
definitions
:
user_stmt
=
self
.
_parser
.
user_stmt
()
if
user_stmt
is
not
None
and
user_stmt
.
type
==
'expr_stmt'
:
for
name
in
user_stmt
.
get_defined_names
():
if
name
.
start_pos
<=
self
.
_pos
<=
name
.
end_pos
:
# TODO scaning for a name and then using it should be
# the default.
definitions
=
set
(
self
.
_evaluator
.
goto_definition
(
name
))
if
not
definitions
and
goto_path
:
definitions
=
set
(
self
.
_prepare_goto
(
goto_path
))
definitions
=
resolve_import_paths
(
definitions
)
names
=
[
s
.
name
for
s
in
definitions
]
defs
=
[
classes
.
Definition
(
self
.
_evaluator
,
name
)
for
name
in
names
]
return
helpers
.
sorted_definitions
(
set
(
defs
))
def
goto_assignments
(
self
):
"""
Return the first definition found. Imports and statements aren't
followed. Multiple objects may be returned, because Python itself is a
dynamic language, which means depending on an option you can have two
different versions of a function.
:rtype: list of :class:`classes.Definition`
"""
results
=
self
.
_goto
()
d
=
[
classes
.
Definition
(
self
.
_evaluator
,
d
)
for
d
in
set
(
results
)]
return
helpers
.
sorted_definitions
(
d
)
def
_goto
(
self
,
add_import_name
=
False
):
"""
Used for goto_assignments and usages.
:param add_import_name: Add the the name (if import) to the result.
"""
def
follow_inexistent_imports
(
defs
):
""" Imports can be generated, e.g. following
`multiprocessing.dummy` generates an import dummy in the
multiprocessing module. The Import doesn't exist -> follow.
"""
definitions
=
set
(
defs
)
for
d
in
defs
:
if
isinstance
(
d
.
parent
,
tree
.
Import
) \
and
d
.
start_pos
==
(
0
,
0
):
i
=
imports
.
ImportWrapper
(
self
.
_evaluator
,
d
.
parent
).
follow
(
is_goto
=
True
)
definitions
.
remove
(
d
)
definitions
|=
follow_inexistent_imports
(
i
)
return
definitions
goto_path
=
self
.
_user_context
.
get_path_under_cursor
()
context
=
self
.
_user_context
.
get_context
()
user_stmt
=
self
.
_parser
.
user_stmt
()
user_scope
=
self
.
_parser
.
user_scope
()
stmt
=
self
.
_get_under_cursor_stmt
(
goto_path
)
if
stmt
is
None
:
return
[]
if
user_scope
is
None
:
last_name
=
None
else
:
# Try to use the parser if possible.
last_name
=
user_scope
.
name_for_position
(
self
.
_pos
)
if
last_name
is
None
:
last_name
=
stmt
while
not
isinstance
(
last_name
,
tree
.
Name
):
try
:
last_name
=
last_name
.
children
[
-
1
]
except
AttributeError
:
# Doesn't have a name in it.
return
[]
if
next
(
context
)
in
(
'class'
,
'def'
):
# The cursor is on a class/function name.
user_scope
=
self
.
_parser
.
user_scope
()
definitions
=
set
([
user_scope
.
name
])
elif
isinstance
(
user_stmt
,
tree
.
Import
):
s
,
name
=
helpers
.
get_on_import_stmt
(
self
.
_evaluator
,
self
.
_user_context
,
user_stmt
)
definitions
=
self
.
_evaluator
.
goto
(
name
)
else
:
# The Evaluator.goto function checks for definitions, but since we
# use a reverse tokenizer, we have new name_part objects, so we
# have to check the user_stmt here for positions.
if
isinstance
(
user_stmt
,
tree
.
ExprStmt
) \
and
isinstance
(
last_name
.
parent
,
tree
.
ExprStmt
):
for
name
in
user_stmt
.
get_defined_names
():
if
name
.
start_pos
<=
self
.
_pos
<=
name
.
end_pos
:
return
[
name
]
defs
=
self
.
_evaluator
.
goto
(
last_name
)
definitions
=
follow_inexistent_imports
(
defs
)
return
definitions
def
usages
(
self
,
additional_module_paths
=
()):
"""
Return :class:`classes.Definition` objects, which contain all
names that point to the definition of the name under the cursor. This
is very useful for refactoring (renaming), or to show all usages of a
variable.
.. todo:: Implement additional_module_paths
:rtype: list of :class:`classes.Definition`
"""
temp
,
settings
.
dynamic_flow_information
=
\
settings
.
dynamic_flow_information
,
False
try
:
user_stmt
=
self
.
_parser
.
user_stmt
()
definitions
=
self
.
_goto
(
add_import_name
=
True
)
if
not
definitions
and
isinstance
(
user_stmt
,
tree
.
Import
):
# For not defined imports (goto doesn't find something, we take
# the name as a definition. This is enough, because every name
# points to it.
name
=
user_stmt
.
name_for_position
(
self
.
_pos
)
if
name
is
None
:
# Must be syntax
return
[]
definitions
=
[
name
]
if
not
definitions
:
# Without a definition for a name we cannot find references.
return
[]
if
not
isinstance
(
user_stmt
,
tree
.
Import
):
# import case is looked at with add_import_name option
definitions
=
usages
.
usages_add_import_modules
(
self
.
_evaluator
,
definitions
)
module
=
set
([
d
.
get_parent_until
()
for
d
in
definitions
])
module
.
add
(
self
.
_parser
.
module
())
names
=
usages
.
usages
(
self
.
_evaluator
,
definitions
,
module
)
for
d
in
set
(
definitions
):
names
.
append
(
classes
.
Definition
(
self
.
_evaluator
,
d
))
finally
:
settings
.
dynamic_flow_information
=
temp
return
helpers
.
sorted_definitions
(
set
(
names
))
def
call_signatures
(
self
):
"""
Return the function object of the call you're currently in.
E.g. if the cursor is here::
abs(# <-- cursor is here
This would return the ``abs`` function. On the other hand::
abs()# <-- cursor is here
This would return ``None``.
:rtype: list of :class:`classes.CallSignature`
"""
call_txt
,
call_index
,
key_name
,
start_pos
=
self
.
_user_context
.
call_signature
()
if
call_txt
is
None
:
return
[]
stmt
=
self
.
_get_under_cursor_stmt
(
call_txt
,
start_pos
)
if
stmt
is
None
:
return
[]
with
common
.
scale_speed_settings
(
settings
.
scale_call_signatures
):
origins
=
cache
.
cache_call_signatures
(
self
.
_evaluator
,
stmt
,
self
.
source
,
self
.
_pos
)
debug
.
speed
(
'func_call followed'
)
return
[
classes
.
CallSignature
(
self
.
_evaluator
,
o
.
name
,
stmt
,
call_index
,
key_name
)
for
o
in
origins
if
hasattr
(
o
,
'py__call__'
)]
def
_analysis
(
self
):
def
check_types
(
types
):
for
typ
in
types
:
try
:
f
=
typ
.
iter_content
except
AttributeError
:
pass
else
:
check_types
(
f
())
#statements = set(chain(*self._parser.module().used_names.values()))
nodes
,
imp_names
,
decorated_funcs
=
\
analysis
.
get_module_statements
(
self
.
_parser
.
module
())
# Sort the statements so that the results are reproducible.
for
n
in
imp_names
:
imports
.
ImportWrapper
(
self
.
_evaluator
,
n
).
follow
()
for
node
in
sorted
(
nodes
,
key
=
lambda
obj
:
obj
.
start_pos
):
check_types
(
self
.
_evaluator
.
eval_element
(
node
))
for
dec_func
in
decorated_funcs
:
er
.
Function
(
self
.
_evaluator
,
dec_func
).
get_decorated_func
()
ana
=
[
a
for
a
in
self
.
_evaluator
.
analysis
if
self
.
path
==
a
.
path
]
return
sorted
(
set
(
ana
),
key
=
lambda
x
:
x
.
line
)
class
Interpreter
(
Script
):
"""
Jedi API for Python REPLs.
In addition to completion of simple attribute access, Jedi
supports code completion based on static code analysis.
Jedi can complete attributes of object which is not initialized
yet.
>>> from os.path import join
>>> namespace = locals()
>>> script = Interpreter('join().up', [namespace])
>>> print(script.completions()[0].name)
upper
"""
def
__init__
(
self
,
source
,
namespaces
,
**
kwds
):
"""
Parse `source` and mixin interpreted Python objects from `namespaces`.
:type source: str
:arg source: Code to parse.
:type namespaces: list of dict
:arg namespaces: a list of namespace dictionaries such as the one
returned by :func:`locals`.
Other optional arguments are same as the ones for :class:`Script`.
If `line` and `column` are None, they are assumed be at the end of
`source`.
"""
if
type
(
namespaces
)
is
not
list
or
len
(
namespaces
)
==
0
or
\
any
([
type
(
x
)
is
not
dict
for
x
in
namespaces
]):
raise
TypeError
(
"namespaces must be a non-empty list of dict"
)
super
(
Interpreter
,
self
).
__init__
(
source
,
**
kwds
)
self
.
namespaces
=
namespaces
# Don't use the fast parser, because it does crazy stuff that we don't
# need in our very simple and small code here (that is always
# changing).
self
.
_parser
=
UserContextParser
(
self
.
_grammar
,
self
.
source
,
self
.
_orig_path
,
self
.
_pos
,
self
.
_user_context
,
self
.
_parsed_callback
,
use_fast_parser
=
False
)
interpreter
.
add_namespaces_to_parser
(
self
.
_evaluator
,
namespaces
,
self
.
_parser
.
module
())
def
_simple_complete
(
self
,
path
,
dot
,
like
):
user_stmt
=
self
.
_parser
.
user_stmt_with_whitespace
()
is_simple_path
=
not
path
or
re
.
search
(
'^[\w][\w\d.]*$'
,
path
)
if
isinstance
(
user_stmt
,
tree
.
Import
)
or
not
is_simple_path
:
return
super
(
Interpreter
,
self
).
_simple_complete
(
path
,
dot
,
like
)
else
:
class
NamespaceModule
(
object
):
def
__getattr__
(
_
,
name
):
for
n
in
self
.
namespaces
:
try
:
return
n
[
name
]
except
KeyError
:
pass
raise
AttributeError
()
def
__dir__
(
_
):
gen
=
(
n
.
keys
()
for
n
in
self
.
namespaces
)
return
list
(
set
(
chain
.
from_iterable
(
gen
)))
paths
=
path
.
split
(
'.'
)
if
path
else
[]
namespaces
=
(
NamespaceModule
(),
builtins
)
for
p
in
paths
:
old
,
namespaces
=
namespaces
, []
for
n
in
old
:
try
:
namespaces
.
append
(
getattr
(
n
,
p
))
except
Exception
:
pass
completion_names
=
[]
for
namespace
in
namespaces
:
for
name
in
dir
(
namespace
):
if
name
.
lower
().
startswith
(
like
.
lower
()):
scope
=
self
.
_parser
.
module
()
n
=
FakeName
(
name
,
scope
)
completion_names
.
append
(
n
)
return
completion_names
def
defined_names
(
source
,
path
=
None
,
encoding
=
'utf-8'
):
"""
Get all definitions in `source` sorted by its position.
This functions can be used for listing functions, classes and
data defined in a file. This can be useful if you want to list
them in "sidebar". Each element in the returned list also has
`defined_names` method which can be used to get sub-definitions
(e.g., methods in class).
:rtype: list of classes.Definition
.. deprecated:: 0.9.0
Use :func:`names` instead.
.. todo:: Remove!
"""
warnings
.
warn
(
"Use call_signatures instead."
,
DeprecationWarning
)
return
names
(
source
,
path
,
encoding
)
def
names
(
source
=
None
,
path
=
None
,
encoding
=
'utf-8'
,
all_scopes
=
False
,
definitions
=
True
,
references
=
False
):
"""
Returns a list of `Definition` objects, containing name parts.
This means you can call ``Definition.goto_assignments()`` and get the
reference of a name.
The parameters are the same as in :py:class:`Script`, except or the
following ones:
:param all_scopes: If True lists the names of all scopes instead of only
the module namespace.
:param definitions: If True lists the names that have been defined by a
class, function or a statement (``a = b`` returns ``a``).
:param references: If True lists all the names that are not listed by
``definitions=True``. E.g. ``a = b`` returns ``b``.
"""
def
def_ref_filter
(
_def
):
is_def
=
_def
.
is_definition
()
return
definitions
and
is_def
or
references
and
not
is_def
# Set line/column to a random position, because they don't matter.
script
=
Script
(
source
,
line
=
1
,
column
=
0
,
path
=
path
,
encoding
=
encoding
)
defs
=
[
classes
.
Definition
(
script
.
_evaluator
,
name_part
)
for
name_part
in
get_module_names
(
script
.
_parser
.
module
(),
all_scopes
)]
return
sorted
(
filter
(
def_ref_filter
,
defs
),
key
=
lambda
x
: (
x
.
line
,
x
.
column
))
def
preload_module
(
*
modules
):
"""
Preloading modules tells Jedi to load a module now, instead of lazy parsing
of modules. Usful for IDEs, to control which modules to load on startup.
:param modules: different module names, list of string.
"""
for
m
in
modules
:
s
=
"import %s as x; x."
%
m
Script
(
s
,
1
,
len
(
s
),
None
).
completions
()
def
set_debug_function
(
func_cb
=
debug
.
print_to_stdout
,
warnings
=
True
,
notices
=
True
,
speed
=
True
):
"""
Define a callback debug function to get all the debug messages.
:param func_cb: The callback function for debug messages, with n params.
"""
debug
.
debug_function
=
func_cb
debug
.
enable_warning
=
warnings
debug
.
enable_notice
=
notices
debug
.
enable_speed
=
speed
Back
|
FazBrowse Home
|
New Git URL