FazBrowse GitHub Viewer
|
Trending
|
URL:
|
Home
Tools:
[Download Repo ZIP]
[View Raw Code]
[Original HTTPS Page]
pythonVSCode/pythonFiles/preview/jedi/evaluate/recursion.py at master · GuloWang/pythonVSCode · GitHub
GuloWang
/
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
/
preview
/
jedi
/
evaluate
/
recursion.py
Copy path
More file actions
More file actions
Latest commit
History
History
History
157 lines (132 loc) · 5.01 KB
Breadcrumbs
pythonVSCode
/
pythonFiles
/
preview
/
jedi
/
evaluate
/
recursion.py
Copy path
File metadata and controls
157 lines (132 loc) · 5.01 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
"""
Recursions are the recipe of |jedi| to conquer Python code. However, someone
must stop recursions going mad. Some settings are here to make |jedi| stop at
the right time. You can read more about them :ref:`here <settings-recursion>`.
Next to :mod:`jedi.evaluate.cache` this module also makes |jedi| not
thread-safe. Why? ``execution_recursion_decorator`` uses class variables to
count the function calls.
"""
from
jedi
import
debug
from
jedi
import
settings
from
jedi
.
evaluate
import
iterable
def
recursion_decorator
(
func
):
def
run
(
evaluator
,
stmt
,
*
args
,
**
kwargs
):
rec_detect
=
evaluator
.
recursion_detector
if
rec_detect
.
push_stmt
(
stmt
):
return
set
()
else
:
result
=
func
(
evaluator
,
stmt
,
*
args
,
**
kwargs
)
rec_detect
.
pop_stmt
()
return
result
return
run
class
RecursionDetector
(
object
):
"""
A decorator to detect recursions in statements. In a recursion a statement
at the same place, in the same module may not be executed two times.
"""
def
__init__
(
self
,
evaluator
):
self
.
top
=
None
self
.
current
=
None
self
.
_evaluator
=
evaluator
def
push_stmt
(
self
,
stmt
):
self
.
current
=
_RecursionNode
(
self
.
_evaluator
,
stmt
,
self
.
current
)
check
=
self
.
_check_recursion
()
if
check
:
debug
.
warning
(
'catched stmt recursion: %s against %s @%s'
,
stmt
,
check
.
stmt
,
stmt
.
start_pos
)
self
.
pop_stmt
()
return
True
return
False
def
pop_stmt
(
self
):
if
self
.
current
is
not
None
:
# I don't know how current can be None, but sometimes it happens
# with Python3.
self
.
current
=
self
.
current
.
parent
def
_check_recursion
(
self
):
test
=
self
.
current
while
True
:
test
=
test
.
parent
if
self
.
current
==
test
:
return
test
if
not
test
:
return
False
def
node_statements
(
self
):
result
=
[]
n
=
self
.
current
while
n
:
result
.
insert
(
0
,
n
.
stmt
)
n
=
n
.
parent
return
result
class
_RecursionNode
(
object
):
""" A node of the RecursionDecorator. """
def
__init__
(
self
,
evaluator
,
stmt
,
parent
):
self
.
_evaluator
=
evaluator
self
.
script
=
stmt
.
get_parent_until
()
self
.
position
=
stmt
.
start_pos
self
.
parent
=
parent
self
.
stmt
=
stmt
# Don't check param instances, they are not causing recursions
# The same's true for the builtins, because the builtins are really
# simple.
self
.
is_ignored
=
self
.
script
==
self
.
_evaluator
.
BUILTINS
def
__eq__
(
self
,
other
):
if
not
other
:
return
None
return
self
.
script
==
other
.
script
\
and
self
.
position
==
other
.
position
\
and
not
self
.
is_ignored
and
not
other
.
is_ignored
def
execution_recursion_decorator
(
func
):
def
run
(
execution
,
**
kwargs
):
detector
=
execution
.
_evaluator
.
execution_recursion_detector
if
detector
.
push_execution
(
execution
):
result
=
set
()
else
:
result
=
func
(
execution
,
**
kwargs
)
detector
.
pop_execution
()
return
result
return
run
class
ExecutionRecursionDetector
(
object
):
"""
Catches recursions of executions.
"""
def
__init__
(
self
,
evaluator
):
self
.
recursion_level
=
0
self
.
parent_execution_funcs
=
[]
self
.
execution_funcs
=
set
()
self
.
execution_count
=
0
self
.
_evaluator
=
evaluator
def
__call__
(
self
,
execution
):
debug
.
dbg
(
'Execution recursions: %s'
,
execution
,
self
.
recursion_level
,
self
.
execution_count
,
len
(
self
.
execution_funcs
))
if
self
.
check_recursion
(
execution
):
result
=
set
()
else
:
result
=
self
.
func
(
execution
)
self
.
pop_execution
()
return
result
def
pop_execution
(
self
):
self
.
parent_execution_funcs
.
pop
()
self
.
recursion_level
-=
1
def
push_execution
(
self
,
execution
):
in_par_execution_funcs
=
execution
.
base
in
self
.
parent_execution_funcs
in_execution_funcs
=
execution
.
base
in
self
.
execution_funcs
self
.
recursion_level
+=
1
self
.
execution_count
+=
1
self
.
execution_funcs
.
add
(
execution
.
base
)
self
.
parent_execution_funcs
.
append
(
execution
.
base
)
if
self
.
execution_count
>
settings
.
max_executions
:
return
True
if
isinstance
(
execution
.
base
, (
iterable
.
Array
,
iterable
.
Generator
)):
return
False
module
=
execution
.
get_parent_until
()
if
module
==
self
.
_evaluator
.
BUILTINS
:
return
False
if
in_par_execution_funcs
:
if
self
.
recursion_level
>
settings
.
max_function_recursion_level
:
return
True
if
in_execution_funcs
and
\
len
(
self
.
execution_funcs
)
>
settings
.
max_until_execution_unique
:
return
True
if
self
.
execution_count
>
settings
.
max_executions_without_builtins
:
return
True
return
False
Back
|
FazBrowse Home
|
New Git URL