skylos 2.0.0__py3-none-any.whl → 2.1.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.

@@ -1,80 +1,60 @@
1
1
  #!/usr/bin/env python3
2
2
  import pytest
3
3
  import ast
4
- from pathlib import Path
5
4
  from unittest.mock import Mock, patch
6
- import fnmatch
7
5
 
8
- try:
9
- from skylos.framework_aware import (
10
- FrameworkAwareVisitor,
6
+ from skylos.framework_aware import (
7
+ FrameworkAwareVisitor,
11
8
  detect_framework_usage,
12
9
  FRAMEWORK_DECORATORS,
13
10
  FRAMEWORK_FUNCTIONS,
14
- FRAMEWORK_IMPORTS
15
- )
16
- except ImportError:
17
- import sys
18
- from pathlib import Path
19
- sys.path.insert(0, str(Path(__file__).parent.parent))
20
- from skylos.framework_aware import (
21
- FrameworkAwareVisitor,
22
- detect_framework_usage,
23
- FRAMEWORK_DECORATORS,
24
- FRAMEWORK_FUNCTIONS,
25
- FRAMEWORK_IMPORTS
11
+ FRAMEWORK_IMPORTS,
26
12
  )
27
13
 
28
14
  class TestFrameworkAwareVisitor:
29
-
30
15
  def test_init_default(self):
31
- """Test default initialization"""
32
- visitor = FrameworkAwareVisitor()
33
- assert visitor.is_framework_file == False
34
- assert visitor.framework_decorated_lines == set()
35
- assert visitor.detected_frameworks == set()
36
-
16
+ v = FrameworkAwareVisitor()
17
+ assert v.is_framework_file is False
18
+ assert v.framework_decorated_lines == set()
19
+ assert v.detected_frameworks == set()
20
+
37
21
  def test_flask_import_detection(self):
38
- """Test Flask import detection"""
39
22
  code = """
40
23
  import flask
41
24
  from flask import Flask, request
42
25
  """
43
26
  tree = ast.parse(code)
44
- visitor = FrameworkAwareVisitor()
45
- visitor.visit(tree)
46
-
47
- assert visitor.is_framework_file == True
48
- assert 'flask' in visitor.detected_frameworks
49
-
27
+ v = FrameworkAwareVisitor()
28
+ v.visit(tree)
29
+ v.finalize()
30
+ assert v.is_framework_file is True
31
+ assert "flask" in v.detected_frameworks
32
+
50
33
  def test_fastapi_import_detection(self):
51
- """Test FastAPI import detection"""
52
34
  code = """
53
35
  from fastapi import FastAPI
54
36
  import fastapi
55
37
  """
56
38
  tree = ast.parse(code)
57
- visitor = FrameworkAwareVisitor()
58
- visitor.visit(tree)
59
-
60
- assert visitor.is_framework_file == True
61
- assert 'fastapi' in visitor.detected_frameworks
62
-
39
+ v = FrameworkAwareVisitor()
40
+ v.visit(tree)
41
+ v.finalize()
42
+ assert v.is_framework_file is True
43
+ assert "fastapi" in v.detected_frameworks
44
+
63
45
  def test_django_import_detection(self):
64
- """Test Django import detection"""
65
46
  code = """
66
47
  from django.http import HttpResponse
67
48
  from django.views import View
68
49
  """
69
50
  tree = ast.parse(code)
70
- visitor = FrameworkAwareVisitor()
71
- visitor.visit(tree)
72
-
73
- assert visitor.is_framework_file == True
74
- assert 'django' in visitor.detected_frameworks
75
-
51
+ v = FrameworkAwareVisitor()
52
+ v.visit(tree)
53
+ v.finalize()
54
+ assert v.is_framework_file is True
55
+ assert "django" in v.detected_frameworks
56
+
76
57
  def test_flask_route_decorator_detection(self):
77
- """Test Flask route decorator detection"""
78
58
  code = """
79
59
  @app.route('/api/users')
80
60
  def get_users():
@@ -85,15 +65,14 @@ def create_user():
85
65
  return {}
86
66
  """
87
67
  tree = ast.parse(code)
88
- visitor = FrameworkAwareVisitor()
89
- visitor.visit(tree)
90
-
91
- assert visitor.is_framework_file == True
92
- assert 3 in visitor.framework_decorated_lines # get_users function
93
- assert 7 in visitor.framework_decorated_lines # create_user function
94
-
68
+ v = FrameworkAwareVisitor()
69
+ v.visit(tree)
70
+ v.finalize()
71
+ assert v.is_framework_file is True
72
+ assert 3 in v.framework_decorated_lines
73
+ assert 7 in v.framework_decorated_lines
74
+
95
75
  def test_fastapi_router_decorator_detection(self):
96
- """Test FastAPI router decorator detection"""
97
76
  code = """
98
77
  @router.get('/items')
99
78
  async def read_items():
@@ -104,15 +83,14 @@ async def create_item():
104
83
  return {}
105
84
  """
106
85
  tree = ast.parse(code)
107
- visitor = FrameworkAwareVisitor()
108
- visitor.visit(tree)
109
-
110
- assert visitor.is_framework_file == True
111
- assert 3 in visitor.framework_decorated_lines
112
- assert 7 in visitor.framework_decorated_lines
113
-
86
+ v = FrameworkAwareVisitor()
87
+ v.visit(tree)
88
+ v.finalize()
89
+ assert v.is_framework_file is True
90
+ assert 3 in v.framework_decorated_lines
91
+ assert 7 in v.framework_decorated_lines
92
+
114
93
  def test_django_decorator_detection(self):
115
- """Test Django decorator detection"""
116
94
  code = """
117
95
  @login_required
118
96
  def protected_view(request):
@@ -123,34 +101,14 @@ def admin_view(request):
123
101
  return HttpResponse("Admin")
124
102
  """
125
103
  tree = ast.parse(code)
126
- visitor = FrameworkAwareVisitor()
127
- visitor.visit(tree)
128
-
129
- assert visitor.is_framework_file == True
130
- assert 3 in visitor.framework_decorated_lines
131
- assert 7 in visitor.framework_decorated_lines
132
-
133
- def test_celery_task_decorator_detection(self):
134
- """Test Celery task decorator detection"""
135
- code = """
136
- @task
137
- def background_task():
138
- return "done"
104
+ v = FrameworkAwareVisitor()
105
+ v.visit(tree)
106
+ v.finalize()
107
+ assert v.is_framework_file is True
108
+ assert 3 in v.framework_decorated_lines
109
+ assert 7 in v.framework_decorated_lines
139
110
 
140
- @shared_task
141
- def shared_background_task():
142
- return "shared done"
143
- """
144
- tree = ast.parse(code)
145
- visitor = FrameworkAwareVisitor()
146
- visitor.visit(tree)
147
-
148
- assert visitor.is_framework_file == True
149
- assert 3 in visitor.framework_decorated_lines
150
- assert 7 in visitor.framework_decorated_lines
151
-
152
111
  def test_django_view_class_detection(self):
153
- """Test Django view class detection"""
154
112
  code = """
155
113
  from django import views
156
114
 
@@ -163,55 +121,29 @@ class UserViewSet(ViewSet):
163
121
  return Response([])
164
122
  """
165
123
  tree = ast.parse(code)
166
- visitor = FrameworkAwareVisitor()
167
- visitor.visit(tree)
168
-
169
- assert visitor.is_framework_file == True
170
- assert 4 in visitor.framework_decorated_lines
171
- assert 8 in visitor.framework_decorated_lines
172
-
173
- def test_django_model_methods_in_framework_file(self):
174
- code = """
175
- from django.db import models
176
-
177
- class User(models.Model):
178
- name = models.CharField(max_length=100)
179
-
180
- def save(self, *args, **kwargs):
181
- # custom save logic
182
- super().save(*args, **kwargs)
183
-
184
- def delete(self, *args, **kwargs):
185
- # custom delete logic
186
- super().delete(*args, **kwargs)
187
- """
188
- tree = ast.parse(code)
189
- visitor = FrameworkAwareVisitor()
190
- visitor.visit(tree)
191
-
192
- assert visitor.is_framework_file == True
193
- assert 7 in visitor.framework_decorated_lines # save method
194
- assert 11 in visitor.framework_decorated_lines # delete method
195
-
124
+ v = FrameworkAwareVisitor()
125
+ v.visit(tree)
126
+ v.finalize()
127
+ assert v.is_framework_file is True
128
+ assert 5 in v.framework_decorated_lines
129
+ assert 9 in v.framework_decorated_lines
130
+
196
131
  def test_framework_functions_not_detected_in_non_framework_file(self):
197
132
  code = """
198
133
  def save(self):
199
- # regular save method, not Django
200
134
  pass
201
135
 
202
136
  def get(self):
203
- # regular get method, not Django view
204
137
  pass
205
138
  """
206
139
  tree = ast.parse(code)
207
- visitor = FrameworkAwareVisitor()
208
- visitor.visit(tree)
209
-
210
- assert visitor.is_framework_file == False
211
- assert visitor.framework_decorated_lines == set()
212
-
140
+ v = FrameworkAwareVisitor()
141
+ v.visit(tree)
142
+ v.finalize()
143
+ assert v.is_framework_file is False
144
+ assert v.framework_decorated_lines == set()
145
+
213
146
  def test_multiple_decorators(self):
214
- """Test function with multiple decorators"""
215
147
  code = """
216
148
  @app.route('/users')
217
149
  @login_required
@@ -220,14 +152,13 @@ def get_users():
220
152
  return []
221
153
  """
222
154
  tree = ast.parse(code)
223
- visitor = FrameworkAwareVisitor()
224
- visitor.visit(tree)
225
-
226
- assert visitor.is_framework_file == True
227
- assert 5 in visitor.framework_decorated_lines
228
-
155
+ v = FrameworkAwareVisitor()
156
+ v.visit(tree)
157
+ v.finalize()
158
+ assert v.is_framework_file is True
159
+ assert 5 in v.framework_decorated_lines
160
+
229
161
  def test_complex_decorator_patterns(self):
230
- """Test complex decorator patterns"""
231
162
  code = """
232
163
  @app.route('/api/v1/users/<int:user_id>', methods=['GET', 'POST'])
233
164
  def user_endpoint(user_id):
@@ -238,135 +169,138 @@ async def get_item(item_id: int):
238
169
  return {}
239
170
  """
240
171
  tree = ast.parse(code)
241
- visitor = FrameworkAwareVisitor()
242
- visitor.visit(tree)
243
-
244
- assert visitor.is_framework_file == True
245
- assert 3 in visitor.framework_decorated_lines
246
- assert 7 in visitor.framework_decorated_lines
247
-
248
- @patch('skylos.framework_aware.Path')
172
+ v = FrameworkAwareVisitor()
173
+ v.visit(tree)
174
+ v.finalize()
175
+ assert v.is_framework_file is True
176
+ assert 3 in v.framework_decorated_lines
177
+ assert 7 in v.framework_decorated_lines
178
+
179
+ @patch("skylos.framework_aware.Path")
249
180
  def test_file_content_framework_detection(self, mock_path):
250
- """Test framework detection from file content"""
251
181
  mock_file = Mock()
252
182
  mock_file.read_text.return_value = "from flask import Flask\napp = Flask(__name__)"
253
183
  mock_path.return_value = mock_file
254
-
255
- visitor = FrameworkAwareVisitor(filename="test.py")
256
-
257
- assert visitor.is_framework_file == True
258
- assert 'flask' in visitor.detected_frameworks
259
-
184
+ v = FrameworkAwareVisitor(filename="test.py")
185
+ v.finalize()
186
+ assert v.is_framework_file is True
187
+ assert "flask" in v.detected_frameworks
188
+
260
189
  def test_normalize_decorator_name(self):
261
- visitor = FrameworkAwareVisitor()
262
-
190
+ v = FrameworkAwareVisitor()
263
191
  node = ast.parse("@decorator\ndef func(): pass").body[0].decorator_list[0]
264
- result = visitor._normalize_decorator(node)
265
- assert result == "@decorator"
266
-
192
+ assert v._normalize_decorator(node) == "@decorator"
267
193
  node = ast.parse("@app.route\ndef func(): pass").body[0].decorator_list[0]
268
- result = visitor._normalize_decorator(node)
269
- assert result == "@app.route"
194
+ assert v._normalize_decorator(node) == "@app.route"
195
+
196
+ def test_depends_marks_dependency_and_flags_framework_file(self):
197
+ code = """
198
+ from fastapi import Depends
199
+
200
+ def dep():
201
+ return 1
202
+
203
+ @router.get("/")
204
+ def foo(x: int = Depends(dep)):
205
+ return {}
206
+ """
207
+ tree = ast.parse(code)
208
+ v = FrameworkAwareVisitor()
209
+ v.visit(tree)
210
+ v.finalize()
211
+ assert v.is_framework_file is True
212
+ assert 4 in v.framework_decorated_lines
213
+
214
+ def test_typed_model_in_route_marks_model_definition(self):
215
+ code = """
216
+ from pydantic import BaseModel
217
+
218
+ class In(BaseModel):
219
+ x: int
220
+
221
+ @router.post("/")
222
+ def calc(req: In):
223
+ return 1
224
+ """
225
+ tree = ast.parse(code)
226
+ v = FrameworkAwareVisitor()
227
+ v.visit(tree)
228
+ v.finalize()
229
+ assert v.is_framework_file is True
230
+ assert 4 in v.framework_decorated_lines
270
231
 
271
232
  class TestDetectFrameworkUsage:
272
-
273
- def test_framework_decorated_function_low_confidence(self):
274
- mock_def = Mock()
275
- mock_def.line = 10
276
- mock_def.simple_name = "get_users"
277
- mock_def.type = "function"
278
-
279
- mock_visitor = Mock()
280
- mock_visitor.framework_decorated_lines = {10}
281
- mock_visitor.is_framework_file = True
282
-
283
- confidence = detect_framework_usage(mock_def, visitor=mock_visitor)
284
- assert confidence == 20
285
-
286
- def test_framework_file_function_medium_confidence(self):
287
- mock_def = Mock()
288
- mock_def.line = 15
289
- mock_def.simple_name = "helper_function"
290
- mock_def.type = "function"
291
-
292
- mock_visitor = Mock()
293
- mock_visitor.framework_decorated_lines = set()
294
- mock_visitor.is_framework_file = True
295
-
296
- confidence = detect_framework_usage(mock_def, visitor=mock_visitor)
297
- assert confidence == 40
298
-
299
- def test_private_function_in_framework_file_no_confidence(self):
300
- mock_def = Mock()
301
- mock_def.line = 20
302
- mock_def.simple_name = "_private_function"
303
- mock_def.type = "function"
304
-
305
- mock_visitor = Mock()
306
- mock_visitor.framework_decorated_lines = set()
307
- mock_visitor.is_framework_file = True
308
-
309
- confidence = detect_framework_usage(mock_def, visitor=mock_visitor)
310
- assert confidence is None
311
-
312
- def test_non_framework_file_no_confidence(self):
313
- mock_def = Mock()
314
- mock_def.line = 25
315
- mock_def.simple_name = "regular_function"
316
- mock_def.type = "function"
317
-
318
- mock_visitor = Mock()
319
- mock_visitor.framework_decorated_lines = set()
320
- mock_visitor.is_framework_file = False
321
-
322
- confidence = detect_framework_usage(mock_def, visitor=mock_visitor)
323
- assert confidence is None
324
-
233
+ def test_decorated_endpoint_confidence_is_one(self):
234
+ d = Mock()
235
+ d.line = 10
236
+ d.simple_name = "get_users"
237
+ d.type = "function"
238
+ v = Mock()
239
+ v.framework_decorated_lines = {10}
240
+ v.is_framework_file = True
241
+ assert detect_framework_usage(d, visitor=v) == 1
242
+
243
+ def test_undecorated_function_in_framework_file_returns_none(self):
244
+ d = Mock()
245
+ d.line = 15
246
+ d.simple_name = "helper_function"
247
+ d.type = "function"
248
+ v = Mock()
249
+ v.framework_decorated_lines = set()
250
+ v.is_framework_file = True
251
+ assert detect_framework_usage(d, visitor=v) is None
252
+
253
+ def test_private_function_in_framework_file_returns_none(self):
254
+ d = Mock()
255
+ d.line = 20
256
+ d.simple_name = "_private_function"
257
+ d.type = "function"
258
+ v = Mock()
259
+ v.framework_decorated_lines = set()
260
+ v.is_framework_file = True
261
+ assert detect_framework_usage(d, visitor=v) is None
262
+
263
+ def test_non_framework_file_returns_none(self):
264
+ d = Mock()
265
+ d.line = 25
266
+ d.simple_name = "regular_function"
267
+ d.type = "function"
268
+ v = Mock()
269
+ v.framework_decorated_lines = set()
270
+ v.is_framework_file = False
271
+ assert detect_framework_usage(d, visitor=v) is None
272
+
325
273
  def test_no_visitor_returns_none(self):
326
- mock_def = Mock()
327
- confidence = detect_framework_usage(mock_def, visitor=None)
328
- assert confidence is None
329
-
330
- def test_non_function_in_framework_file_no_confidence(self):
331
- mock_def = Mock()
332
- mock_def.line = 30
333
- mock_def.simple_name = "my_variable"
334
- mock_def.type = "variable"
335
-
336
- mock_visitor = Mock()
337
- mock_visitor.framework_decorated_lines = set()
338
- mock_visitor.is_framework_file = True
339
-
340
- confidence = detect_framework_usage(mock_def, visitor=mock_visitor)
341
- assert confidence is None
274
+ d = Mock()
275
+ assert detect_framework_usage(d, visitor=None) is None
342
276
 
277
+ def test_non_function_in_framework_file_returns_none(self):
278
+ d = Mock()
279
+ d.line = 30
280
+ d.simple_name = "my_variable"
281
+ d.type = "variable"
282
+ v = Mock()
283
+ v.framework_decorated_lines = set()
284
+ v.is_framework_file = True
285
+ assert detect_framework_usage(d, visitor=v) is None
343
286
 
344
287
  class TestFrameworkPatterns:
345
-
346
288
  def test_framework_decorators_list(self):
347
- """Test that FRAMEWORK_DECORATORS contains expected patterns"""
348
- assert "@app.route" in FRAMEWORK_DECORATORS
349
- assert "@router.get" in FRAMEWORK_DECORATORS
289
+ assert "@*.route" in FRAMEWORK_DECORATORS
290
+ assert "@*.get" in FRAMEWORK_DECORATORS
350
291
  assert "@login_required" in FRAMEWORK_DECORATORS
351
- assert "@task" in FRAMEWORK_DECORATORS
352
- assert "@validator" in FRAMEWORK_DECORATORS
353
-
292
+
354
293
  def test_framework_functions_list(self):
355
- """Test that FRAMEWORK_FUNCTIONS contains expected patterns"""
356
294
  assert "get" in FRAMEWORK_FUNCTIONS
357
295
  assert "post" in FRAMEWORK_FUNCTIONS
358
- assert "save" in FRAMEWORK_FUNCTIONS
359
296
  assert "*_queryset" in FRAMEWORK_FUNCTIONS
360
297
  assert "get_context_data" in FRAMEWORK_FUNCTIONS
361
-
362
- def test_framework_imports_set(self):
363
- """Test that FRAMEWORK_IMPORTS contains expected frameworks"""
364
- assert 'flask' in FRAMEWORK_IMPORTS
365
- assert 'django' in FRAMEWORK_IMPORTS
366
- assert 'fastapi' in FRAMEWORK_IMPORTS
367
- assert 'celery' in FRAMEWORK_IMPORTS
368
- assert 'pydantic' in FRAMEWORK_IMPORTS
369
298
 
299
+ def test_framework_imports_set(self):
300
+ assert "flask" in FRAMEWORK_IMPORTS
301
+ assert "django" in FRAMEWORK_IMPORTS
302
+ assert "fastapi" in FRAMEWORK_IMPORTS
303
+ assert "pydantic" in FRAMEWORK_IMPORTS
370
304
 
371
305
  if __name__ == "__main__":
372
306
  pytest.main([__file__, "-v"])
File without changes