Skip to content

Commit b13799d

Browse files
committed
feat: add Pylint API for code checking and integrate with tool operations
1 parent d85d206 commit b13799d

File tree

4 files changed

+91
-3
lines changed

4 files changed

+91
-3
lines changed

apps/tools/api/tool.py

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44

55
from common.mixins.api_mixin import APIMixin
66
from common.result import ResultSerializer, DefaultResultSerializer
7-
from tools.serializers.tool import ToolModelSerializer, ToolCreateRequest, ToolDebugRequest, ToolEditRequest
7+
from tools.serializers.tool import ToolModelSerializer, ToolCreateRequest, ToolDebugRequest, ToolEditRequest, \
8+
PylintInstance
89

910

1011
class ToolCreateResponse(ResultSerializer):
@@ -209,3 +210,28 @@ def get_parameters():
209210
required=False,
210211
),
211212
]
213+
214+
215+
class PylintAPI(APIMixin):
216+
@staticmethod
217+
def get_parameters():
218+
return [
219+
OpenApiParameter(
220+
name="workspace_id",
221+
description="工作空间id",
222+
type=OpenApiTypes.STR,
223+
location='path',
224+
required=True,
225+
),
226+
OpenApiParameter(
227+
name="tool_id",
228+
description="工具id",
229+
type=OpenApiTypes.STR,
230+
location='path',
231+
required=True,
232+
)
233+
]
234+
235+
@staticmethod
236+
def get_request():
237+
return PylintInstance

apps/tools/serializers/tool.py

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# -*- coding: utf-8 -*-
22
import io
33
import json
4+
import os
45
import pickle
56
import re
67

@@ -10,13 +11,15 @@
1011
from django.db.models import QuerySet, Q
1112
from django.http import HttpResponse
1213
from django.utils.translation import gettext_lazy as _
14+
from pylint.lint import Run
15+
from pylint.reporters import JSON2Reporter
1316
from rest_framework import serializers, status
1417

1518
from common.db.search import page_search
1619
from common.exception.app_exception import AppApiException
1720
from common.result import result
1821
from common.utils.tool_code import ToolExecutor
19-
from maxkb.const import CONFIG
22+
from maxkb.const import CONFIG, PROJECT_DIR
2023
from tools.models import Tool, ToolScope, ToolFolder
2124
from tools.serializers.tool_folder import ToolFolderFlatSerializer
2225

@@ -36,6 +39,25 @@ def __init__(self, tool: dict, version: str):
3639
}
3740

3841

42+
def to_dict(message, file_name):
43+
return {
44+
'line': message.line,
45+
'column': message.column,
46+
'endLine': message.end_line,
47+
'endColumn': message.end_column,
48+
'message': (message.msg or "").replace(file_name, 'code'),
49+
'type': message.category
50+
}
51+
52+
53+
def get_file_name():
54+
file_name = f"{uuid.uuid7()}"
55+
pylint_dir = os.path.join(PROJECT_DIR, 'data', 'pylint')
56+
if not os.path.exists(pylint_dir):
57+
os.makedirs(pylint_dir)
58+
return os.path.join(pylint_dir, file_name)
59+
60+
3961
class RestrictedUnpickler(pickle.Unpickler):
4062

4163
def find_class(self, folder, name):
@@ -164,6 +186,10 @@ class ToolDebugRequest(serializers.Serializer):
164186
debug_field_list = DebugField(required=True, many=True)
165187

166188

189+
class PylintInstance(serializers.Serializer):
190+
code = serializers.CharField(required=True, allow_null=True, allow_blank=True, label=_('function content'))
191+
192+
167193
class ToolSerializer(serializers.Serializer):
168194
class Create(serializers.Serializer):
169195
user_id = serializers.UUIDField(required=True, label=_('user id'))
@@ -287,6 +313,22 @@ def export(self):
287313
except Exception as e:
288314
return result.error(str(e), response_status=status.HTTP_500_INTERNAL_SERVER_ERROR)
289315

316+
def pylint(self, instance, is_valid=True):
317+
if is_valid:
318+
self.is_valid(raise_exception=True)
319+
PylintInstance(data=instance).is_valid(raise_exception=True)
320+
code = instance.get('code')
321+
file_name = get_file_name()
322+
with open(file_name, 'w') as file:
323+
file.write(code)
324+
reporter = JSON2Reporter()
325+
Run([file_name,
326+
"--disable=line-too-long",
327+
'--module-rgx=[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}'],
328+
reporter=reporter, exit=False)
329+
os.remove(file_name)
330+
return [to_dict(m, os.path.basename(file_name)) for m in reporter.messages]
331+
290332
class Import(serializers.Serializer):
291333
file = UploadedFileField(required=True, label=_("file"))
292334
user_id = serializers.UUIDField(required=True, label=_("User ID"))

apps/tools/urls.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
path('workspace/<str:workspace_id>/tool/import', views.ToolView.Import.as_view()),
99
path('workspace/<str:workspace_id>/tool/<str:tool_id>', views.ToolView.Operate.as_view()),
1010
path('workspace/<str:workspace_id>/tool/<str:tool_id>/debug', views.ToolView.Debug.as_view()),
11+
path('workspace/<str:workspace_id>/tool/<str:tool_id>/pylint', views.ToolView.Pylint.as_view()),
1112
path('workspace/<str:workspace_id>/tool/<str:tool_id>/export', views.ToolView.Export.as_view()),
1213
path('workspace/<str:workspace_id>/tool/<int:current_page>/<int:page_size>', views.ToolView.Page.as_view()),
1314
]

apps/tools/views/tool.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from common.constants.permission_constants import PermissionConstants
1010
from common.result import result
1111
from tools.api.tool import ToolCreateAPI, ToolEditAPI, ToolReadAPI, ToolDeleteAPI, ToolTreeReadAPI, ToolDebugApi, \
12-
ToolExportAPI, ToolImportAPI, ToolPageAPI
12+
ToolExportAPI, ToolImportAPI, ToolPageAPI, PylintAPI
1313
from tools.serializers.tool import ToolSerializer, ToolTreeSerializer
1414

1515

@@ -174,3 +174,22 @@ def get(self, request: Request, tool_id: str, workspace_id: str):
174174
return ToolSerializer.Operate(
175175
data={'id': tool_id, 'workspace_id': workspace_id}
176176
).export()
177+
178+
class Pylint(APIView):
179+
authentication_classes = [TokenAuth]
180+
181+
@extend_schema(
182+
methods=['POST'],
183+
summary=_('Check code'),
184+
operation_id=_('Check code'),
185+
description=_('Check code'),
186+
request=PylintAPI.get_request(),
187+
responses=PylintAPI.get_response(),
188+
parameters=PylintAPI.get_parameters(),
189+
tags=[_('Tool')]
190+
)
191+
@has_permissions(PermissionConstants.TOOL_EXPORT.get_workspace_permission())
192+
def post(self, request: Request, workspace_id: str, tool_id: str):
193+
return result.success(ToolSerializer.Operate(
194+
data={'id': tool_id, 'workspace_id': workspace_id}
195+
).pylint(request.data))

0 commit comments

Comments
 (0)