skylos 1.0.9__tar.gz → 1.0.10__tar.gz
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-1.0.9 → skylos-1.0.10}/PKG-INFO +1 -1
- {skylos-1.0.9 → skylos-1.0.10}/pyproject.toml +1 -1
- {skylos-1.0.9 → skylos-1.0.10}/setup.py +1 -1
- {skylos-1.0.9 → skylos-1.0.10}/skylos/__init__.py +1 -1
- {skylos-1.0.9 → skylos-1.0.10}/skylos/analyzer.py +76 -16
- {skylos-1.0.9 → skylos-1.0.10}/skylos.egg-info/PKG-INFO +1 -1
- {skylos-1.0.9 → skylos-1.0.10}/README.md +0 -0
- {skylos-1.0.9 → skylos-1.0.10}/setup.cfg +0 -0
- {skylos-1.0.9 → skylos-1.0.10}/skylos/cli.py +0 -0
- {skylos-1.0.9 → skylos-1.0.10}/skylos/visitor.py +0 -0
- {skylos-1.0.9 → skylos-1.0.10}/skylos.egg-info/SOURCES.txt +0 -0
- {skylos-1.0.9 → skylos-1.0.10}/skylos.egg-info/dependency_links.txt +0 -0
- {skylos-1.0.9 → skylos-1.0.10}/skylos.egg-info/entry_points.txt +0 -0
- {skylos-1.0.9 → skylos-1.0.10}/skylos.egg-info/requires.txt +0 -0
- {skylos-1.0.9 → skylos-1.0.10}/skylos.egg-info/top_level.txt +0 -0
- {skylos-1.0.9 → skylos-1.0.10}/test/__init__.py +0 -0
- {skylos-1.0.9 → skylos-1.0.10}/test/compare_tools.py +0 -0
- {skylos-1.0.9 → skylos-1.0.10}/test/diagnostics.py +0 -0
- {skylos-1.0.9 → skylos-1.0.10}/test/sample_repo/__init__.py +0 -0
- {skylos-1.0.9 → skylos-1.0.10}/test/sample_repo/app.py +0 -0
- {skylos-1.0.9 → skylos-1.0.10}/test/sample_repo/sample_repo/__init__.py +0 -0
- {skylos-1.0.9 → skylos-1.0.10}/test/sample_repo/sample_repo/commands.py +0 -0
- {skylos-1.0.9 → skylos-1.0.10}/test/sample_repo/sample_repo/models.py +0 -0
- {skylos-1.0.9 → skylos-1.0.10}/test/sample_repo/sample_repo/routes.py +0 -0
- {skylos-1.0.9 → skylos-1.0.10}/test/sample_repo/sample_repo/utils.py +0 -0
- {skylos-1.0.9 → skylos-1.0.10}/test/test_skylos.py +0 -0
- {skylos-1.0.9 → skylos-1.0.10}/test/test_visitor.py +0 -0
|
@@ -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("__"):
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
if d.
|
|
104
|
-
|
|
105
|
-
|
|
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 = {
|
|
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
|
-
|
|
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"")
|
|
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]")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|