skylos 1.2.2__py3-none-any.whl → 2.0.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/visitor.py CHANGED
@@ -7,22 +7,25 @@ DBG = bool(int(os.getenv("SKYLOS_DEBUG", "0")))
7
7
  log = logging.getLogger("Skylos")
8
8
 
9
9
 
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"}
11
- DYNAMIC_PATTERNS={"getattr","globals","eval","exec"}
10
+ PYTHON_BUILTINS={"print", "len", "str", "int", "float", "list", "dict", "set", "tuple", "range", "open",
11
+ "super", "object", "type", "enumerate", "zip", "map", "filter", "sorted", "sum", "min",
12
+ "next", "iter", "bytes", "bytearray", "format", "round", "abs", "complex", "hash", "id", "bool", "callable",
13
+ "getattr", "max", "all", "any", "setattr", "hasattr", "isinstance", "globals", "locals",
14
+ "vars", "dir" ,"property", "classmethod", "staticmethod"}
15
+ DYNAMIC_PATTERNS={"getattr", "globals", "eval", "exec"}
12
16
 
13
17
  class Definition:
14
- __slots__ = ('name', 'type', 'filename', 'line', 'simple_name', 'confidence', 'references', 'is_exported', 'in_init')
15
18
 
16
- def __init__(self, n, t, f, l):
17
- self.name = n
19
+ def __init__(self, name, t, filename, line):
20
+ self.name = name
18
21
  self.type = t
19
- self.filename = f
20
- self.line = l
21
- self.simple_name = n.split('.')[-1]
22
+ self.filename = filename
23
+ self.line = line
24
+ self.simple_name = name.split('.')[-1]
22
25
  self.confidence = 100
23
26
  self.references = 0
24
27
  self.is_exported = False
25
- self.in_init = "__init__.py" in str(f)
28
+ self.in_init = "__init__.py" in str(filename)
26
29
 
27
30
  def to_dict(self):
28
31
  if self.type == "method" and "." in self.name:
@@ -48,26 +51,30 @@ class Definition:
48
51
 
49
52
  class Visitor(ast.NodeVisitor):
50
53
  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
- def add_def(self,n,t,l):
63
- if n not in{d.name for d in self.defs}:self.defs.append(Definition(n,t,self.file,l))
64
-
65
- def add_ref(self,n):self.refs.append((n,self.file))
66
-
67
- def qual(self,n):
68
- if n in self.alias:return self.alias[n]
69
- if n in PYTHON_BUILTINS:return n
70
- return f"{self.mod}.{n}"if self.mod else n
54
+ self.mod= mod
55
+ self.file= file
56
+ self.defs= []
57
+ self.refs= []
58
+ self.cls= None
59
+ self.alias= {}
60
+ self.dyn= set()
61
+ self.exports= set()
62
+ self.current_function_scope= []
63
+ self.current_function_params= []
64
+
65
+ def add_def(self, name, t, line):
66
+ if name not in {d.name for d in self.defs}:
67
+ self.defs.append(Definition(name, t, self.file, line))
68
+
69
+ def add_ref(self, name):
70
+ self.refs.append((name, self.file))
71
+
72
+ def qual(self, name):
73
+ if name in self.alias:
74
+ return self.alias[name]
75
+ if name in PYTHON_BUILTINS:
76
+ return name
77
+ return f"{self.mod}.{name}" if self.mod else name
71
78
 
72
79
  def visit_annotation(self, node):
73
80
  if node is not None:
@@ -83,24 +90,23 @@ class Visitor(ast.NodeVisitor):
83
90
  return
84
91
 
85
92
  if DBG:
86
- log.debug(f"[visitor] parsing string annotation {annotation_str!r} "
87
- f"in {self.filename}:{getattr(self, 'line', '?')}")
93
+ log.debug(f"parsing annotation: {annotation_str}")
94
+
88
95
 
89
96
  try:
90
97
  parsed = ast.parse(annotation_str, mode="eval")
91
98
  self.visit(parsed.body)
92
- except Exception:
99
+ except:
93
100
  if DBG:
94
- log.debug("[visitor] inner-annotation parse failed:\n" +
95
- traceback.format_exc())
96
- # keep going but dont swallow symbol names:
101
+ if DBG: log.debug("annotation parse failed")
102
+
97
103
  for tok in re.findall(r"[A-Za-z_][A-Za-z0-9_]*", annotation_str):
98
104
  self.add_ref(tok)
99
105
 
100
- def visit_Import(self,node):
106
+ def visit_Import(self, node):
101
107
  for a in node.names:
102
- full=a.name
103
- self.alias[a.asname or a.name.split(".")[-1]]=full
108
+ full= a.name
109
+ self.alias[a.asname or a.name.split(".")[-1]]= full
104
110
  self.add_def(full,"import",node.lineno)
105
111
 
106
112
  def visit_ImportFrom(self, node):
@@ -127,6 +133,7 @@ class Visitor(ast.NodeVisitor):
127
133
  self.visit_annotation(arg.annotation)
128
134
  for arg in args.posonlyargs:
129
135
  self.visit_annotation(arg.annotation)
136
+
130
137
  for arg in args.kwonlyargs:
131
138
  self.visit_annotation(arg.annotation)
132
139
  if args.vararg:
@@ -143,11 +150,11 @@ class Visitor(ast.NodeVisitor):
143
150
  outer_scope_prefix = '.'.join(self.current_function_scope) + '.' if self.current_function_scope else ''
144
151
 
145
152
  if self.cls:
146
- name_parts = [self.mod, self.cls, outer_scope_prefix + node.name]
153
+ name_parts= [self.mod, self.cls, outer_scope_prefix + node.name]
147
154
  else:
148
- name_parts = [self.mod, outer_scope_prefix + node.name]
155
+ name_parts= [self.mod, outer_scope_prefix + node.name]
149
156
 
150
- qualified_name = ".".join(filter(None, name_parts))
157
+ qualified_name= ".".join(filter(None, name_parts))
151
158
 
152
159
  self.add_def(qualified_name,"method"if self.cls else"function",node.lineno)
153
160
 
@@ -173,11 +180,11 @@ class Visitor(ast.NodeVisitor):
173
180
  self.current_function_scope.pop()
174
181
  self.current_function_params = old_params
175
182
 
176
- visit_AsyncFunctionDef=visit_FunctionDef
183
+ visit_AsyncFunctionDef= visit_FunctionDef
177
184
 
178
- def visit_ClassDef(self,node):
179
- cname=f"{self.mod}.{node.name}"
180
- self.add_def(cname,"class",node.lineno)
185
+ def visit_ClassDef(self, node):
186
+ cname =f"{self.mod}.{node.name}"
187
+ self.add_def(cname, "class",node.lineno)
181
188
 
182
189
  for base in node.bases:
183
190
  self.visit(base)
@@ -186,9 +193,13 @@ class Visitor(ast.NodeVisitor):
186
193
  for decorator in node.decorator_list:
187
194
  self.visit(decorator)
188
195
 
189
- prev=self.cls;self.cls=node.name
190
- for b in node.body:self.visit(b)
191
- self.cls=prev
196
+ prev= self.cls
197
+
198
+ self.cls= node.name
199
+ for b in node.body:
200
+ self.visit(b)
201
+
202
+ self.cls= prev
192
203
 
193
204
  def visit_AnnAssign(self, node):
194
205
  self.visit_annotation(node.annotation)
@@ -215,20 +226,22 @@ class Visitor(ast.NodeVisitor):
215
226
  def visit_Assign(self, node):
216
227
  def process_target_for_def(target_node):
217
228
  if isinstance(target_node, ast.Name):
218
- var_name_simple = target_node.id
219
- if var_name_simple == "__all__" and not self.current_function_scope and not self.cls:
229
+ name_simple = target_node.id
230
+ if name_simple == "__all__" and not self.current_function_scope and not self.cls:
220
231
  return
221
232
 
222
233
  scope_parts = [self.mod]
234
+
223
235
  if self.cls:
224
236
  scope_parts.append(self.cls)
237
+
225
238
  if self.current_function_scope:
226
239
  scope_parts.extend(self.current_function_scope)
227
240
 
228
241
  prefix = '.'.join(filter(None, scope_parts))
229
- qualified_var_name = f"{prefix}.{var_name_simple}" if prefix else var_name_simple
242
+ var_name = f"{prefix}.{name_simple}" if prefix else name_simple
230
243
 
231
- self.add_def(qualified_var_name, "variable", target_node.lineno)
244
+ self.add_def(var_name, "variable", target_node.lineno)
232
245
 
233
246
  elif isinstance(target_node, (ast.Tuple, ast.List)):
234
247
  for elt in target_node.elts:
@@ -248,8 +261,8 @@ class Visitor(ast.NodeVisitor):
248
261
  value = elt.s
249
262
 
250
263
  if value is not None:
251
- full_name_export = f"{self.mod}.{value}" if self.mod else value
252
- self.add_ref(full_name_export)
264
+ export_name = f"{self.mod}.{value}" if self.mod else value
265
+ self.add_ref(export_name)
253
266
  self.add_ref(value)
254
267
 
255
268
  self.generic_visit(node)
@@ -285,12 +298,13 @@ class Visitor(ast.NodeVisitor):
285
298
  elif isinstance(node.func, ast.Name) and node.func.id in ("eval", "exec"):
286
299
  self.dyn.add(self.mod.split(".")[0] if self.mod else "")
287
300
 
288
- def visit_Name(self,node):
289
- if isinstance(node.ctx,ast.Load):
301
+ def visit_Name(self, node):
302
+ if isinstance(node.ctx, ast.Load):
290
303
  for param_name, param_full_name in self.current_function_params:
291
304
  if node.id == param_name:
292
305
  self.add_ref(param_full_name)
293
306
  break
307
+
294
308
  else:
295
309
  # not parameter, handle normally
296
310
  qualified = self.qual(node.id)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: skylos
3
- Version: 1.2.2
3
+ Version: 2.0.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
@@ -1,10 +1,11 @@
1
- skylos/__init__.py,sha256=ZZWhq0TZ3G-yDi9inbYvMn8OBes-pqo1aYB5EivuxFI,152
2
- skylos/analyzer.py,sha256=cO6J-hOsdJLoyw2vkL2BdX_fS-i5R50suLuh1QqPly4,15144
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
1
+ skylos/__init__.py,sha256=xIvJTzzvvgfcQWYMckJFXNNlXPpU1gjO1IldPy7T_N4,151
2
+ skylos/analyzer.py,sha256=TDr_szli65cuQWD6BUcQCUFleM1R-QZD0uRUoHlU6As,14145
3
+ skylos/cli.py,sha256=Xqc_vnueic0D39FI0YzMtJObLsn8MqFFCUnY1nrpEt4,18115
4
+ skylos/constants.py,sha256=vAfKls0OuR5idtXzeMDfYv5-wLtYWDe1NW5TSUJT8RI,1636
5
+ skylos/framework_aware.py,sha256=vbZ1CZIL_2TOEkdH8uVSPPihLM2ctqA01zEHL8HG5sw,5768
6
+ skylos/server.py,sha256=5Rlgy3LdE8I5TWRJJh0n19JqhVYaAOc9fUtRjL-PpX8,16270
7
+ skylos/test_aware.py,sha256=kxYoMG2m02kbMlxtFOM-MWJO8qqxHviP9HgAMbKRfvU,2304
8
+ skylos/visitor.py,sha256=FXNck0qjVB3lfp4X63D5-bE1NsvUTbfvT17ivIevhjk,12654
8
9
  test/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
10
  test/compare_tools.py,sha256=0g9PDeJlbst-7hOaQzrL4MiJFQKpqM8q8VeBGzpPczg,22738
10
11
  test/conftest.py,sha256=57sTF6vLL5U0CVKwGQFJcRs6n7t1dEHIriQoSluNmAI,6418
@@ -25,8 +26,8 @@ test/sample_repo/sample_repo/commands.py,sha256=b6gQ9YDabt2yyfqGbOpLo0osF7wya8O4
25
26
  test/sample_repo/sample_repo/models.py,sha256=xXIg3pToEZwKuUCmKX2vTlCF_VeFA0yZlvlBVPIy5Qw,3320
26
27
  test/sample_repo/sample_repo/routes.py,sha256=8yITrt55BwS01G7nWdESdx8LuxmReqop1zrGUKPeLi8,2475
27
28
  test/sample_repo/sample_repo/utils.py,sha256=S56hEYh8wkzwsD260MvQcmUFOkw2EjFU27nMLFE6G2k,1103
28
- skylos-1.2.2.dist-info/METADATA,sha256=2cvKXdg5thOkSpCbaN7jQ3Lwa10jVmVVB6KvDST3ZOw,224
29
- skylos-1.2.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
30
- skylos-1.2.2.dist-info/entry_points.txt,sha256=zzRpN2ByznlQoLeuLolS_TFNYSQxUGBL1EXQsAd6bIA,43
31
- skylos-1.2.2.dist-info/top_level.txt,sha256=f8GA_7KwfaEopPMP8-EXDQXaqd4IbsOQPakZy01LkdQ,12
32
- skylos-1.2.2.dist-info/RECORD,,
29
+ skylos-2.0.0.dist-info/METADATA,sha256=gVlJTPqEjfbbnn0TGbDT5aEx8TBtD1r-mitvOfJBI-Y,224
30
+ skylos-2.0.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
31
+ skylos-2.0.0.dist-info/entry_points.txt,sha256=zzRpN2ByznlQoLeuLolS_TFNYSQxUGBL1EXQsAd6bIA,43
32
+ skylos-2.0.0.dist-info/top_level.txt,sha256=f8GA_7KwfaEopPMP8-EXDQXaqd4IbsOQPakZy01LkdQ,12
33
+ skylos-2.0.0.dist-info/RECORD,,
File without changes