Skip to content

Commit 5e92d1d

Browse files
committed
fix linters, remove astunparse dependency
Signed-off-by: William Woodruff <william@trailofbits.com>
1 parent a80bba8 commit 5e92d1d

File tree

12 files changed

+96
-150
lines changed

12 files changed

+96
-150
lines changed

example/trace_binary.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import io
2-
3-
from astunparse import unparse
2+
from ast import unparse
43

54
import fickling.tracing as tracing
65
from fickling.fickle import Interpreter, Pickled

fickling/analysis.py

Lines changed: 25 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,20 @@
1+
from __future__ import annotations
2+
13
import json
2-
import sys
34
from abc import ABC, abstractmethod
5+
from ast import unparse
46
from collections import defaultdict
7+
from collections.abc import Iterable, Iterator
58
from enum import Enum
6-
from typing import Dict, Iterable, Iterator, List, Optional, Set, Tuple, Type
7-
8-
if sys.version_info < (3, 9):
9-
from astunparse import unparse
10-
else:
11-
from ast import unparse
129

1310
from fickling.fickle import Interpreter, Pickled, Proto
1411

1512

1613
class AnalyzerMeta(type):
17-
_DEFAULT_INSTANCE: Optional["Analyzer"] = None
14+
_DEFAULT_INSTANCE: Analyzer | None = None
1815

1916
@property
20-
def default_instance(cls) -> "Analyzer":
17+
def default_instance(cls) -> Analyzer:
2118
if cls._DEFAULT_INSTANCE is None:
2219
cls._DEFAULT_INSTANCE = Analyzer(Analysis.ALL)
2320
return cls._DEFAULT_INSTANCE
@@ -26,11 +23,11 @@ def default_instance(cls) -> "Analyzer":
2623
class AnalysisContext:
2724
def __init__(self, pickled: Pickled):
2825
self.pickled: Pickled = pickled
29-
self.reported_shortened_code: Set[str] = set()
30-
self.previous_results: List[AnalysisResult] = []
31-
self.results_by_analysis: Dict[Type[Analysis], List[AnalysisResult]] = defaultdict(list)
26+
self.reported_shortened_code: set[str] = set()
27+
self.previous_results: list[AnalysisResult] = []
28+
self.results_by_analysis: dict[type[Analysis], list[AnalysisResult]] = defaultdict(list)
3229

33-
def analyze(self, analysis: "Analysis") -> "List[AnalysisResult]":
30+
def analyze(self, analysis: Analysis) -> list[AnalysisResult]:
3431
results = list(analysis.analyze(self))
3532
if not results:
3633
self.results_by_analysis[type(analysis)].append(AnalysisResult(Severity.LIKELY_SAFE))
@@ -40,10 +37,10 @@ def analyze(self, analysis: "Analysis") -> "List[AnalysisResult]":
4037
return results
4138

4239
@property
43-
def results(self) -> "AnalysisResults":
40+
def results(self) -> AnalysisResults:
4441
return AnalysisResults(pickled=self.pickled, results=self.previous_results)
4542

46-
def shorten_code(self, ast_node) -> Tuple[str, bool]:
43+
def shorten_code(self, ast_node) -> tuple[str, bool]:
4744
code = unparse(ast_node).strip()
4845
if len(code) > 32:
4946
cutoff = code.find("(")
@@ -59,10 +56,10 @@ def shorten_code(self, ast_node) -> Tuple[str, bool]:
5956

6057

6158
class Analyzer(metaclass=AnalyzerMeta):
62-
def __init__(self, analyses: Iterable["Analysis"]):
63-
self.analyses: Tuple[Analysis, ...] = tuple(analyses)
59+
def __init__(self, analyses: Iterable[Analysis]):
60+
self.analyses: tuple[Analysis, ...] = tuple(analyses)
6461

65-
def analyze(self, pickled: Pickled) -> "AnalysisResults":
62+
def analyze(self, pickled: Pickled) -> AnalysisResults:
6663
context = AnalysisContext(pickled=pickled)
6764
for a in self.analyses:
6865
context.analyze(a)
@@ -101,14 +98,14 @@ class AnalysisResult:
10198
def __init__(
10299
self,
103100
severity: Severity,
104-
message: Optional[str] = None,
101+
message: str | None = None,
105102
analysis_name: str = None,
106-
trigger: Optional[str] = None,
103+
trigger: str | None = None,
107104
):
108105
self.severity: Severity = severity
109-
self.message: Optional[str] = message
106+
self.message: str | None = message
110107
self.analysis_name: str = analysis_name
111-
self.trigger: Optional[str] = trigger # Field to store the trigger code fragment or artifact
108+
self.trigger: str | None = trigger # Field to store the trigger code fragment or artifact
112109

113110
def __lt__(self, other):
114111
return isinstance(other, AnalysisResult) and (
@@ -127,7 +124,7 @@ def __str__(self):
127124

128125

129126
class Analysis(ABC):
130-
ALL: "List[Analysis]" = []
127+
ALL: list[Analysis] = []
131128

132129
def __init_subclass__(cls, **kwargs):
133130
Analysis.ALL.append(cls())
@@ -140,7 +137,7 @@ def analyze(self, context: AnalysisContext) -> Iterator[AnalysisResult]:
140137
class DuplicateProtoAnalysis(Analysis):
141138
def analyze(self, context: AnalysisContext) -> Iterator[AnalysisResult]:
142139
had_proto = False
143-
proto_versions: Set[int] = set()
140+
proto_versions: set[int] = set()
144141
for i, opcode in enumerate(context.pickled):
145142
if isinstance(opcode, Proto):
146143
if had_proto:
@@ -344,7 +341,7 @@ def analyze(self, context: AnalysisContext) -> Iterator[AnalysisResult]:
344341
class AnalysisResults:
345342
def __init__(self, pickled: Pickled, results: Iterable[AnalysisResult]):
346343
self.pickled: Pickled = pickled
347-
self.results: Tuple[AnalysisResult, ...] = tuple(results)
344+
self.results: tuple[AnalysisResult, ...] = tuple(results)
348345

349346
@property
350347
def severity(self) -> Severity:
@@ -356,7 +353,7 @@ def __bool__(self):
356353
"""Returns True if all analyses failed to find any unsafe operations"""
357354
return all(map(bool, sorted(self.results)))
358355

359-
def detailed_results(self) -> Dict[str, Dict[str, str]]:
356+
def detailed_results(self) -> dict[str, dict[str, str]]:
360357
detailed = defaultdict(dict)
361358
for result in self.results:
362359
if result.trigger:
@@ -386,9 +383,9 @@ def to_dict(self, verbosity: Severity = Severity.POSSIBLY_UNSAFE):
386383

387384
def check_safety(
388385
pickled: Pickled,
389-
analyzer: Optional[Analyzer] = None,
386+
analyzer: Analyzer | None = None,
390387
verbosity: Severity = Severity.POSSIBLY_UNSAFE,
391-
json_output_path: Optional[str] = None,
388+
json_output_path: str | None = None,
392389
) -> AnalysisResults:
393390
if analyzer is None:
394391
analyzer = Analyzer.default_instance

fickling/cli.py

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,16 @@
1+
from __future__ import annotations
2+
13
import sys
24
from argparse import ArgumentParser
3-
from typing import List, Optional
4-
5-
if sys.version_info >= (3, 9):
6-
from ast import unparse
7-
else:
8-
from astunparse import unparse
5+
from ast import unparse
96

107
from . import __version__, fickle, tracing
118
from .analysis import Severity, check_safety
129

1310
DEFAULT_JSON_OUTPUT_FILE = "safety_results.json"
1411

1512

16-
def main(argv: Optional[List[str]] = None) -> int:
13+
def main(argv: list[str] | None = None) -> int:
1714
if argv is None:
1815
argv = sys.argv
1916

0 commit comments

Comments
 (0)