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.mixins.api_mixin import APIMixin
|
||||||
from common.result import ResultSerializer, DefaultResultSerializer
|
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):
|
class ToolCreateResponse(ResultSerializer):
|
||||||
@ -209,3 +210,28 @@ class ToolPageAPI(ToolReadAPI):
|
|||||||
required=False,
|
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 -*-
|
# -*- coding: utf-8 -*-
|
||||||
import io
|
import io
|
||||||
import json
|
import json
|
||||||
|
import os
|
||||||
import pickle
|
import pickle
|
||||||
import re
|
import re
|
||||||
|
|
||||||
@ -10,13 +11,15 @@ from django.db import transaction
|
|||||||
from django.db.models import QuerySet, Q
|
from django.db.models import QuerySet, Q
|
||||||
from django.http import HttpResponse
|
from django.http import HttpResponse
|
||||||
from django.utils.translation import gettext_lazy as _
|
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 rest_framework import serializers, status
|
||||||
|
|
||||||
from common.db.search import page_search
|
from common.db.search import page_search
|
||||||
from common.exception.app_exception import AppApiException
|
from common.exception.app_exception import AppApiException
|
||||||
from common.result import result
|
from common.result import result
|
||||||
from common.utils.tool_code import ToolExecutor
|
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.models import Tool, ToolScope, ToolFolder
|
||||||
from tools.serializers.tool_folder import ToolFolderFlatSerializer
|
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):
|
class RestrictedUnpickler(pickle.Unpickler):
|
||||||
|
|
||||||
def find_class(self, folder, name):
|
def find_class(self, folder, name):
|
||||||
@ -164,6 +186,10 @@ class ToolDebugRequest(serializers.Serializer):
|
|||||||
debug_field_list = DebugField(required=True, many=True)
|
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 ToolSerializer(serializers.Serializer):
|
||||||
class Create(serializers.Serializer):
|
class Create(serializers.Serializer):
|
||||||
user_id = serializers.UUIDField(required=True, label=_('user id'))
|
user_id = serializers.UUIDField(required=True, label=_('user id'))
|
||||||
@ -287,6 +313,22 @@ class ToolSerializer(serializers.Serializer):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
return result.error(str(e), response_status=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
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):
|
class Import(serializers.Serializer):
|
||||||
file = UploadedFileField(required=True, label=_("file"))
|
file = UploadedFileField(required=True, label=_("file"))
|
||||||
user_id = serializers.UUIDField(required=True, label=_("User ID"))
|
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/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>', 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>/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/<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()),
|
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.constants.permission_constants import PermissionConstants
|
||||||
from common.result import result
|
from common.result import result
|
||||||
from tools.api.tool import ToolCreateAPI, ToolEditAPI, ToolReadAPI, ToolDeleteAPI, ToolTreeReadAPI, ToolDebugApi, \
|
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
|
from tools.serializers.tool import ToolSerializer, ToolTreeSerializer
|
||||||
|
|
||||||
|
|
||||||
@ -174,3 +174,22 @@ class ToolView(APIView):
|
|||||||
return ToolSerializer.Operate(
|
return ToolSerializer.Operate(
|
||||||
data={'id': tool_id, 'workspace_id': workspace_id}
|
data={'id': tool_id, 'workspace_id': workspace_id}
|
||||||
).export()
|
).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
Block a user