skylos 1.1.11__py3-none-any.whl → 1.1.12__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 CHANGED
@@ -3,29 +3,15 @@ import ast,sys,json,logging,re
3
3
  from pathlib import Path
4
4
  from collections import defaultdict
5
5
  from skylos.visitor import Visitor
6
+ from skylos.constants import (
7
+ AUTO_CALLED, TEST_METHOD_PATTERN, MAGIC_METHODS,
8
+ TEST_LIFECYCLE_METHODS, TEST_IMPORT_PATTERNS, TEST_DECORATORS,
9
+ DEFAULT_EXCLUDE_FOLDERS
10
+ )
6
11
 
7
12
  logging.basicConfig(level=logging.INFO,format='%(asctime)s - %(levelname)s - %(message)s')
8
13
  logger=logging.getLogger('Skylos')
9
14
 
10
- AUTO_CALLED={"__init__","__enter__","__exit__"}
11
- TEST_METHOD_PATTERN = re.compile(r"^test_\w+$")
12
- MAGIC_METHODS={f"__{n}__"for n in["init","new","call","getattr","getattribute","enter","exit","str","repr","hash","eq","ne","lt","gt","le","ge","iter","next","contains","len","getitem","setitem","delitem","iadd","isub","imul","itruediv","ifloordiv","imod","ipow","ilshift","irshift","iand","ixor","ior","round","format","dir","abs","complex","int","float","bool","bytes","reduce","await","aiter","anext","add","sub","mul","truediv","floordiv","mod","divmod","pow","lshift","rshift","and","or","xor","radd","rsub","rmul","rtruediv","rfloordiv","rmod","rdivmod","rpow","rlshift","rrshift","rand","ror","rxor"]}
13
-
14
- DEFAULT_EXCLUDE_FOLDERS = {
15
- "__pycache__",
16
- ".git",
17
- ".pytest_cache",
18
- ".mypy_cache",
19
- ".tox",
20
- "htmlcov",
21
- ".coverage",
22
- "build",
23
- "dist",
24
- "*.egg-info",
25
- "venv",
26
- ".venv"
27
- }
28
-
29
15
  def parse_exclude_folders(user_exclude_folders, use_defaults=True, include_folders=None):
30
16
  exclude_set = set()
31
17
 
@@ -156,7 +142,79 @@ class Skylos:
156
142
  return class_def.base_classes
157
143
 
158
144
  return []
145
+
146
+ def _has_test_imports(self, file_path):
147
+ try:
148
+ with open(file_path, 'r', encoding='utf-8') as f:
149
+ content = f.read()
150
+
151
+ for test_import in TEST_IMPORT_PATTERNS:
152
+ if f"import {test_import}" in content or f"from {test_import}" in content:
153
+ return True
154
+
155
+ return False
156
+ except:
157
+ return False
158
+
159
+ def _is_test_file(self, file_path):
160
+ """check if file locs indicates its a test file"""
161
+ file_str = str(file_path).lower()
162
+
163
+ if (file_str.endswith("test.py") or
164
+ file_str.endswith("_test.py") or
165
+ "test_" in file_str or
166
+ "/test/" in file_str or
167
+ "/tests/" in file_str or
168
+ "\\test\\" in file_str or
169
+ "\\tests\\" in file_str):
170
+ return True
171
+
172
+ return False
173
+
174
+ def _has_test_decorators(self, file_path):
175
+ """Check if file uses test-related decorators"""
176
+ try:
177
+ with open(file_path, 'r', encoding='utf-8') as f:
178
+ content = f.read()
179
+
180
+ for decorator in TEST_DECORATORS:
181
+ if f"@{decorator}" in content:
182
+ return True
183
+
184
+ return False
185
+ except:
186
+ return False
187
+
188
+ def _is_test_related(self, definition):
189
+
190
+ if "." in definition.name:
191
+ class_name = definition.name.rsplit(".", 1)[0]
192
+ class_simple_name = class_name.split(".")[-1]
159
193
 
194
+ if (class_simple_name.startswith("Test") or
195
+ class_simple_name.endswith("Test") or
196
+ class_simple_name.endswith("TestCase")):
197
+ return True
198
+
199
+ if (definition.type == "method" and
200
+ (TEST_METHOD_PATTERN.match(definition.simple_name) or
201
+ definition.simple_name in TEST_LIFECYCLE_METHODS)):
202
+ return True
203
+
204
+ # NOT for imports, variables, parameters
205
+ if definition.type in ("function", "method", "class"):
206
+ if self._is_test_file(definition.filename):
207
+ return True
208
+
209
+ if self._has_test_imports(definition.filename):
210
+ return True
211
+
212
+ ## check decorators -- test related
213
+ if self._has_test_decorators(definition.filename):
214
+ return True
215
+
216
+ return False
217
+
160
218
  def _apply_heuristics(self):
161
219
  class_methods=defaultdict(list)
162
220
  for d in self.defs.values():
@@ -180,6 +238,16 @@ class Skylos:
180
238
  if d.type != "parameter" and (d.simple_name in MAGIC_METHODS or (d.simple_name.startswith("__") and d.simple_name.endswith("__"))):
181
239
  d.confidence = 0
182
240
 
241
+ if (d.type == "import" and d.name.startswith("__future__.") and
242
+ d.simple_name in ("annotations", "absolute_import", "division",
243
+ "print_function", "unicode_literals", "generator_stop")):
244
+ d.confidence = 0
245
+
246
+ if (d.simple_name.startswith("_") and
247
+ not d.simple_name.startswith("__") and
248
+ d.simple_name != "_"):
249
+ d.confidence = 0
250
+
183
251
  if not d.simple_name.startswith("_") and d.type in ("function", "method", "class"):
184
252
  d.confidence = min(d.confidence, 90)
185
253
 
@@ -192,13 +260,8 @@ class Skylos:
192
260
  if d.type == "variable" and d.simple_name == "_":
193
261
  d.confidence = 0
194
262
 
195
- if d.type == "method" and TEST_METHOD_PATTERN.match(d.simple_name):
196
- class_name = d.name.rsplit(".", 1)[0]
197
- class_simple_name = class_name.split(".")[-1]
198
- if (class_simple_name.startswith("Test") or
199
- class_simple_name.endswith("Test") or
200
- class_simple_name.endswith("TestCase")):
201
- d.confidence = 0
263
+ if self._is_test_related(d):
264
+ d.confidence = 0
202
265
 
203
266
  def analyze(self, path, thr=60, exclude_folders=None):
204
267
 
skylos/constants.py ADDED
@@ -0,0 +1,35 @@
1
+ import re
2
+
3
+ AUTO_CALLED={"__init__","__enter__","__exit__"}
4
+ TEST_METHOD_PATTERN = re.compile(r"^test_\w+$")
5
+ MAGIC_METHODS={f"__{n}__"for n in["init","new","call","getattr","getattribute","enter","exit","str","repr","hash","eq","ne","lt","gt","le","ge","iter","next","contains","len","getitem","setitem","delitem","iadd","isub","imul","itruediv","ifloordiv","imod","ipow","ilshift","irshift","iand","ixor","ior","round","format","dir","abs","complex","int","float","bool","bytes","reduce","await","aiter","anext","add","sub","mul","truediv","floordiv","mod","divmod","pow","lshift","rshift","and","or","xor","radd","rsub","rmul","rtruediv","rfloordiv","rmod","rdivmod","rpow","rlshift","rrshift","rand","ror","rxor"]}
6
+ TEST_LIFECYCLE_METHODS = {
7
+ "setUp", "tearDown", "setUpClass", "tearDownClass",
8
+ "setUpModule", "tearDownModule", "setup_method", "teardown_method",
9
+ "setup_class", "teardown_class", "setup_function", "teardown_function"
10
+ }
11
+ TEST_IMPORT_PATTERNS = {
12
+ "unittest", "unittest.mock", "mock", "pytest", "nose", "nose2",
13
+ "responses", "requests_mock", "freezegun", "factory_boy",
14
+ "hypothesis", "sure", "expects", "testfixtures", "faker"
15
+ }
16
+
17
+ TEST_DECORATORS = {
18
+ "patch", "mock", "pytest.fixture", "pytest.mark", "given",
19
+ "responses.activate", "freeze_time", "patch.object", "patch.dict"
20
+ }
21
+
22
+ DEFAULT_EXCLUDE_FOLDERS = {
23
+ "__pycache__",
24
+ ".git",
25
+ ".pytest_cache",
26
+ ".mypy_cache",
27
+ ".tox",
28
+ "htmlcov",
29
+ ".coverage",
30
+ "build",
31
+ "dist",
32
+ "*.egg-info",
33
+ "venv",
34
+ ".venv"
35
+ }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: skylos
3
- Version: 1.1.11
3
+ Version: 1.1.12
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,6 +1,7 @@
1
1
  skylos/__init__.py,sha256=ZZWhq0TZ3G-yDi9inbYvMn8OBes-pqo1aYB5EivuxFI,152
2
- skylos/analyzer.py,sha256=sXLvtJ3AB946HWV9JpDiWJ4-qwcT1cKRTA3TVTx2VNU,13117
2
+ skylos/analyzer.py,sha256=r3Em6cHSUY1xEwOfQjHbtqLC9vfPwRrwZxN6HrPfRCk,15012
3
3
  skylos/cli.py,sha256=7lcRFc3zailK2cPCWk6yT-EF0oeY_CmBo6TyD5m6c5Y,17355
4
+ skylos/constants.py,sha256=xv4BAYWS5R48nA3n_PiZtYQNqBJHS42QVIBSpxl3ZuQ,1538
4
5
  skylos/visitor.py,sha256=0h07CNS6RnWi3vMjWO0sexzePRXIAfPjQib8Qxu11oY,11740
5
6
  test/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
7
  test/compare_tools.py,sha256=0g9PDeJlbst-7hOaQzrL4MiJFQKpqM8q8VeBGzpPczg,22738
@@ -18,8 +19,8 @@ test/sample_repo/sample_repo/commands.py,sha256=b6gQ9YDabt2yyfqGbOpLo0osF7wya8O4
18
19
  test/sample_repo/sample_repo/models.py,sha256=xXIg3pToEZwKuUCmKX2vTlCF_VeFA0yZlvlBVPIy5Qw,3320
19
20
  test/sample_repo/sample_repo/routes.py,sha256=8yITrt55BwS01G7nWdESdx8LuxmReqop1zrGUKPeLi8,2475
20
21
  test/sample_repo/sample_repo/utils.py,sha256=S56hEYh8wkzwsD260MvQcmUFOkw2EjFU27nMLFE6G2k,1103
21
- skylos-1.1.11.dist-info/METADATA,sha256=LUAqpC_E7ouGZxVtjyFa1LEXrTfV8MOyrQGRnDLnHYM,225
22
- skylos-1.1.11.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
23
- skylos-1.1.11.dist-info/entry_points.txt,sha256=zzRpN2ByznlQoLeuLolS_TFNYSQxUGBL1EXQsAd6bIA,43
24
- skylos-1.1.11.dist-info/top_level.txt,sha256=f8GA_7KwfaEopPMP8-EXDQXaqd4IbsOQPakZy01LkdQ,12
25
- skylos-1.1.11.dist-info/RECORD,,
22
+ skylos-1.1.12.dist-info/METADATA,sha256=a99JTCI1FND6v_6OPumg5O8A1lvMqBTiAcGiQ1T4CEc,225
23
+ skylos-1.1.12.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
24
+ skylos-1.1.12.dist-info/entry_points.txt,sha256=zzRpN2ByznlQoLeuLolS_TFNYSQxUGBL1EXQsAd6bIA,43
25
+ skylos-1.1.12.dist-info/top_level.txt,sha256=f8GA_7KwfaEopPMP8-EXDQXaqd4IbsOQPakZy01LkdQ,12
26
+ skylos-1.1.12.dist-info/RECORD,,