skylos 1.0.9__py3-none-any.whl → 1.0.10__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.
skylos/__init__.py CHANGED
@@ -1,6 +1,6 @@
1
1
  from skylos.analyzer import analyze
2
2
 
3
- __version__ = "1.0.9"
3
+ __version__ = "1.0.10"
4
4
 
5
5
  def debug_test():
6
6
  return "debug-ok"
skylos/analyzer.py CHANGED
@@ -26,7 +26,6 @@ class Skylos:
26
26
  return".".join(p)
27
27
 
28
28
  def _mark_exports(self):
29
-
30
29
  for name, d in self.defs.items():
31
30
  if d.in_init and not d.simple_name.startswith('_'):
32
31
  d.is_exported = True
@@ -71,7 +70,6 @@ class Skylos:
71
70
  d.references += 1
72
71
 
73
72
  def _get_base_classes(self, class_name):
74
- """Get base classes for a given class name"""
75
73
  if class_name not in self.defs:
76
74
  return []
77
75
 
@@ -83,7 +81,6 @@ class Skylos:
83
81
  return []
84
82
 
85
83
  def _apply_heuristics(self):
86
-
87
84
  class_methods=defaultdict(list)
88
85
  for d in self.defs.values():
89
86
  if d.type in("method","function") and"." in d.name:
@@ -97,17 +94,21 @@ class Skylos:
97
94
  if m.simple_name in AUTO_CALLED:m.references+=1
98
95
 
99
96
  for d in self.defs.values():
100
- if d.simple_name in MAGIC_METHODS or d.simple_name.startswith("__")and d.simple_name.endswith("__"):d.confidence=0
101
- if not d.simple_name.startswith("_")and d.type in("function","method","class"):d.confidence=min(d.confidence,90)
102
- if d.in_init and d.type in("function","class"):d.confidence=min(d.confidence,85)
103
- if d.name.split(".")[0] in self.dynamic:d.confidence=min(d.confidence,50)
104
-
105
- for d in self.defs.values():
97
+ if d.simple_name in MAGIC_METHODS or (d.simple_name.startswith("__") and d.simple_name.endswith("__")):
98
+ d.confidence = 0
99
+
100
+ if not d.simple_name.startswith("_") and d.type in ("function", "method", "class"):
101
+ d.confidence = min(d.confidence, 90)
102
+
103
+ if d.in_init and d.type in ("function", "class"):
104
+ d.confidence = min(d.confidence, 85)
105
+
106
+ if d.name.split(".")[0] in self.dynamic:
107
+ d.confidence = min(d.confidence, 60)
108
+
106
109
  if d.type == "method" and TEST_METHOD_PATTERN.match(d.simple_name):
107
- # check if its in a class that inherits from a test base class
108
110
  class_name = d.name.rsplit(".", 1)[0]
109
111
  class_simple_name = class_name.split(".")[-1]
110
- # class name suggests it's a test class, ignore test methods
111
112
  if "Test" in class_simple_name or class_simple_name.endswith("TestCase"):
112
113
  d.confidence = 0
113
114
 
@@ -134,9 +135,6 @@ class Skylos:
134
135
  self._apply_heuristics()
135
136
  self._mark_exports()
136
137
 
137
- # for name, d in self.defs.items():
138
- # print(f" {d.type} '{name}': {d.references} refs, exported: {d.is_exported}, confidence: {d.confidence}")
139
-
140
138
  thr = max(0, thr)
141
139
 
142
140
  unused = []
@@ -144,7 +142,13 @@ class Skylos:
144
142
  if d.references == 0 and not d.is_exported and d.confidence >= thr:
145
143
  unused.append(d.to_dict())
146
144
 
147
- result = {"unused_functions": [], "unused_imports": [], "unused_classes": []}
145
+ result = {
146
+ "unused_functions": [],
147
+ "unused_imports": [],
148
+ "unused_classes": [],
149
+ "unused_variables": []
150
+ }
151
+
148
152
  for u in unused:
149
153
  if u["type"] in ("function", "method"):
150
154
  result["unused_functions"].append(u)
@@ -152,6 +156,8 @@ class Skylos:
152
156
  result["unused_imports"].append(u)
153
157
  elif u["type"] == "class":
154
158
  result["unused_classes"].append(u)
159
+ elif u["type"] == "variable":
160
+ result["unused_variables"].append(u)
155
161
 
156
162
  return json.dumps(result, indent=2)
157
163
 
@@ -175,6 +181,60 @@ def analyze(path,conf=60):return Skylos().analyze(path,conf)
175
181
  if __name__=="__main__":
176
182
  if len(sys.argv)>1:
177
183
  p=sys.argv[1];c=int(sys.argv[2])if len(sys.argv)>2 else 60
178
- print(analyze(p,c))
184
+ result = analyze(p,c)
185
+
186
+ data = json.loads(result)
187
+ print("\n🔍 Python Static Analysis Results")
188
+ print("===================================\n")
189
+
190
+ total_items = sum(len(items) for items in data.values())
191
+
192
+ print("Summary:")
193
+ if data["unused_functions"]:
194
+ print(f" • Unreachable functions: {len(data['unused_functions'])}")
195
+ if data["unused_imports"]:
196
+ print(f" • Unused imports: {len(data['unused_imports'])}")
197
+ if data["unused_classes"]:
198
+ print(f" • Unused classes: {len(data['unused_classes'])}")
199
+ if data["unused_variables"]:
200
+ print(f" • Unused variables: {len(data['unused_variables'])}")
201
+
202
+ if data["unused_functions"]:
203
+ print("\n📦 Unreachable Functions")
204
+ print("=======================")
205
+ for i, func in enumerate(data["unused_functions"], 1):
206
+ print(f" {i}. {func['name']}")
207
+ print(f" └─ {func['file']}:{func['line']}")
208
+
209
+ if data["unused_imports"]:
210
+ print("\n📥 Unused Imports")
211
+ print("================")
212
+ for i, imp in enumerate(data["unused_imports"], 1):
213
+ print(f" {i}. {imp['simple_name']}")
214
+ print(f" └─ {imp['file']}:{imp['line']}")
215
+
216
+ if data["unused_classes"]:
217
+ print("\n📋 Unused Classes")
218
+ print("=================")
219
+ for i, cls in enumerate(data["unused_classes"], 1):
220
+ print(f" {i}. {cls['name']}")
221
+ print(f" └─ {cls['file']}:{cls['line']}")
222
+
223
+ if data["unused_variables"]:
224
+ print("\n📊 Unused Variables")
225
+ print("==================")
226
+ for i, var in enumerate(data["unused_variables"], 1):
227
+ print(f" {i}. {var['name']}")
228
+ print(f" └─ {var['file']}:{var['line']}")
229
+
230
+ print("\n" + "─" * 50)
231
+ print(f"Found {total_items} dead code items. Add this badge to your README:")
232
+ print(f"```markdown")
233
+ print(f"![Dead Code: {total_items}](https://img.shields.io/badge/Dead_Code-{total_items}_detected-orange?logo=codacy&logoColor=red)")
234
+ print(f"```")
235
+
236
+ print("\nNext steps:")
237
+ print(" • Use --interactive to select specific items to remove")
238
+ print(" • Use --dry-run to preview changes before applying them")
179
239
  else:
180
240
  print("Usage: python Skylos.py <path> [confidence_threshold]")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: skylos
3
- Version: 1.0.9
3
+ Version: 1.0.10
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,5 +1,5 @@
1
- skylos/__init__.py,sha256=-Lq8D8LCAJ2XInTPVDyUUxehIExbEV1yHmmEyQcd_3U,151
2
- skylos/analyzer.py,sha256=EtL0IIw1NYzdGpXiOFQk4SXTSuTayVGpmGi0mZXL_Hk,7347
1
+ skylos/__init__.py,sha256=U8NngtBsmaUGNLstSCYzDjfSCT1KyFOKExYRX7VmZfw,152
2
+ skylos/analyzer.py,sha256=1joG0Ek3jNj7qv7w3gFiNeb2BD8CXgX5PF6fVc_HIG4,9710
3
3
  skylos/cli.py,sha256=l-qfaC0RUH2L9YgjlMOvlQrCPD5hcV3McHIk1az-CI4,13525
4
4
  skylos/visitor.py,sha256=uHNHKf7Kf8Qg1sIa-PsH2NHCQD6R9Bd_NELs-41deE8,9339
5
5
  test/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -14,8 +14,8 @@ test/sample_repo/sample_repo/commands.py,sha256=b6gQ9YDabt2yyfqGbOpLo0osF7wya8O4
14
14
  test/sample_repo/sample_repo/models.py,sha256=xXIg3pToEZwKuUCmKX2vTlCF_VeFA0yZlvlBVPIy5Qw,3320
15
15
  test/sample_repo/sample_repo/routes.py,sha256=8yITrt55BwS01G7nWdESdx8LuxmReqop1zrGUKPeLi8,2475
16
16
  test/sample_repo/sample_repo/utils.py,sha256=S56hEYh8wkzwsD260MvQcmUFOkw2EjFU27nMLFE6G2k,1103
17
- skylos-1.0.9.dist-info/METADATA,sha256=snCs-osdKIbaJMErLmo7iIbX2mBkbFUxqY_FXZTWNuY,224
18
- skylos-1.0.9.dist-info/WHEEL,sha256=Nw36Djuh_5VDukK0H78QzOX-_FQEo6V37m3nkm96gtU,91
19
- skylos-1.0.9.dist-info/entry_points.txt,sha256=zzRpN2ByznlQoLeuLolS_TFNYSQxUGBL1EXQsAd6bIA,43
20
- skylos-1.0.9.dist-info/top_level.txt,sha256=f8GA_7KwfaEopPMP8-EXDQXaqd4IbsOQPakZy01LkdQ,12
21
- skylos-1.0.9.dist-info/RECORD,,
17
+ skylos-1.0.10.dist-info/METADATA,sha256=iVIhmRsXWo0WPlMjYVrZpsi2mUVdEbKYrXDvOW4hbIk,225
18
+ skylos-1.0.10.dist-info/WHEEL,sha256=zaaOINJESkSfm_4HQVc5ssNzHCPXhJm0kEUakpsEHaU,91
19
+ skylos-1.0.10.dist-info/entry_points.txt,sha256=zzRpN2ByznlQoLeuLolS_TFNYSQxUGBL1EXQsAd6bIA,43
20
+ skylos-1.0.10.dist-info/top_level.txt,sha256=f8GA_7KwfaEopPMP8-EXDQXaqd4IbsOQPakZy01LkdQ,12
21
+ skylos-1.0.10.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.7.1)
2
+ Generator: setuptools (80.8.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5