skylos 1.1.12__py3-none-any.whl → 1.2.1__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/analyzer.py +128 -133
- skylos/cli.py +20 -2
- skylos/constants.py +34 -27
- skylos/framework_aware.py +158 -0
- skylos/test_aware.py +66 -0
- skylos/visitor.py +28 -3
- {skylos-1.1.12.dist-info → skylos-1.2.1.dist-info}/METADATA +1 -1
- skylos-1.2.1.dist-info/RECORD +32 -0
- test/test_analyzer.py +253 -195
- test/test_changes_analyzer.py +149 -0
- test/test_constants.py +348 -0
- test/test_framework_aware.py +372 -0
- test/test_test_aware.py +328 -0
- test/test_visitor.py +0 -10
- skylos-1.1.12.dist-info/RECORD +0 -26
- {skylos-1.1.12.dist-info → skylos-1.2.1.dist-info}/WHEEL +0 -0
- {skylos-1.1.12.dist-info → skylos-1.2.1.dist-info}/entry_points.txt +0 -0
- {skylos-1.1.12.dist-info → skylos-1.2.1.dist-info}/top_level.txt +0 -0
skylos/test_aware.py
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import ast
|
|
2
|
+
from skylos.constants import TEST_IMPORT_RE, TEST_DECOR_RE, TEST_FILE_RE
|
|
3
|
+
|
|
4
|
+
class TestAwareVisitor:
|
|
5
|
+
|
|
6
|
+
def __init__(self, filename=None):
|
|
7
|
+
self.is_test_file = False
|
|
8
|
+
self.test_decorated_lines = set()
|
|
9
|
+
|
|
10
|
+
# mark as test file based on the file path/name NOT imports
|
|
11
|
+
if filename and TEST_FILE_RE.search(str(filename)):
|
|
12
|
+
self.is_test_file = True
|
|
13
|
+
|
|
14
|
+
def visit(self, node):
|
|
15
|
+
method = 'visit_' + node.__class__.__name__
|
|
16
|
+
visitor = getattr(self, method, self.generic_visit)
|
|
17
|
+
return visitor(node)
|
|
18
|
+
|
|
19
|
+
def generic_visit(self, node):
|
|
20
|
+
for field, value in ast.iter_fields(node):
|
|
21
|
+
if isinstance(value, list):
|
|
22
|
+
for item in value:
|
|
23
|
+
if isinstance(item, ast.AST):
|
|
24
|
+
self.visit(item)
|
|
25
|
+
elif isinstance(value, ast.AST):
|
|
26
|
+
self.visit(value)
|
|
27
|
+
|
|
28
|
+
def visit_Import(self, node):
|
|
29
|
+
|
|
30
|
+
if self.is_test_file:
|
|
31
|
+
for alias in node.names:
|
|
32
|
+
if TEST_IMPORT_RE.match(alias.name):
|
|
33
|
+
pass
|
|
34
|
+
self.generic_visit(node)
|
|
35
|
+
|
|
36
|
+
def visit_ImportFrom(self, node):
|
|
37
|
+
if self.is_test_file:
|
|
38
|
+
if node.module and TEST_IMPORT_RE.match(node.module):
|
|
39
|
+
pass
|
|
40
|
+
self.generic_visit(node)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def visit_FunctionDef(self, node):
|
|
44
|
+
if (node.name.startswith('test_') or
|
|
45
|
+
node.name.endswith('_test') or
|
|
46
|
+
any(node.name.startswith(prefix) for prefix in ['setup', 'teardown']) or
|
|
47
|
+
node.name in ['setUp', 'tearDown', 'setUpClass', 'tearDownClass',
|
|
48
|
+
'setUpModule', 'tearDownModule']):
|
|
49
|
+
self.test_decorated_lines.add(node.lineno)
|
|
50
|
+
|
|
51
|
+
for deco in node.decorator_list:
|
|
52
|
+
name = self._decorator_name(deco)
|
|
53
|
+
if name and (TEST_DECOR_RE.match(name) or 'pytest' in name or 'fixture' in name):
|
|
54
|
+
self.test_decorated_lines.add(node.lineno)
|
|
55
|
+
self.generic_visit(node)
|
|
56
|
+
|
|
57
|
+
def visit_AsyncFunctionDef(self, node):
|
|
58
|
+
self.visit_FunctionDef(node)
|
|
59
|
+
|
|
60
|
+
def _decorator_name(self, deco):
|
|
61
|
+
if isinstance(deco, ast.Name):
|
|
62
|
+
return deco.id
|
|
63
|
+
if isinstance(deco, ast.Attribute):
|
|
64
|
+
parent = self._decorator_name(deco.value)
|
|
65
|
+
return f"{parent}.{deco.attr}" if parent else deco.attr
|
|
66
|
+
return ""
|
skylos/visitor.py
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
2
|
import ast
|
|
3
3
|
from pathlib import Path
|
|
4
|
+
import os
|
|
5
|
+
import re, logging, traceback
|
|
6
|
+
DBG = bool(int(os.getenv("SKYLOS_DEBUG", "0")))
|
|
7
|
+
log = logging.getLogger("Skylos")
|
|
8
|
+
|
|
4
9
|
|
|
5
10
|
PYTHON_BUILTINS={"print","len","str","int","float","list","dict","set","tuple","range","open","super","object","type","enumerate","zip","map","filter","sorted","reversed","sum","min","max","all","any","next","iter","repr","chr","ord","bytes","bytearray","memoryview","format","round","abs","pow","divmod","complex","hash","id","bool","callable","getattr","setattr","delattr","hasattr","isinstance","issubclass","globals","locals","vars","dir","property","classmethod","staticmethod"}
|
|
6
11
|
DYNAMIC_PATTERNS={"getattr","globals","eval","exec"}
|
|
@@ -74,11 +79,23 @@ class Visitor(ast.NodeVisitor):
|
|
|
74
79
|
self.visit(node)
|
|
75
80
|
|
|
76
81
|
def visit_string_annotation(self, annotation_str):
|
|
82
|
+
if not isinstance(annotation_str, str):
|
|
83
|
+
return
|
|
84
|
+
|
|
85
|
+
if DBG:
|
|
86
|
+
log.debug(f"[visitor] parsing string annotation {annotation_str!r} "
|
|
87
|
+
f"in {self.filename}:{getattr(self, 'line', '?')}")
|
|
88
|
+
|
|
77
89
|
try:
|
|
78
|
-
parsed = ast.parse(annotation_str, mode=
|
|
90
|
+
parsed = ast.parse(annotation_str, mode="eval")
|
|
79
91
|
self.visit(parsed.body)
|
|
80
|
-
except:
|
|
81
|
-
|
|
92
|
+
except Exception:
|
|
93
|
+
if DBG:
|
|
94
|
+
log.debug("[visitor] inner-annotation parse failed:\n" +
|
|
95
|
+
traceback.format_exc())
|
|
96
|
+
# keep going but dont swallow symbol names:
|
|
97
|
+
for tok in re.findall(r"[A-Za-z_][A-Za-z0-9_]*", annotation_str):
|
|
98
|
+
self.add_ref(tok)
|
|
82
99
|
|
|
83
100
|
def visit_Import(self,node):
|
|
84
101
|
for a in node.names:
|
|
@@ -250,6 +267,11 @@ class Visitor(ast.NodeVisitor):
|
|
|
250
267
|
if module_name != "self":
|
|
251
268
|
qualified_name = f"{self.qual(module_name)}.{attr_name}"
|
|
252
269
|
self.add_ref(qualified_name)
|
|
270
|
+
|
|
271
|
+
elif isinstance(node.args[0], ast.Name):
|
|
272
|
+
target_name = node.args[0].id
|
|
273
|
+
if target_name != "self":
|
|
274
|
+
self.dyn.add(self.mod.split(".")[0] if self.mod else "")
|
|
253
275
|
|
|
254
276
|
elif isinstance(node.func, ast.Name) and node.func.id == "globals":
|
|
255
277
|
parent = getattr(node, 'parent', None)
|
|
@@ -259,6 +281,9 @@ class Visitor(ast.NodeVisitor):
|
|
|
259
281
|
func_name = parent.slice.value
|
|
260
282
|
self.add_ref(func_name)
|
|
261
283
|
self.add_ref(f"{self.mod}.{func_name}")
|
|
284
|
+
|
|
285
|
+
elif isinstance(node.func, ast.Name) and node.func.id in ("eval", "exec"):
|
|
286
|
+
self.dyn.add(self.mod.split(".")[0] if self.mod else "")
|
|
262
287
|
|
|
263
288
|
def visit_Name(self,node):
|
|
264
289
|
if isinstance(node.ctx,ast.Load):
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
skylos/__init__.py,sha256=ZZWhq0TZ3G-yDi9inbYvMn8OBes-pqo1aYB5EivuxFI,152
|
|
2
|
+
skylos/analyzer.py,sha256=zbWheTzHGbgfwbW0Z2euQyca1dDZL4BPscIHvAMVkME,15079
|
|
3
|
+
skylos/cli.py,sha256=6udZY4vLU6PFzVMkaiCLCRcLXgquyHdmf4rIOAPosWc,18266
|
|
4
|
+
skylos/constants.py,sha256=F1kMjuTxfw2hJjd0SeOQcgex5WhHMUhXCzOlVmwuACs,1230
|
|
5
|
+
skylos/framework_aware.py,sha256=p7BGoFnzkpaLJoE3M5qgyIeZvXx17tOkdyXgeqGKmqU,5804
|
|
6
|
+
skylos/test_aware.py,sha256=cduaWMcFsuzIEQWAMFPC58xGk8NUU3SbUS0ChRPedv8,2372
|
|
7
|
+
skylos/visitor.py,sha256=MnWyzs0b2JOD2Nj1Iu7ZIZHCr7fRC92PY1bsT8bdgXg,12796
|
|
8
|
+
test/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
9
|
+
test/compare_tools.py,sha256=0g9PDeJlbst-7hOaQzrL4MiJFQKpqM8q8VeBGzpPczg,22738
|
|
10
|
+
test/conftest.py,sha256=57sTF6vLL5U0CVKwGQFJcRs6n7t1dEHIriQoSluNmAI,6418
|
|
11
|
+
test/diagnostics.py,sha256=ExuFOCVpc9BDwNYapU96vj9RXLqxji32Sv6wVF4nJYU,13802
|
|
12
|
+
test/test_analyzer.py,sha256=vZ-0cSF_otm7ZYdp6U3a8eWGwRZ6Tf0tVuJxYqcxdqM,22816
|
|
13
|
+
test/test_changes_analyzer.py,sha256=l1hspCFz-sF8gqOilJvntUDuGckwhYsVtzvSRB13ZWw,5085
|
|
14
|
+
test/test_cli.py,sha256=rtdKzanDRJT_F92jKkCQFdhvlfwVJxfXKO8Hrbn-mIg,13180
|
|
15
|
+
test/test_constants.py,sha256=pMuDy0UpC81zENMDCeK6Bqmm3BR_HHZQSlMG-9TgOm0,12602
|
|
16
|
+
test/test_framework_aware.py,sha256=tJ7bnhiGeSdsAvrWaGJO5ovTrw9n9BBk6o1HCw15yDA,11693
|
|
17
|
+
test/test_integration.py,sha256=bNKGUe-w0xEZEdnoQNHbssvKMGs9u9fmFQTOz1lX9_k,12398
|
|
18
|
+
test/test_skylos.py,sha256=kz77STrS4k3Eez5RDYwGxOg2WH3e7zNZPUYEaTLbGTs,15608
|
|
19
|
+
test/test_test_aware.py,sha256=VmbR_MQY0m941CAxxux8OxJHIr7l8crfWRouSeBMhIo,9390
|
|
20
|
+
test/test_visitor.py,sha256=xAbGv-XaozKm_0WJJhr0hMb6mLaJcbPz57G9-SWkxFU,22764
|
|
21
|
+
test/sample_repo/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
22
|
+
test/sample_repo/app.py,sha256=M5XgoAn-LPz50mKAj_ZacRKf-Pg7I4HbjWP7Z9jE4a0,226
|
|
23
|
+
test/sample_repo/sample_repo/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
24
|
+
test/sample_repo/sample_repo/commands.py,sha256=b6gQ9YDabt2yyfqGbOpLo0osF7wya8O4Lm7m8gtCr3g,2575
|
|
25
|
+
test/sample_repo/sample_repo/models.py,sha256=xXIg3pToEZwKuUCmKX2vTlCF_VeFA0yZlvlBVPIy5Qw,3320
|
|
26
|
+
test/sample_repo/sample_repo/routes.py,sha256=8yITrt55BwS01G7nWdESdx8LuxmReqop1zrGUKPeLi8,2475
|
|
27
|
+
test/sample_repo/sample_repo/utils.py,sha256=S56hEYh8wkzwsD260MvQcmUFOkw2EjFU27nMLFE6G2k,1103
|
|
28
|
+
skylos-1.2.1.dist-info/METADATA,sha256=DY1_WEnwZbz1xpWVbV7WwRRmxPqg8pVdS8DlTWs62Sc,224
|
|
29
|
+
skylos-1.2.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
30
|
+
skylos-1.2.1.dist-info/entry_points.txt,sha256=zzRpN2ByznlQoLeuLolS_TFNYSQxUGBL1EXQsAd6bIA,43
|
|
31
|
+
skylos-1.2.1.dist-info/top_level.txt,sha256=f8GA_7KwfaEopPMP8-EXDQXaqd4IbsOQPakZy01LkdQ,12
|
|
32
|
+
skylos-1.2.1.dist-info/RECORD,,
|