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/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='eval')
90
+ parsed = ast.parse(annotation_str, mode="eval")
79
91
  self.visit(parsed.body)
80
- except:
81
- pass
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):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: skylos
3
- Version: 1.1.12
3
+ Version: 1.2.1
4
4
  Summary: A static analysis tool for Python codebases
5
5
  Author-email: oha <aaronoh2015@gmail.com>
6
6
  Requires-Python: >=3.9
@@ -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,,