skylos 1.2.2__py3-none-any.whl → 2.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of skylos might be problematic. Click here for more details.
- skylos/__init__.py +1 -1
- skylos/analyzer.py +103 -121
- skylos/cli.py +66 -109
- skylos/codemods.py +89 -0
- skylos/constants.py +25 -10
- skylos/framework_aware.py +290 -90
- skylos/server.py +560 -0
- skylos/test_aware.py +0 -1
- skylos/visitor.py +249 -90
- {skylos-1.2.2.dist-info → skylos-2.1.0.dist-info}/METADATA +4 -1
- {skylos-1.2.2.dist-info → skylos-2.1.0.dist-info}/RECORD +16 -13
- test/test_codemods.py +153 -0
- test/test_framework_aware.py +176 -242
- {skylos-1.2.2.dist-info → skylos-2.1.0.dist-info}/WHEEL +0 -0
- {skylos-1.2.2.dist-info → skylos-2.1.0.dist-info}/entry_points.txt +0 -0
- {skylos-1.2.2.dist-info → skylos-2.1.0.dist-info}/top_level.txt +0 -0
skylos/visitor.py
CHANGED
|
@@ -1,28 +1,27 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
2
|
import ast
|
|
3
3
|
from pathlib import Path
|
|
4
|
-
import
|
|
5
|
-
import re, logging, traceback
|
|
6
|
-
DBG = bool(int(os.getenv("SKYLOS_DEBUG", "0")))
|
|
7
|
-
log = logging.getLogger("Skylos")
|
|
4
|
+
import re
|
|
8
5
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
6
|
+
PYTHON_BUILTINS={"print", "len", "str", "int", "float", "list", "dict", "set", "tuple", "range", "open",
|
|
7
|
+
"super", "object", "type", "enumerate", "zip", "map", "filter", "sorted", "sum", "min",
|
|
8
|
+
"next", "iter", "bytes", "bytearray", "format", "round", "abs", "complex", "hash", "id", "bool", "callable",
|
|
9
|
+
"getattr", "max", "all", "any", "setattr", "hasattr", "isinstance", "globals", "locals",
|
|
10
|
+
"vars", "dir" ,"property", "classmethod", "staticmethod"}
|
|
11
|
+
DYNAMIC_PATTERNS={"getattr", "globals", "eval", "exec"}
|
|
12
12
|
|
|
13
13
|
class Definition:
|
|
14
|
-
__slots__ = ('name', 'type', 'filename', 'line', 'simple_name', 'confidence', 'references', 'is_exported', 'in_init')
|
|
15
14
|
|
|
16
|
-
def __init__(self,
|
|
17
|
-
self.name =
|
|
15
|
+
def __init__(self, name, t, filename, line):
|
|
16
|
+
self.name = name
|
|
18
17
|
self.type = t
|
|
19
|
-
self.filename =
|
|
20
|
-
self.line =
|
|
21
|
-
self.simple_name =
|
|
18
|
+
self.filename = filename
|
|
19
|
+
self.line = line
|
|
20
|
+
self.simple_name = name.split('.')[-1]
|
|
22
21
|
self.confidence = 100
|
|
23
22
|
self.references = 0
|
|
24
23
|
self.is_exported = False
|
|
25
|
-
self.in_init = "__init__.py" in str(
|
|
24
|
+
self.in_init = "__init__.py" in str(filename)
|
|
26
25
|
|
|
27
26
|
def to_dict(self):
|
|
28
27
|
if self.type == "method" and "." in self.name:
|
|
@@ -48,26 +47,33 @@ class Definition:
|
|
|
48
47
|
|
|
49
48
|
class Visitor(ast.NodeVisitor):
|
|
50
49
|
def __init__(self,mod,file):
|
|
51
|
-
self.mod=mod
|
|
52
|
-
self.file=file
|
|
53
|
-
self.defs=[]
|
|
54
|
-
self.refs=[]
|
|
55
|
-
self.cls=None
|
|
56
|
-
self.alias={}
|
|
57
|
-
self.dyn=set()
|
|
58
|
-
self.exports=set()
|
|
59
|
-
self.current_function_scope
|
|
60
|
-
self.current_function_params
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
def
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
50
|
+
self.mod= mod
|
|
51
|
+
self.file= file
|
|
52
|
+
self.defs= []
|
|
53
|
+
self.refs= []
|
|
54
|
+
self.cls= None
|
|
55
|
+
self.alias= {}
|
|
56
|
+
self.dyn= set()
|
|
57
|
+
self.exports= set()
|
|
58
|
+
self.current_function_scope= []
|
|
59
|
+
self.current_function_params= []
|
|
60
|
+
self.local_var_maps = []
|
|
61
|
+
self.in_cst_class = 0
|
|
62
|
+
self.local_type_maps = []
|
|
63
|
+
|
|
64
|
+
def add_def(self, name, t, line):
|
|
65
|
+
if name not in {d.name for d in self.defs}:
|
|
66
|
+
self.defs.append(Definition(name, t, self.file, line))
|
|
67
|
+
|
|
68
|
+
def add_ref(self, name):
|
|
69
|
+
self.refs.append((name, self.file))
|
|
70
|
+
|
|
71
|
+
def qual(self, name):
|
|
72
|
+
if name in self.alias:
|
|
73
|
+
return self.alias[name]
|
|
74
|
+
if name in PYTHON_BUILTINS:
|
|
75
|
+
return name
|
|
76
|
+
return f"{self.mod}.{name}" if self.mod else name
|
|
71
77
|
|
|
72
78
|
def visit_annotation(self, node):
|
|
73
79
|
if node is not None:
|
|
@@ -82,25 +88,17 @@ class Visitor(ast.NodeVisitor):
|
|
|
82
88
|
if not isinstance(annotation_str, str):
|
|
83
89
|
return
|
|
84
90
|
|
|
85
|
-
if DBG:
|
|
86
|
-
log.debug(f"[visitor] parsing string annotation {annotation_str!r} "
|
|
87
|
-
f"in {self.filename}:{getattr(self, 'line', '?')}")
|
|
88
|
-
|
|
89
91
|
try:
|
|
90
92
|
parsed = ast.parse(annotation_str, mode="eval")
|
|
91
93
|
self.visit(parsed.body)
|
|
92
|
-
except
|
|
93
|
-
if DBG:
|
|
94
|
-
log.debug("[visitor] inner-annotation parse failed:\n" +
|
|
95
|
-
traceback.format_exc())
|
|
96
|
-
# keep going but dont swallow symbol names:
|
|
94
|
+
except:
|
|
97
95
|
for tok in re.findall(r"[A-Za-z_][A-Za-z0-9_]*", annotation_str):
|
|
98
96
|
self.add_ref(tok)
|
|
99
97
|
|
|
100
|
-
def visit_Import(self,node):
|
|
98
|
+
def visit_Import(self, node):
|
|
101
99
|
for a in node.names:
|
|
102
|
-
full=a.name
|
|
103
|
-
self.alias[a.asname or a.name.split(".")[-1]]=full
|
|
100
|
+
full= a.name
|
|
101
|
+
self.alias[a.asname or a.name.split(".")[-1]]= full
|
|
104
102
|
self.add_def(full,"import",node.lineno)
|
|
105
103
|
|
|
106
104
|
def visit_ImportFrom(self, node):
|
|
@@ -127,6 +125,7 @@ class Visitor(ast.NodeVisitor):
|
|
|
127
125
|
self.visit_annotation(arg.annotation)
|
|
128
126
|
for arg in args.posonlyargs:
|
|
129
127
|
self.visit_annotation(arg.annotation)
|
|
128
|
+
|
|
130
129
|
for arg in args.kwonlyargs:
|
|
131
130
|
self.visit_annotation(arg.annotation)
|
|
132
131
|
if args.vararg:
|
|
@@ -143,16 +142,18 @@ class Visitor(ast.NodeVisitor):
|
|
|
143
142
|
outer_scope_prefix = '.'.join(self.current_function_scope) + '.' if self.current_function_scope else ''
|
|
144
143
|
|
|
145
144
|
if self.cls:
|
|
146
|
-
name_parts
|
|
145
|
+
name_parts= [self.mod, self.cls, outer_scope_prefix + node.name]
|
|
147
146
|
else:
|
|
148
|
-
name_parts
|
|
147
|
+
name_parts= [self.mod, outer_scope_prefix + node.name]
|
|
149
148
|
|
|
150
|
-
qualified_name
|
|
149
|
+
qualified_name= ".".join(filter(None, name_parts))
|
|
151
150
|
|
|
152
151
|
self.add_def(qualified_name,"method"if self.cls else"function",node.lineno)
|
|
153
152
|
|
|
154
153
|
self.current_function_scope.append(node.name)
|
|
155
|
-
|
|
154
|
+
self.local_var_maps.append({})
|
|
155
|
+
self.local_type_maps.append({})
|
|
156
|
+
|
|
156
157
|
old_params = self.current_function_params
|
|
157
158
|
self.current_function_params = []
|
|
158
159
|
|
|
@@ -172,32 +173,95 @@ class Visitor(ast.NodeVisitor):
|
|
|
172
173
|
|
|
173
174
|
self.current_function_scope.pop()
|
|
174
175
|
self.current_function_params = old_params
|
|
176
|
+
self.local_var_maps.pop()
|
|
177
|
+
self.local_type_maps.pop()
|
|
175
178
|
|
|
176
|
-
visit_AsyncFunctionDef=visit_FunctionDef
|
|
179
|
+
visit_AsyncFunctionDef= visit_FunctionDef
|
|
177
180
|
|
|
178
|
-
def visit_ClassDef(self,node):
|
|
179
|
-
cname=f"{self.mod}.{node.name}"
|
|
180
|
-
self.add_def(cname,"class",node.lineno)
|
|
181
|
+
def visit_ClassDef(self, node):
|
|
182
|
+
cname =f"{self.mod}.{node.name}"
|
|
183
|
+
self.add_def(cname, "class",node.lineno)
|
|
184
|
+
|
|
185
|
+
is_cst = False
|
|
181
186
|
|
|
182
187
|
for base in node.bases:
|
|
188
|
+
base_name = ""
|
|
189
|
+
if isinstance(base, ast.Attribute):
|
|
190
|
+
base_name = base.attr
|
|
191
|
+
elif isinstance(base, ast.Name):
|
|
192
|
+
base_name = base.id
|
|
183
193
|
self.visit(base)
|
|
194
|
+
if base_name in {"CSTTransformer", "CSTVisitor"}:
|
|
195
|
+
is_cst = True
|
|
184
196
|
for keyword in node.keywords:
|
|
185
197
|
self.visit(keyword.value)
|
|
186
198
|
for decorator in node.decorator_list:
|
|
187
199
|
self.visit(decorator)
|
|
188
200
|
|
|
189
|
-
prev=self.cls
|
|
190
|
-
|
|
191
|
-
|
|
201
|
+
prev= self.cls
|
|
202
|
+
if is_cst:
|
|
203
|
+
self.in_cst_class += 1
|
|
204
|
+
|
|
205
|
+
self.cls= node.name
|
|
206
|
+
for b in node.body:
|
|
207
|
+
self.visit(b)
|
|
208
|
+
|
|
209
|
+
self.cls= prev
|
|
210
|
+
if is_cst:
|
|
211
|
+
self.in_cst_class -= 1
|
|
192
212
|
|
|
193
213
|
def visit_AnnAssign(self, node):
|
|
194
214
|
self.visit_annotation(node.annotation)
|
|
195
215
|
if node.value:
|
|
196
216
|
self.visit(node.value)
|
|
197
|
-
|
|
217
|
+
|
|
218
|
+
def _define(t):
|
|
219
|
+
if isinstance(t, ast.Name):
|
|
220
|
+
name_simple = t.id
|
|
221
|
+
scope_parts = [self.mod]
|
|
222
|
+
if self.cls: scope_parts.append(self.cls)
|
|
223
|
+
if self.current_function_scope: scope_parts.extend(self.current_function_scope)
|
|
224
|
+
prefix = '.'.join(filter(None, scope_parts))
|
|
225
|
+
if prefix:
|
|
226
|
+
var_name = f"{prefix}.{name_simple}"
|
|
227
|
+
else:
|
|
228
|
+
var_name = name_simple
|
|
229
|
+
|
|
230
|
+
self.add_def(var_name, "variable", t.lineno)
|
|
231
|
+
if self.current_function_scope and self.local_var_maps:
|
|
232
|
+
self.local_var_maps[-1][name_simple] = var_name
|
|
233
|
+
elif isinstance(t, (ast.Tuple, ast.List)):
|
|
234
|
+
for elt in t.elts:
|
|
235
|
+
_define(elt)
|
|
236
|
+
_define(node.target)
|
|
198
237
|
|
|
199
238
|
def visit_AugAssign(self, node):
|
|
200
|
-
|
|
239
|
+
if isinstance(node.target, ast.Name):
|
|
240
|
+
nm = node.target.id
|
|
241
|
+
if (self.current_function_scope and
|
|
242
|
+
self.local_var_maps and
|
|
243
|
+
self.local_var_maps and
|
|
244
|
+
nm in self.local_var_maps[-1]):
|
|
245
|
+
|
|
246
|
+
self.add_ref(self.local_var_maps[-1][nm])
|
|
247
|
+
|
|
248
|
+
else:
|
|
249
|
+
self.add_ref(self.qual(nm))
|
|
250
|
+
scope_parts = [self.mod]
|
|
251
|
+
if self.cls: scope_parts.append(self.cls)
|
|
252
|
+
|
|
253
|
+
if self.current_function_scope: scope_parts.extend(self.current_function_scope)
|
|
254
|
+
prefix = '.'.join(filter(None, scope_parts))
|
|
255
|
+
if prefix:
|
|
256
|
+
var_name = f"{prefix}.{nm}"
|
|
257
|
+
else:
|
|
258
|
+
var_name = nm
|
|
259
|
+
|
|
260
|
+
self.add_def(var_name, "variable", node.lineno)
|
|
261
|
+
if self.current_function_scope and self.local_var_maps:
|
|
262
|
+
self.local_var_maps[-1][nm] = var_name
|
|
263
|
+
else:
|
|
264
|
+
self.visit(node.target)
|
|
201
265
|
self.visit(node.value)
|
|
202
266
|
|
|
203
267
|
def visit_Subscript(self, node):
|
|
@@ -215,8 +279,11 @@ class Visitor(ast.NodeVisitor):
|
|
|
215
279
|
def visit_Assign(self, node):
|
|
216
280
|
def process_target_for_def(target_node):
|
|
217
281
|
if isinstance(target_node, ast.Name):
|
|
218
|
-
|
|
219
|
-
if
|
|
282
|
+
name_simple = target_node.id
|
|
283
|
+
if (name_simple == "METADATA_DEPENDENCIES"
|
|
284
|
+
and self.cls and self.in_cst_class > 0):
|
|
285
|
+
return
|
|
286
|
+
if name_simple == "__all__" and not self.current_function_scope and not self.cls:
|
|
220
287
|
return
|
|
221
288
|
|
|
222
289
|
scope_parts = [self.mod]
|
|
@@ -224,11 +291,16 @@ class Visitor(ast.NodeVisitor):
|
|
|
224
291
|
scope_parts.append(self.cls)
|
|
225
292
|
if self.current_function_scope:
|
|
226
293
|
scope_parts.extend(self.current_function_scope)
|
|
227
|
-
|
|
294
|
+
|
|
228
295
|
prefix = '.'.join(filter(None, scope_parts))
|
|
229
|
-
|
|
296
|
+
if prefix:
|
|
297
|
+
var_name = f"{prefix}.{name_simple}"
|
|
298
|
+
else:
|
|
299
|
+
var_name = name_simple
|
|
230
300
|
|
|
231
|
-
self.add_def(
|
|
301
|
+
self.add_def(var_name, "variable", target_node.lineno)
|
|
302
|
+
if self.current_function_scope and self.local_var_maps:
|
|
303
|
+
self.local_var_maps[-1][name_simple] = var_name
|
|
232
304
|
|
|
233
305
|
elif isinstance(target_node, (ast.Tuple, ast.List)):
|
|
234
306
|
for elt in target_node.elts:
|
|
@@ -236,7 +308,7 @@ class Visitor(ast.NodeVisitor):
|
|
|
236
308
|
|
|
237
309
|
for t in node.targets:
|
|
238
310
|
process_target_for_def(t)
|
|
239
|
-
|
|
311
|
+
|
|
240
312
|
for target in node.targets:
|
|
241
313
|
if isinstance(target, ast.Name) and target.id == "__all__":
|
|
242
314
|
if isinstance(node.value, (ast.List, ast.Tuple)):
|
|
@@ -246,12 +318,48 @@ class Visitor(ast.NodeVisitor):
|
|
|
246
318
|
value = elt.value
|
|
247
319
|
elif hasattr(elt, 's') and isinstance(elt.s, str):
|
|
248
320
|
value = elt.s
|
|
249
|
-
|
|
321
|
+
|
|
250
322
|
if value is not None:
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
323
|
+
if self.mod:
|
|
324
|
+
export_name = f"{self.mod}.{value}"
|
|
325
|
+
else:
|
|
326
|
+
export_name = value
|
|
327
|
+
|
|
328
|
+
self.add_ref(export_name)
|
|
329
|
+
self.add_ref(value)
|
|
330
|
+
|
|
331
|
+
try:
|
|
332
|
+
if isinstance(node.value, ast.Call):
|
|
333
|
+
callee = node.value.func
|
|
334
|
+
fqname = None
|
|
335
|
+
|
|
336
|
+
if isinstance(callee, ast.Name):
|
|
337
|
+
fqname = self.alias.get(callee.id, self.qual(callee.id))
|
|
338
|
+
|
|
339
|
+
elif isinstance(callee, ast.Attribute):
|
|
340
|
+
parts = []
|
|
341
|
+
cur = callee
|
|
342
|
+
while isinstance(cur, ast.Attribute):
|
|
343
|
+
parts.append(cur.attr)
|
|
344
|
+
cur = cur.value
|
|
345
|
+
head = None
|
|
346
|
+
if isinstance(cur, ast.Name):
|
|
347
|
+
head = self.alias.get(cur.id, self.qual(cur.id))
|
|
348
|
+
if head:
|
|
349
|
+
fqname = ".".join([head] + list(reversed(parts)))
|
|
350
|
+
|
|
351
|
+
if fqname and self.current_function_scope and self.local_type_maps:
|
|
352
|
+
def _mark_target(t):
|
|
353
|
+
if isinstance(t, ast.Name):
|
|
354
|
+
self.local_type_maps[-1][t.id] = fqname
|
|
355
|
+
elif isinstance(t, (ast.Tuple, ast.List)):
|
|
356
|
+
for elt in t.elts:
|
|
357
|
+
_mark_target(elt)
|
|
358
|
+
for t in node.targets:
|
|
359
|
+
_mark_target(t)
|
|
360
|
+
except Exception:
|
|
361
|
+
pass
|
|
362
|
+
|
|
255
363
|
self.generic_visit(node)
|
|
256
364
|
|
|
257
365
|
def visit_Call(self, node):
|
|
@@ -271,7 +379,10 @@ class Visitor(ast.NodeVisitor):
|
|
|
271
379
|
elif isinstance(node.args[0], ast.Name):
|
|
272
380
|
target_name = node.args[0].id
|
|
273
381
|
if target_name != "self":
|
|
274
|
-
|
|
382
|
+
if self.mod:
|
|
383
|
+
self.dyn.add(self.mod.split(".")[0])
|
|
384
|
+
else:
|
|
385
|
+
self.dyn.add("")
|
|
275
386
|
|
|
276
387
|
elif isinstance(node.func, ast.Name) and node.func.id == "globals":
|
|
277
388
|
parent = getattr(node, 'parent', None)
|
|
@@ -283,32 +394,80 @@ class Visitor(ast.NodeVisitor):
|
|
|
283
394
|
self.add_ref(f"{self.mod}.{func_name}")
|
|
284
395
|
|
|
285
396
|
elif isinstance(node.func, ast.Name) and node.func.id in ("eval", "exec"):
|
|
286
|
-
|
|
397
|
+
root_mod = ""
|
|
398
|
+
if self.mod:
|
|
399
|
+
root_mod = self.mod.split(".")[0]
|
|
400
|
+
self.dyn.add(root_mod)
|
|
287
401
|
|
|
288
|
-
def visit_Name(self,node):
|
|
289
|
-
if isinstance(node.ctx,ast.Load):
|
|
402
|
+
def visit_Name(self, node):
|
|
403
|
+
if isinstance(node.ctx, ast.Load):
|
|
290
404
|
for param_name, param_full_name in self.current_function_params:
|
|
291
405
|
if node.id == param_name:
|
|
292
406
|
self.add_ref(param_full_name)
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
self.
|
|
298
|
-
|
|
299
|
-
|
|
407
|
+
return
|
|
408
|
+
|
|
409
|
+
if (self.current_function_scope and
|
|
410
|
+
self.local_var_maps
|
|
411
|
+
and self.local_var_maps
|
|
412
|
+
and node.id in self.local_var_maps[-1]):
|
|
413
|
+
|
|
414
|
+
self.add_ref(self.local_var_maps[-1][node.id])
|
|
415
|
+
return
|
|
416
|
+
|
|
417
|
+
qualified = self.qual(node.id)
|
|
418
|
+
self.add_ref(qualified)
|
|
419
|
+
if node.id in DYNAMIC_PATTERNS:
|
|
420
|
+
self.dyn.add(self.mod.split(".")[0])
|
|
300
421
|
|
|
301
422
|
def visit_Attribute(self, node):
|
|
302
423
|
self.generic_visit(node)
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
self.
|
|
424
|
+
|
|
425
|
+
if not isinstance(node.ctx, ast.Load):
|
|
426
|
+
return
|
|
427
|
+
|
|
428
|
+
if isinstance(node.value, ast.Name):
|
|
429
|
+
base = node.value.id
|
|
430
|
+
|
|
431
|
+
param_hit = None
|
|
432
|
+
for param_name, param_full in self.current_function_params:
|
|
433
|
+
if base == param_name:
|
|
434
|
+
param_hit = (param_name, param_full)
|
|
435
|
+
break
|
|
436
|
+
|
|
437
|
+
if param_hit:
|
|
438
|
+
self.add_ref(param_hit[1])
|
|
439
|
+
|
|
440
|
+
if self.cls and base in {"self", "cls"}:
|
|
441
|
+
if self.mod:
|
|
442
|
+
owner = f"{self.mod}.{self.cls}"
|
|
443
|
+
else:
|
|
444
|
+
owner = self.cls
|
|
445
|
+
|
|
446
|
+
self.add_ref(f"{owner}.{node.attr}")
|
|
447
|
+
return
|
|
448
|
+
|
|
449
|
+
if (self.current_function_scope and
|
|
450
|
+
self.local_type_maps and
|
|
451
|
+
self.local_type_maps[-1].get(base)):
|
|
452
|
+
|
|
453
|
+
self.add_ref(f"{self.local_type_maps[-1][base]}.{node.attr}")
|
|
454
|
+
return
|
|
455
|
+
|
|
456
|
+
self.add_ref(f"{self.qual(base)}.{node.attr}")
|
|
457
|
+
|
|
458
|
+
def visit_NamedExpr(self, node):
|
|
459
|
+
self.visit(node.value)
|
|
460
|
+
if isinstance(node.target, ast.Name):
|
|
461
|
+
nm = node.target.id
|
|
462
|
+
scope_parts = [self.mod]
|
|
463
|
+
if self.cls: scope_parts.append(self.cls)
|
|
464
|
+
if self.current_function_scope: scope_parts.extend(self.current_function_scope)
|
|
465
|
+
prefix = '.'.join(filter(None, scope_parts))
|
|
466
|
+
var_name = f"{prefix}.{nm}" if prefix else nm
|
|
467
|
+
self.add_def(var_name, "variable", node.lineno)
|
|
468
|
+
if self.current_function_scope and self.local_var_maps:
|
|
469
|
+
self.local_var_maps[-1][nm] = var_name
|
|
470
|
+
self.add_ref(var_name)
|
|
312
471
|
|
|
313
472
|
def visit_keyword(self, node):
|
|
314
473
|
self.visit(node.value)
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: skylos
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 2.1.0
|
|
4
4
|
Summary: A static analysis tool for Python codebases
|
|
5
5
|
Author-email: oha <aaronoh2015@gmail.com>
|
|
6
6
|
Requires-Python: >=3.9
|
|
7
7
|
Requires-Dist: inquirer>=3.0.0
|
|
8
|
+
Requires-Dist: flask>=2.1.0
|
|
9
|
+
Requires-Dist: flask-cors>=3.0.0
|
|
10
|
+
Requires-Dist: libcst>=1.8.2
|
|
8
11
|
Dynamic: requires-python
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
skylos/__init__.py,sha256=
|
|
2
|
-
skylos/analyzer.py,sha256=
|
|
3
|
-
skylos/cli.py,sha256=
|
|
4
|
-
skylos/
|
|
5
|
-
skylos/
|
|
6
|
-
skylos/
|
|
7
|
-
skylos/
|
|
1
|
+
skylos/__init__.py,sha256=sr_HNrjL2O7hbyh_8vN2tG1ZKw8sXJVegKjp3G8Iz9c,151
|
|
2
|
+
skylos/analyzer.py,sha256=JoQ_otvLmI5k64y3h11jVZEWuA6u3npY15Nwy1vrGi0,14995
|
|
3
|
+
skylos/cli.py,sha256=bRxhvKkw_VWQVHT6WxKyX9i3qJjGuJJaEJ3QI8FIpZw,15887
|
|
4
|
+
skylos/codemods.py,sha256=A5dNwTJiYtgP3Mv8NQ03etdfi9qNHSECv1GRpLyDCYU,3213
|
|
5
|
+
skylos/constants.py,sha256=vAfKls0OuR5idtXzeMDfYv5-wLtYWDe1NW5TSUJT8RI,1636
|
|
6
|
+
skylos/framework_aware.py,sha256=eX4oU0jQwDWejkkW4kjRNctre27sVLHK1CTDDiqPqRw,13054
|
|
7
|
+
skylos/server.py,sha256=5Rlgy3LdE8I5TWRJJh0n19JqhVYaAOc9fUtRjL-PpX8,16270
|
|
8
|
+
skylos/test_aware.py,sha256=kxYoMG2m02kbMlxtFOM-MWJO8qqxHviP9HgAMbKRfvU,2304
|
|
9
|
+
skylos/visitor.py,sha256=i-YWVenc8mG0dWzYi945HmktIE2RkgL7rBT7VUnhkLI,18073
|
|
8
10
|
test/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
9
11
|
test/compare_tools.py,sha256=0g9PDeJlbst-7hOaQzrL4MiJFQKpqM8q8VeBGzpPczg,22738
|
|
10
12
|
test/conftest.py,sha256=57sTF6vLL5U0CVKwGQFJcRs6n7t1dEHIriQoSluNmAI,6418
|
|
@@ -12,8 +14,9 @@ test/diagnostics.py,sha256=ExuFOCVpc9BDwNYapU96vj9RXLqxji32Sv6wVF4nJYU,13802
|
|
|
12
14
|
test/test_analyzer.py,sha256=vZ-0cSF_otm7ZYdp6U3a8eWGwRZ6Tf0tVuJxYqcxdqM,22816
|
|
13
15
|
test/test_changes_analyzer.py,sha256=l1hspCFz-sF8gqOilJvntUDuGckwhYsVtzvSRB13ZWw,5085
|
|
14
16
|
test/test_cli.py,sha256=rtdKzanDRJT_F92jKkCQFdhvlfwVJxfXKO8Hrbn-mIg,13180
|
|
17
|
+
test/test_codemods.py,sha256=Tbp9jE95HDl77EenTmyTtB1Sc3L8fwY9xiMNVDN5lxo,4522
|
|
15
18
|
test/test_constants.py,sha256=pMuDy0UpC81zENMDCeK6Bqmm3BR_HHZQSlMG-9TgOm0,12602
|
|
16
|
-
test/test_framework_aware.py,sha256=
|
|
19
|
+
test/test_framework_aware.py,sha256=G9va1dEQ31wsvd4X7ROf_1YhhAQG5CogB7v0hYCojQ8,8802
|
|
17
20
|
test/test_integration.py,sha256=bNKGUe-w0xEZEdnoQNHbssvKMGs9u9fmFQTOz1lX9_k,12398
|
|
18
21
|
test/test_skylos.py,sha256=kz77STrS4k3Eez5RDYwGxOg2WH3e7zNZPUYEaTLbGTs,15608
|
|
19
22
|
test/test_test_aware.py,sha256=VmbR_MQY0m941CAxxux8OxJHIr7l8crfWRouSeBMhIo,9390
|
|
@@ -25,8 +28,8 @@ test/sample_repo/sample_repo/commands.py,sha256=b6gQ9YDabt2yyfqGbOpLo0osF7wya8O4
|
|
|
25
28
|
test/sample_repo/sample_repo/models.py,sha256=xXIg3pToEZwKuUCmKX2vTlCF_VeFA0yZlvlBVPIy5Qw,3320
|
|
26
29
|
test/sample_repo/sample_repo/routes.py,sha256=8yITrt55BwS01G7nWdESdx8LuxmReqop1zrGUKPeLi8,2475
|
|
27
30
|
test/sample_repo/sample_repo/utils.py,sha256=S56hEYh8wkzwsD260MvQcmUFOkw2EjFU27nMLFE6G2k,1103
|
|
28
|
-
skylos-1.
|
|
29
|
-
skylos-1.
|
|
30
|
-
skylos-1.
|
|
31
|
-
skylos-1.
|
|
32
|
-
skylos-1.
|
|
31
|
+
skylos-2.1.0.dist-info/METADATA,sha256=oE2audt2wkmDLNdDcZCHgmDxtrZY8gygMnDwI5Qi6V4,314
|
|
32
|
+
skylos-2.1.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
33
|
+
skylos-2.1.0.dist-info/entry_points.txt,sha256=zzRpN2ByznlQoLeuLolS_TFNYSQxUGBL1EXQsAd6bIA,43
|
|
34
|
+
skylos-2.1.0.dist-info/top_level.txt,sha256=f8GA_7KwfaEopPMP8-EXDQXaqd4IbsOQPakZy01LkdQ,12
|
|
35
|
+
skylos-2.1.0.dist-info/RECORD,,
|