Skip to content

Commit 87c75a5

Browse files
committed
Share common CodeTF models where possible
1 parent 23ddddc commit 87c75a5

File tree

3 files changed

+85
-77
lines changed

3 files changed

+85
-77
lines changed

src/codemodder/codetf/common.py

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
from abc import ABCMeta
22
from enum import Enum
33
from pathlib import Path
4+
from typing import Optional
45

5-
from pydantic import BaseModel
6+
from pydantic import BaseModel, ConfigDict, model_validator
67

78
from codemodder.logging import logger
89

@@ -26,3 +27,60 @@ def write_report(self, outfile: Path | str) -> int:
2627
return 2
2728
logger.debug("wrote report to %s", outfile)
2829
return 0
30+
31+
32+
class Rule(BaseModel):
33+
id: str
34+
name: str
35+
url: Optional[str] = None
36+
37+
model_config = ConfigDict(frozen=True)
38+
39+
40+
class Finding(BaseModel):
41+
id: str
42+
rule: Rule
43+
44+
model_config = ConfigDict(frozen=True)
45+
46+
47+
class Action(CaseInsensitiveEnum):
48+
ADD = "add"
49+
REMOVE = "remove"
50+
51+
52+
class PackageResult(CaseInsensitiveEnum):
53+
COMPLETED = "completed"
54+
FAILED = "failed"
55+
SKIPPED = "skipped"
56+
57+
58+
class DiffSide(CaseInsensitiveEnum):
59+
LEFT = "left"
60+
RIGHT = "right"
61+
62+
63+
class PackageAction(BaseModel):
64+
action: Action
65+
result: PackageResult
66+
package: str
67+
68+
69+
class Change(BaseModel):
70+
lineNumber: int
71+
description: Optional[str]
72+
diffSide: DiffSide = DiffSide.RIGHT
73+
properties: Optional[dict] = None
74+
packageActions: Optional[list[PackageAction]] = None
75+
76+
@model_validator(mode="after")
77+
def validate_lineNumber(self):
78+
if self.lineNumber < 1:
79+
raise ValueError("lineNumber must be greater than 0")
80+
return self
81+
82+
@model_validator(mode="after")
83+
def validate_description(self):
84+
if self.description is not None and not self.description:
85+
raise ValueError("description must not be empty")
86+
return self

src/codemodder/codetf/v2/codetf.py

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,21 @@
1111
from enum import Enum
1212
from typing import TYPE_CHECKING, Optional
1313

14-
from pydantic import BaseModel, ConfigDict, model_validator
14+
from pydantic import BaseModel, model_validator
1515

1616
from codemodder import __version__
1717

18-
from ..common import CaseInsensitiveEnum, CodeTFWriter
18+
from ..common import (
19+
CaseInsensitiveEnum,
20+
)
21+
from ..common import Change as CommonChange
22+
from ..common import (
23+
CodeTFWriter,
24+
)
25+
from ..common import Finding as CommonFinding
26+
from ..common import (
27+
Rule,
28+
)
1929

2030
if TYPE_CHECKING:
2131
from codemodder.context import CodemodExecutionContext
@@ -46,10 +56,6 @@ class PackageAction(BaseModel):
4656
class Change(BaseModel):
4757
lineNumber: int
4858
description: Optional[str]
49-
# All of our changes are currently treated as additive, so it makes sense
50-
# for the comments to appear on the RIGHT side of the split diff. Eventually we
51-
# may want to differentiate between LEFT and RIGHT, but for now we'll just
52-
# default to RIGHT.
5359
diffSide: DiffSide = DiffSide.RIGHT
5460
properties: Optional[dict] = None
5561
packageActions: Optional[list[PackageAction]] = None
@@ -77,6 +83,15 @@ def with_findings(self, findings: list[Finding] | None) -> Change:
7783
fixedFindings=findings,
7884
)
7985

86+
def to_common(self) -> CommonChange:
87+
return CommonChange(
88+
lineNumber=self.lineNumber,
89+
description=self.description,
90+
diffSide=self.diffSide,
91+
properties=self.properties,
92+
packageActions=self.packageActions,
93+
)
94+
8095

8196
class AIMetadata(BaseModel):
8297
provider: Optional[str] = None
@@ -138,20 +153,7 @@ def validate_description(self):
138153
return self
139154

140155

141-
class Rule(BaseModel):
142-
id: str
143-
name: str
144-
url: Optional[str] = None
145-
146-
model_config = ConfigDict(frozen=True)
147-
148-
149-
class Finding(BaseModel):
150-
id: Optional[str] = None
151-
rule: Rule
152-
153-
model_config = ConfigDict(frozen=True)
154-
156+
class Finding(CommonFinding):
155157
def to_unfixed_finding(
156158
self,
157159
*,
@@ -170,7 +172,7 @@ def to_unfixed_finding(
170172
def with_rule(self, name: str, url: Optional[str]) -> Finding:
171173
return Finding(
172174
id=self.id,
173-
rule=Rule(id=self.rule.id, name=name, url=url),
175+
rule=Rule(id=self.rule.id, name=name, url=url) if self.rule else None,
174176
)
175177

176178

src/codemodder/codetf/v3/codetf.py

Lines changed: 3 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55

66
from pydantic import BaseModel, model_validator
77

8-
from ..common import CaseInsensitiveEnum, CodeTFWriter
8+
from ..common import Change, CodeTFWriter, Finding
9+
from ..v2.codetf import Finding as V2Finding
910

1011

1112
class Run(BaseModel):
@@ -44,59 +45,6 @@ class FixStatus(BaseModel):
4445
details: Optional[str]
4546

4647

47-
class Rule(BaseModel):
48-
id: str
49-
name: str
50-
url: Optional[str] = None
51-
52-
53-
class Finding(BaseModel):
54-
id: str
55-
rule: Optional[Rule] = None
56-
57-
58-
class Action(CaseInsensitiveEnum):
59-
ADD = "add"
60-
REMOVE = "remove"
61-
62-
63-
class PackageResult(CaseInsensitiveEnum):
64-
COMPLETED = "completed"
65-
FAILED = "failed"
66-
SKIPPED = "skipped"
67-
68-
69-
class DiffSide(CaseInsensitiveEnum):
70-
LEFT = "left"
71-
RIGHT = "right"
72-
73-
74-
class PackageAction(BaseModel):
75-
action: Action
76-
result: PackageResult
77-
package: str
78-
79-
80-
class Change(BaseModel):
81-
lineNumber: int
82-
description: Optional[str]
83-
diffSide: DiffSide = DiffSide.RIGHT
84-
properties: Optional[dict] = None
85-
packageActions: Optional[list[PackageAction]] = None
86-
87-
@model_validator(mode="after")
88-
def validate_lineNumber(self):
89-
if self.lineNumber < 1:
90-
raise ValueError("lineNumber must be greater than 0")
91-
return self
92-
93-
@model_validator(mode="after")
94-
def validate_description(self):
95-
if self.description is not None and not self.description:
96-
raise ValueError("description must not be empty")
97-
return self
98-
99-
10048
class ChangeSet(BaseModel):
10149
path: str
10250
diff: str
@@ -158,7 +106,7 @@ class FixQuality(BaseModel):
158106
class FixResult(BaseModel):
159107
"""Result corresponding to a single finding"""
160108

161-
finding: Finding
109+
finding: Finding | V2Finding
162110
fixStatus: FixStatus
163111
changeSets: list[ChangeSet]
164112
fixMetadata: Optional[FixMetadata] = None

0 commit comments

Comments
 (0)