77from __future__ import annotations
88
99import json
10- import sys
1110from textwrap import shorten
12- from typing import TYPE_CHECKING , TypedDict , TextIO
13-
14- from pylint .constants import MSG_TYPES
11+ from typing import TYPE_CHECKING , TypedDict
1512
1613import pylint
14+ from pylint .constants import MSG_TYPES
1715from pylint .interfaces import CONFIDENCE_MAP , UNDEFINED
1816from pylint .message import Message
1917from pylint .reporters .base_reporter import BaseReporter
20- from pylint .typing import MessageLocationTuple , MessageTypesFullName
18+ from pylint .typing import MessageLocationTuple
2119
2220if TYPE_CHECKING :
2321 from pylint .lint .pylinter import PyLinter
24- from pylint .reporters .ureports .nodes import Section
2522 from pylint .reporters import sarif_types
23+ from pylint .reporters .ureports .nodes import Section
2624
2725# Since message-id is an invalid name we need to use the alternative syntax
2826OldJsonExport = TypedDict (
@@ -218,41 +216,53 @@ def display_messages(self, layout: Section | None) -> None:
218216 output : sarif_types .Log = {
219217 "version" : "2.1.0" ,
220218 "$schema" : "https://docs.oasis-open.org/sarif/sarif/v2.1.0/cs01/schemas/sarif-schema-2.1.0.json" ,
221- "runs" : [{
222- "tool" : {
223- "driver" : {
224- "name" : "pylint" ,
225- "fullName" : f"pylint { pylint .__version__ } " ,
226- "version" : pylint .__version__ ,
227- # should be versioned but not all versions are kept so...
228- "informationUri" : "https://pylint.readthedocs.io/" ,
229- "rules" : [
230- {
231- "id" : m .msgid ,
232- "name" : m .symbol ,
233- "deprecatedIds" : [msgid for msgid , _ in m .old_names ],
234- "deprecatedNames" : [name for _ , name in m .old_names ],
235- # per 3.19.19 shortDescription should be a
236- # single sentence which can't be guaranteed,
237- # however github requires it...
238- "shortDescription" : {'text' : m .description .split ("." , 1 )[0 ]},
239- # github requires that this is less than 1024 characters
240- "fullDescription" : {'text' : shorten (m .description , 1024 , placeholder = "..." )},
241- "help" : {"text" : m .format_help ()},
242- "helpUri" : f"https://pylint.readthedocs.io/en/stable/user_guide/messages/{ MSG_TYPES [m .msgid [0 ]]} /{ m .symbol } .html"
243- # handle_message only gets the formatted message,
244- # so to use `messageStrings` we'd need to
245- # convert the templating and extract the args
246- # out of the msg
247- }
248- for checker in self .linter .get_checkers ()
249- for m in checker .messages
250- if m .symbol in self .linter .stats .by_msg
251- ]
252- }
253- },
254- "results" : [self .serialize (message ) for message in self .messages ],
255- }]
219+ "runs" : [
220+ {
221+ "tool" : {
222+ "driver" : {
223+ "name" : "pylint" ,
224+ "fullName" : f"pylint { pylint .__version__ } " ,
225+ "version" : pylint .__version__ ,
226+ # should be versioned but not all versions are kept so...
227+ "informationUri" : "https://pylint.readthedocs.io/" ,
228+ "rules" : [
229+ {
230+ "id" : m .msgid ,
231+ "name" : m .symbol ,
232+ "deprecatedIds" : [
233+ msgid for msgid , _ in m .old_names
234+ ],
235+ "deprecatedNames" : [
236+ name for _ , name in m .old_names
237+ ],
238+ # per 3.19.19 shortDescription should be a
239+ # single sentence which can't be guaranteed,
240+ # however github requires it...
241+ "shortDescription" : {
242+ "text" : m .description .split ("." , 1 )[0 ]
243+ },
244+ # github requires that this is less than 1024 characters
245+ "fullDescription" : {
246+ "text" : shorten (
247+ m .description , 1024 , placeholder = "..."
248+ )
249+ },
250+ "help" : {"text" : m .format_help ()},
251+ "helpUri" : f"https://pylint.readthedocs.io/en/stable/user_guide/messages/{ MSG_TYPES [m .msgid [0 ]]} /{ m .symbol } .html" ,
252+ # handle_message only gets the formatted message,
253+ # so to use `messageStrings` we'd need to
254+ # convert the templating and extract the args
255+ # out of the msg
256+ }
257+ for checker in self .linter .get_checkers ()
258+ for m in checker .messages
259+ if m .symbol in self .linter .stats .by_msg
260+ ],
261+ }
262+ },
263+ "results" : [self .serialize (message ) for message in self .messages ],
264+ }
265+ ],
256266 }
257267 json .dump (output , self .out )
258268
@@ -268,7 +278,7 @@ def serialize(message: Message) -> sarif_types.Result:
268278 location : sarif_types .Location = {
269279 "physicalLocation" : {
270280 "artifactLocation" : {
271- "uri" : message .path .replace (' \\ ' , '/' ),
281+ "uri" : message .path .replace (" \\ " , "/" ),
272282 },
273283 "region" : region ,
274284 },
@@ -288,9 +298,10 @@ def serialize(message: Message) -> sarif_types.Result:
288298 "partialFingerprints" : {
289299 # encoding the node path seems like it would be useful to dedup alerts?
290300 "nodePath/v1" : "" ,
291- }
301+ },
292302 }
293303
304+
294305CATEGORY_MAP : dict [str , sarif_types .ResultLevel ] = {
295306 "convention" : "note" ,
296307 "refactor" : "note" ,
@@ -301,6 +312,7 @@ def serialize(message: Message) -> sarif_types.Result:
301312 "fatal" : "error" ,
302313}
303314
315+
304316def register (linter : PyLinter ) -> None :
305317 linter .register_reporter (JSONReporter )
306318 linter .register_reporter (JSON2Reporter )
0 commit comments