or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

analysis-runner.mdconfiguration.mdexceptions.mdfile-finding.mdformatters.mdindex.mdmessages.mdprofiles.mdtools.md

messages.mddocs/

0

# Messages

1

2

Standardized data structures for representing analysis results and source code locations. The Message and Location classes provide a unified format for all analysis tool outputs.

3

4

## Capabilities

5

6

### Message Class

7

8

Represents a single analysis issue or finding from a static analysis tool.

9

10

```python { .api }

11

class Message:

12

def __init__(self, source: str, code: str, location: Location, message: str,

13

doc_url: Optional[str] = None, is_fixable: bool = False) -> None

14

```

15

16

Creates a new message representing an analysis finding.

17

18

**Parameters:**

19

- `source`: str - Name of the tool that generated this message (e.g., "pylint", "pyflakes")

20

- `code`: str - Error/warning code from the tool (e.g., "E501", "unused-import")

21

- `location`: Location - Source code location where the issue was found

22

- `message`: str - Human-readable description of the issue

23

- `doc_url`: Optional[str] - URL to documentation about this issue type

24

- `is_fixable`: bool - Whether this issue can be automatically fixed

25

26

**Properties:**

27

- `source`: str - Tool that generated the message

28

- `code`: str - Error/warning code

29

- `location`: Location - Location of the issue

30

- `message`: str - Human-readable message text

31

- `doc_url`: Optional[str] - Documentation URL

32

- `is_fixable`: bool - Auto-fixable flag

33

34

**Comparison Methods:**

35

Messages can be compared and sorted. Two messages are equal if they have the same location and code. Messages are sorted first by location, then by code.

36

37

```python { .api }

38

def __eq__(self, other: object) -> bool

39

```

40

41

```python { .api }

42

def __lt__(self, other: "Message") -> bool

43

```

44

45

```python { .api }

46

def __repr__(self) -> str

47

```

48

49

### Location Class

50

51

Represents a specific location in source code where an issue was found.

52

53

```python { .api }

54

class Location:

55

def __init__(self, path: Optional[Union[Path, str]], module: Optional[str],

56

function: Optional[str], line: Optional[int], character: Optional[int],

57

line_end: Optional[int] = None, character_end: Optional[int] = None) -> None

58

```

59

60

Creates a new location object.

61

62

**Parameters:**

63

- `path`: Optional[Union[Path, str]] - File path (converted to absolute Path)

64

- `module`: Optional[str] - Python module name

65

- `function`: Optional[str] - Function or method name where issue occurs

66

- `line`: Optional[int] - Line number (1-based, None for file-level issues)

67

- `character`: Optional[int] - Character position on the line (0-based)

68

- `line_end`: Optional[int] - End line number for multi-line issues

69

- `character_end`: Optional[int] - End character position for multi-line issues

70

71

**Properties:**

72

- `path`: Optional[Path] - Absolute file path

73

- `module`: Optional[str] - Module name

74

- `function`: Optional[str] - Function name

75

- `line`: Optional[int] - Line number

76

- `character`: Optional[int] - Character position

77

- `line_end`: Optional[int] - End line number

78

- `character_end`: Optional[int] - End character position

79

80

```python { .api }

81

def absolute_path(self) -> Optional[Path]

82

```

83

84

Returns the absolute path to the file.

85

86

**Returns:**

87

- `Optional[Path]` - Absolute path or None if no path was provided

88

89

```python { .api }

90

def relative_path(self, root: Optional[Path]) -> Optional[Path]

91

```

92

93

Returns the path relative to the specified root directory.

94

95

**Parameters:**

96

- `root`: Optional[Path] - Root directory for relative path calculation

97

98

**Returns:**

99

- `Optional[Path]` - Relative path if possible, otherwise absolute path

100

101

**Comparison Methods:**

102

Locations can be compared and sorted. Comparison is done by path first, then line, then character.

103

104

```python { .api }

105

def __eq__(self, other: object) -> bool

106

```

107

108

```python { .api }

109

def __lt__(self, other: "Location") -> bool

110

```

111

112

```python { .api }

113

def __hash__(self) -> int

114

```

115

116

```python { .api }

117

def __repr__(self) -> str

118

```

119

120

### Utility Functions

121

122

```python { .api }

123

def make_tool_error_message(filepath: Union[Path, str], source: str, code: str, message: str,

124

line: Optional[int] = None, character: Optional[int] = None,

125

module: Optional[str] = None, function: Optional[str] = None) -> Message

126

```

127

128

Convenience function for creating Message objects for tool errors.

129

130

**Parameters:**

131

- `filepath`: Union[Path, str] - Path to the file

132

- `source`: str - Tool name

133

- `code`: str - Error code

134

- `message`: str - Error message

135

- `line`: Optional[int] - Line number

136

- `character`: Optional[int] - Character position

137

- `module`: Optional[str] - Module name

138

- `function`: Optional[str] - Function name

139

140

**Returns:**

141

- `Message` - New Message object with the specified parameters

142

143

## Usage Examples

144

145

### Creating Messages

146

147

```python

148

from pathlib import Path

149

from prospector.message import Message, Location, make_tool_error_message

150

151

# Create a location

152

location = Location(

153

path=Path("src/main.py"),

154

module="main",

155

function="calculate",

156

line=42,

157

character=10

158

)

159

160

# Create a message

161

message = Message(

162

source="pylint",

163

code="C0103",

164

location=location,

165

message="Invalid name 'x' for variable",

166

doc_url="https://pylint.pycqa.org/en/latest/messages/convention/invalid-name.html",

167

is_fixable=False

168

)

169

170

print(f"Issue: {message.message}")

171

print(f"Location: {message.location}")

172

print(f"From: {message.source}")

173

```

174

175

### Using Convenience Function

176

177

```python

178

from prospector.message import make_tool_error_message

179

180

# Create a message using the convenience function

181

message = make_tool_error_message(

182

filepath="src/utils.py",

183

source="pyflakes",

184

code="unused-import",

185

message="'os' imported but unused",

186

line=1,

187

character=0,

188

module="utils"

189

)

190

191

print(f"{message.source}: {message.message}")

192

```

193

194

### Working with Locations

195

196

```python

197

from pathlib import Path

198

from prospector.message import Location

199

200

# Create location with minimal information

201

location = Location(

202

path="src/main.py",

203

module=None,

204

function=None,

205

line=100,

206

character=15

207

)

208

209

# Get absolute path

210

abs_path = location.absolute_path()

211

print(f"Absolute path: {abs_path}")

212

213

# Get relative path from project root

214

project_root = Path("/home/user/myproject")

215

rel_path = location.relative_path(project_root)

216

print(f"Relative path: {rel_path}")

217

218

# Location for file-level issues

219

file_location = Location(

220

path="setup.py",

221

module=None,

222

function=None,

223

line=None, # No specific line

224

character=None

225

)

226

```

227

228

### Sorting and Comparing Messages

229

230

```python

231

from prospector.message import Message, Location

232

233

# Create multiple messages

234

messages = [

235

Message("pylint", "E501", Location("file2.py", None, None, 10, 0), "Line too long"),

236

Message("pylint", "C0103", Location("file1.py", None, None, 5, 0), "Invalid name"),

237

Message("pyflakes", "unused", Location("file1.py", None, None, 5, 0), "Unused import"),

238

Message("pylint", "E501", Location("file1.py", None, None, 20, 0), "Line too long"),

239

]

240

241

# Sort messages (by location, then by code)

242

sorted_messages = sorted(messages)

243

244

for msg in sorted_messages:

245

print(f"{msg.location.path}:{msg.location.line} {msg.source}:{msg.code} {msg.message}")

246

247

# Check for duplicates

248

msg1 = Message("pylint", "E501", Location("test.py", None, None, 10, 0), "Error 1")

249

msg2 = Message("pylint", "E501", Location("test.py", None, None, 10, 0), "Error 2")

250

251

print(f"Are messages equal? {msg1 == msg2}") # True - same location and code

252

```

253

254

### Multi-line Issues

255

256

```python

257

from prospector.message import Message, Location

258

259

# Create location for multi-line issue

260

location = Location(

261

path="src/complex.py",

262

module="complex",

263

function="long_function",

264

line=50, # Start line

265

character=4, # Start character

266

line_end=55, # End line

267

character_end=8 # End character

268

)

269

270

message = Message(

271

source="pylint",

272

code="R0915",

273

location=location,

274

message="Too many statements (60/50)"

275

)

276

277

print(f"Issue spans lines {location.line}-{location.line_end}")

278

```