mirror of
https://github.com/1Panel-dev/MaxKB.git
synced 2025-12-31 10:12:51 +00:00
feat: add Pylint API for code checking and integrate with tool operations
This commit is contained in:
parent
d85d20694d
commit
b13799d584
|
|
@ -4,7 +4,8 @@ from drf_spectacular.utils import OpenApiParameter
|
|||
|
||||
from common.mixins.api_mixin import APIMixin
|
||||
from common.result import ResultSerializer, DefaultResultSerializer
|
||||
from tools.serializers.tool import ToolModelSerializer, ToolCreateRequest, ToolDebugRequest, ToolEditRequest
|
||||
from tools.serializers.tool import ToolModelSerializer, ToolCreateRequest, ToolDebugRequest, ToolEditRequest, \
|
||||
PylintInstance
|
||||
|
||||
|
||||
class ToolCreateResponse(ResultSerializer):
|
||||
|
|
@ -209,3 +210,28 @@ class ToolPageAPI(ToolReadAPI):
|
|||
required=False,
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
class PylintAPI(APIMixin):
|
||||
@staticmethod
|
||||
def get_parameters():
|
||||
return [
|
||||
OpenApiParameter(
|
||||
name="workspace_id",
|
||||
description="工作空间id",
|
||||
type=OpenApiTypes.STR,
|
||||
location='path',
|
||||
required=True,
|
||||
),
|
||||
OpenApiParameter(
|
||||
name="tool_id",
|
||||
description="工具id",
|
||||
type=OpenApiTypes.STR,
|
||||
location='path',
|
||||
required=True,
|
||||
)
|
||||
]
|
||||
|
||||
@staticmethod
|
||||
def get_request():
|
||||
return PylintInstance
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import io
|
||||
import json
|
||||
import os
|
||||
import pickle
|
||||
import re
|
||||
|
||||
|
|
@ -10,13 +11,15 @@ from django.db import transaction
|
|||
from django.db.models import QuerySet, Q
|
||||
from django.http import HttpResponse
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from pylint.lint import Run
|
||||
from pylint.reporters import JSON2Reporter
|
||||
from rest_framework import serializers, status
|
||||
|
||||
from common.db.search import page_search
|
||||
from common.exception.app_exception import AppApiException
|
||||
from common.result import result
|
||||
from common.utils.tool_code import ToolExecutor
|
||||
from maxkb.const import CONFIG
|
||||
from maxkb.const import CONFIG, PROJECT_DIR
|
||||
from tools.models import Tool, ToolScope, ToolFolder
|
||||
from tools.serializers.tool_folder import ToolFolderFlatSerializer
|
||||
|
||||
|
|
@ -36,6 +39,25 @@ ALLOWED_CLASSES = {
|
|||
}
|
||||
|
||||
|
||||
def to_dict(message, file_name):
|
||||
return {
|
||||
'line': message.line,
|
||||
'column': message.column,
|
||||
'endLine': message.end_line,
|
||||
'endColumn': message.end_column,
|
||||
'message': (message.msg or "").replace(file_name, 'code'),
|
||||
'type': message.category
|
||||
}
|
||||
|
||||
|
||||
def get_file_name():
|
||||
file_name = f"{uuid.uuid7()}"
|
||||
pylint_dir = os.path.join(PROJECT_DIR, 'data', 'pylint')
|
||||
if not os.path.exists(pylint_dir):
|
||||
os.makedirs(pylint_dir)
|
||||
return os.path.join(pylint_dir, file_name)
|
||||
|
||||
|
||||
class RestrictedUnpickler(pickle.Unpickler):
|
||||
|
||||
def find_class(self, folder, name):
|
||||
|
|
@ -164,6 +186,10 @@ class ToolDebugRequest(serializers.Serializer):
|
|||
debug_field_list = DebugField(required=True, many=True)
|
||||
|
||||
|
||||
class PylintInstance(serializers.Serializer):
|
||||
code = serializers.CharField(required=True, allow_null=True, allow_blank=True, label=_('function content'))
|
||||
|
||||
|
||||
class ToolSerializer(serializers.Serializer):
|
||||
class Create(serializers.Serializer):
|
||||
user_id = serializers.UUIDField(required=True, label=_('user id'))
|
||||
|
|
@ -287,6 +313,22 @@ class ToolSerializer(serializers.Serializer):
|
|||
except Exception as e:
|
||||
return result.error(str(e), response_status=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
||||
|
||||
def pylint(self, instance, is_valid=True):
|
||||
if is_valid:
|
||||
self.is_valid(raise_exception=True)
|
||||
PylintInstance(data=instance).is_valid(raise_exception=True)
|
||||
code = instance.get('code')
|
||||
file_name = get_file_name()
|
||||
with open(file_name, 'w') as file:
|
||||
file.write(code)
|
||||
reporter = JSON2Reporter()
|
||||
Run([file_name,
|
||||
"--disable=line-too-long",
|
||||
'--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}'],
|
||||
reporter=reporter, exit=False)
|
||||
os.remove(file_name)
|
||||
return [to_dict(m, os.path.basename(file_name)) for m in reporter.messages]
|
||||
|
||||
class Import(serializers.Serializer):
|
||||
file = UploadedFileField(required=True, label=_("file"))
|
||||
user_id = serializers.UUIDField(required=True, label=_("User ID"))
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ urlpatterns = [
|
|||
path('workspace/<str:workspace_id>/tool/import', views.ToolView.Import.as_view()),
|
||||
path('workspace/<str:workspace_id>/tool/<str:tool_id>', views.ToolView.Operate.as_view()),
|
||||
path('workspace/<str:workspace_id>/tool/<str:tool_id>/debug', views.ToolView.Debug.as_view()),
|
||||
path('workspace/<str:workspace_id>/tool/<str:tool_id>/pylint', views.ToolView.Pylint.as_view()),
|
||||
path('workspace/<str:workspace_id>/tool/<str:tool_id>/export', views.ToolView.Export.as_view()),
|
||||
path('workspace/<str:workspace_id>/tool/<int:current_page>/<int:page_size>', views.ToolView.Page.as_view()),
|
||||
]
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ from common.auth.authentication import has_permissions
|
|||
from common.constants.permission_constants import PermissionConstants
|
||||
from common.result import result
|
||||
from tools.api.tool import ToolCreateAPI, ToolEditAPI, ToolReadAPI, ToolDeleteAPI, ToolTreeReadAPI, ToolDebugApi, \
|
||||
ToolExportAPI, ToolImportAPI, ToolPageAPI
|
||||
ToolExportAPI, ToolImportAPI, ToolPageAPI, PylintAPI
|
||||
from tools.serializers.tool import ToolSerializer, ToolTreeSerializer
|
||||
|
||||
|
||||
|
|
@ -174,3 +174,22 @@ class ToolView(APIView):
|
|||
return ToolSerializer.Operate(
|
||||
data={'id': tool_id, 'workspace_id': workspace_id}
|
||||
).export()
|
||||
|
||||
class Pylint(APIView):
|
||||
authentication_classes = [TokenAuth]
|
||||
|
||||
@extend_schema(
|
||||
methods=['POST'],
|
||||
summary=_('Check code'),
|
||||
operation_id=_('Check code'),
|
||||
description=_('Check code'),
|
||||
request=PylintAPI.get_request(),
|
||||
responses=PylintAPI.get_response(),
|
||||
parameters=PylintAPI.get_parameters(),
|
||||
tags=[_('Tool')]
|
||||
)
|
||||
@has_permissions(PermissionConstants.TOOL_EXPORT.get_workspace_permission())
|
||||
def post(self, request: Request, workspace_id: str, tool_id: str):
|
||||
return result.success(ToolSerializer.Operate(
|
||||
data={'id': tool_id, 'workspace_id': workspace_id}
|
||||
).pylint(request.data))
|
||||
|
|
|
|||
Loading…
Reference in New Issue