11
11
"""
12
12
13
13
import sys
14
+ import os
14
15
import logging
15
16
from argparse import ArgumentParser
16
17
from pathlib import Path
@@ -54,7 +55,7 @@ def make_sarif_run(tool_name: str) -> dict:
54
55
return sarif_run
55
56
56
57
57
- def flake8_linter (target : Path ) -> None :
58
+ def flake8_linter (target : Path , * args ) -> None :
58
59
"""Run the flake8 linter.
59
60
60
61
In contrast to the other linters, flake8 has plugin architecture.
@@ -154,7 +155,7 @@ def ruff_format_sarif(results: List[Dict[str, Any]], target: Path) -> dict:
154
155
return sarif_run
155
156
156
157
157
- def ruff_linter (target : Path ) -> Optional [dict ]:
158
+ def ruff_linter (target : Path , * args ) -> Optional [dict ]:
158
159
"""Run the ruff linter."""
159
160
try :
160
161
# pylint: disable=import-outside-toplevel
@@ -256,7 +257,7 @@ def pylint_format_sarif(results: List[Dict[str, Any]], target: Path) -> dict:
256
257
return sarif_run
257
258
258
259
259
- def pylint_linter (target : Path ) -> Optional [dict ]:
260
+ def pylint_linter (target : Path , * args ) -> Optional [dict ]:
260
261
"""Run the pylint linter."""
261
262
process = run (
262
263
["pylint" , "--output-format=json" , "--recursive=y" , target .absolute ().as_posix ()],
@@ -371,7 +372,7 @@ def mypy_format_sarif(mypy_results: str, target: Path) -> dict:
371
372
return sarif_run
372
373
373
374
374
- def mypy_linter (target : Path ) -> Optional [dict ]:
375
+ def mypy_linter (target : Path , typeshed_path : Path ) -> Optional [dict ]:
375
376
"""Run the mypy linter."""
376
377
mypy_args = [
377
378
"--install-types" ,
@@ -383,6 +384,8 @@ def mypy_linter(target: Path) -> Optional[dict]:
383
384
"--show-column-numbers" ,
384
385
"--show-error-end" ,
385
386
"--show-absolute-path" ,
387
+ "--custom-typeshed-dir" ,
388
+ typeshed_path .as_posix (),
386
389
]
387
390
388
391
process_lint = run (["mypy" , * mypy_args , target .absolute ().as_posix ()], capture_output = True , check = False )
@@ -462,9 +465,13 @@ def pyright_format_sarif(results: dict, target: Path) -> dict:
462
465
return sarif_run
463
466
464
467
465
- def pyright_linter (target : Path ) -> Optional [dict ]:
468
+ def pyright_linter (target : Path , typeshed_path : Path ) -> Optional [dict ]:
466
469
"""Run the pyright linter."""
467
- process = run (["pyright" , "--outputjson" , target .absolute ().as_posix ()], capture_output = True , check = False )
470
+ process = run (
471
+ ["pyright" , "--outputjson" , "--typeshedpath" , typeshed_path , target .absolute ().as_posix ()],
472
+ capture_output = True ,
473
+ check = False ,
474
+ )
468
475
469
476
if process .stderr :
470
477
LOG .error ("STDERR: %s" , process .stderr .decode ("utf-8" ))
@@ -545,10 +552,14 @@ def pytype_format_sarif(results: str, target: Path) -> dict:
545
552
return sarif_run
546
553
547
554
548
- def pytype_linter (target : Path ) -> Optional [dict ]:
555
+ def pytype_linter (target : Path , typeshed_path : Path ) -> Optional [dict ]:
549
556
"""Run the pytype linter."""
557
+ os .environ ["TYPESHED_HOME" ] = typeshed_path .as_posix ()
558
+
550
559
process = run (
551
- ["pytype" , "--exclude" , ".pytype/" , "--" , target .absolute ().as_posix ()], capture_output = True , check = False
560
+ ["pytype" , "--exclude" , ".pytype/" , "--" , target .as_posix ()],
561
+ capture_output = True ,
562
+ check = False ,
552
563
)
553
564
554
565
if process .stderr :
@@ -567,6 +578,44 @@ def pytype_linter(target: Path) -> Optional[dict]:
567
578
return sarif_run
568
579
569
580
581
+ def pyre_linter (target : Path , typeshed_path : Path ) -> Optional [dict ]:
582
+ """Run the pytype linter."""
583
+ process = run (
584
+ [
585
+ "pyre" ,
586
+ "--source-directory" ,
587
+ target .as_posix (),
588
+ "--output" ,
589
+ "sarif" ,
590
+ "--typeshed" ,
591
+ typeshed_path .as_posix (),
592
+ "check" ,
593
+ ],
594
+ capture_output = True ,
595
+ check = False ,
596
+ )
597
+
598
+ if process .stderr :
599
+ LOG .debug ("STDERR: %s" , process .stderr .decode ("utf-8" ))
600
+
601
+ if not process .stdout :
602
+ LOG .error ("No output from pytype" )
603
+ return None
604
+
605
+ try :
606
+ sarif = json .loads (process .stdout .decode ("utf-8" ))
607
+ except json .JSONDecodeError as err :
608
+ LOG .error ("Unable to parse pyre output: %s" , err )
609
+ LOG .debug ("Output: %s" , process .stdout .decode ("utf-8" ))
610
+ return None
611
+
612
+ if "runs" in sarif and len (sarif ["runs" ]) > 0 :
613
+ return sarif ["runs" ][0 ]
614
+
615
+ LOG .error ("SARIF not correctly formed, or no runs to output" )
616
+ return None
617
+
618
+
570
619
def make_fixit_description (rule : str ) -> str :
571
620
"""Format 'SomeRuleDescription' into 'Some rule description'."""
572
621
rule = FIND_CAMEL_CASE .sub (lambda x : x .group (0 ).lower () + " " , rule )
@@ -670,6 +719,7 @@ def make_paths_relative_to_target(runs: List[dict], target: Path) -> None:
670
719
"mypy" : mypy_linter ,
671
720
"pyright" : pyright_linter ,
672
721
"fixit" : fixit_linter ,
722
+ "pyre" : pyre_linter ,
673
723
}
674
724
675
725
# pytype is only supported on Python 3.10 and below, at the time of writing
@@ -682,6 +732,7 @@ def add_args(parser: ArgumentParser) -> None:
682
732
parser .add_argument ("linter" , choices = LINTERS .keys (), nargs = "+" , help = "The linter(s) to use" )
683
733
parser .add_argument ("--target" , "-t" , default = "." , required = False , help = "Target path for the linter" )
684
734
parser .add_argument ("--output" , "-o" , default = "python_linter.sarif" , required = False , help = "Output filename" )
735
+ parser .add_argument ("--typeshed-path" , required = False , help = "Path to typeshed" )
685
736
parser .add_argument ("--debug" , "-d" , action = "store_true" , required = False , help = "Enable debug logging" )
686
737
687
738
@@ -700,11 +751,12 @@ def main() -> None:
700
751
sarif_runs : List [dict ] = []
701
752
702
753
target = Path (args .target ).resolve ().absolute ()
754
+ typeshed_path = Path (args .typeshed_path ).resolve ().absolute ()
703
755
704
756
for linter in args .linter :
705
757
LOG .debug ("Running %s" , linter )
706
758
707
- sarif_run = LINTERS [linter ](target )
759
+ sarif_run = LINTERS [linter ](target , typeshed_path )
708
760
709
761
if sarif_run is not None :
710
762
sarif_runs .append (sarif_run )
0 commit comments