compass-lib 0.0.2__py3-none-any.whl → 0.0.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
compass_lib/constants.py CHANGED
@@ -1,36 +1,84 @@
1
- from __future__ import annotations
2
-
3
- import re
4
-
5
- from compass_lib.enums import ShotFlag
6
-
7
- # ============================== SPECIAL CHARS ============================== #
8
-
9
- COMPASS_SECTION_SEPARATOR = "\f" # Form_feed: https://www.ascii-code.com/12
10
- COMPASS_END_OF_FILE = "\x1a" # Substitute: https://www.ascii-code.com/26
11
-
12
- # ================================== REGEX ================================== #
13
- # Priorized regex:
14
- # 1. Section Split with `\r\n`
15
- # 2. Section Split with `\n`
16
- # 3. Section Split with `\f` alone
17
- COMPASS_SECTION_SPLIT_RE = re.compile(
18
- rf"{COMPASS_SECTION_SEPARATOR}\r\n|{COMPASS_SECTION_SEPARATOR}\n|{COMPASS_SECTION_SEPARATOR}"
19
- )
20
-
21
- # String format:
22
- # - `SURVEY NAME: toc+187?`
23
- COMPASS_SECTION_NAME_RE = re.compile(r"SURVEY NAME:\s*(?P<section_name>\S*)")
24
-
25
- # String format:
26
- # - `SURVEY DATE: 1 26 86`
27
- # - `SURVEY DATE: 4 22 2001`
28
- # - `SURVEY DATE: 8 28 1988 COMMENT:Surface to shelter`
29
- COMPASS_DATE_COMMENT_RE = re.compile(
30
- r"^SURVEY DATE:\s*(?P<date>\d{1,2}\s+\d{1,2}\s+\d{2,4}|None)(?:\s+COMMENT:\s*(?P<comment>.*))?$" # noqa: E501
31
- )
32
-
33
- COMPASS_SHOT_FLAGS_RE = re.compile(
34
- rf"({ShotFlag.__start_token__}"
35
- rf"([{''.join(ShotFlag._value2member_map_.keys())}]*){ShotFlag.__end_token__})*(.*)"
36
- )
1
+ # -*- coding: utf-8 -*-
2
+ """Constants used throughout the compass_lib library.
3
+
4
+ This module centralizes all constant values to ensure consistency
5
+ and avoid magic numbers/strings scattered across the codebase.
6
+ """
7
+
8
+ # -----------------------------------------------------------------------------
9
+ # File Encodings
10
+ # -----------------------------------------------------------------------------
11
+
12
+ #: Default encoding for Compass files (Windows-1252 / CP1252)
13
+ COMPASS_ENCODING = "cp1252"
14
+
15
+ #: Encoding used for JSON files
16
+ JSON_ENCODING = "utf-8"
17
+
18
+ #: Encoding used when reading raw Compass files (ASCII with replacements)
19
+ ASCII_ENCODING = "ascii"
20
+
21
+ # -----------------------------------------------------------------------------
22
+ # Unit Conversions
23
+ # -----------------------------------------------------------------------------
24
+
25
+ #: Conversion factor from feet to meters
26
+ FEET_TO_METERS: float = 0.3048
27
+
28
+ #: Conversion factor from meters to feet
29
+ METERS_TO_FEET: float = 1.0 / FEET_TO_METERS
30
+
31
+ # -----------------------------------------------------------------------------
32
+ # Missing Data Indicators
33
+ # -----------------------------------------------------------------------------
34
+
35
+ #: Values >= this threshold indicate missing data for distances/measurements
36
+ MISSING_VALUE_THRESHOLD: float = 990.0
37
+
38
+ #: Values <= this threshold indicate missing data for angles
39
+ MISSING_ANGLE_THRESHOLD: float = -900.0
40
+
41
+ #: String representation of missing value in formatted output
42
+ MISSING_VALUE_STRING: str = "-999.00"
43
+
44
+ #: Null LRUD values used in PLT files (either 999.0 or 999.9 indicates missing)
45
+ NULL_LRUD_VALUES: tuple[float, float] = (999.0, 999.9)
46
+
47
+ # -----------------------------------------------------------------------------
48
+ # Formatting Constants
49
+ # -----------------------------------------------------------------------------
50
+
51
+ #: Width of station name column in DAT files
52
+ STATION_NAME_WIDTH: int = 13
53
+
54
+ #: Width of numeric columns in DAT files
55
+ NUMBER_WIDTH: int = 8
56
+
57
+ #: Decimal precision for GeoJSON coordinates (WGS84)
58
+ GEOJSON_COORDINATE_PRECISION: int = 7
59
+
60
+ #: Decimal precision for elevation values in GeoJSON
61
+ GEOJSON_ELEVATION_PRECISION: int = 2
62
+
63
+ # -----------------------------------------------------------------------------
64
+ # Shot Flag Characters
65
+ # -----------------------------------------------------------------------------
66
+
67
+ #: Mapping of shot flags to their character representations
68
+ FLAG_CHARS: dict[str, str] = {
69
+ "exclude_distance": "L",
70
+ "exclude_from_plotting": "P",
71
+ "exclude_from_all_processing": "X",
72
+ "do_not_adjust": "C",
73
+ }
74
+
75
+ # -----------------------------------------------------------------------------
76
+ # UTM Constants
77
+ # -----------------------------------------------------------------------------
78
+
79
+ #: Southern hemisphere UTM northing offset (10 million meters)
80
+ #: Note: This constant represents the false northing added to southern hemisphere
81
+ #: UTM coordinates. However, in Compass, hemisphere is determined by the ZONE SIGN
82
+ #: (positive = north, negative = south), NOT by comparing northing to this threshold.
83
+ #: This constant is kept for reference and potential future use.
84
+ UTM_SOUTHERN_HEMISPHERE_OFFSET: float = 10_000_000.0
compass_lib/enums.py CHANGED
@@ -1,119 +1,240 @@
1
- from __future__ import annotations
1
+ # -*- coding: utf-8 -*-
2
+ """Enumerations for Compass file formats.
3
+
4
+ This module contains all enumerations used in Compass survey data formats,
5
+ including units for measurements, file types, and various classification types.
6
+ """
2
7
 
3
8
  from enum import Enum
4
- from enum import IntEnum
5
- from pathlib import Path
6
- from typing import TYPE_CHECKING
9
+ from math import radians
10
+ from math import tan
7
11
 
8
- if TYPE_CHECKING:
9
- from typing_extensions import Self
12
+ from compass_lib.constants import FEET_TO_METERS
10
13
 
11
14
 
12
- class CustomEnum(Enum):
13
- @classmethod
14
- def reverse(cls, name):
15
- return cls._value2member_map_[name]
15
+ class FileFormat(str, Enum):
16
+ """File format types for conversion operations.
16
17
 
18
+ Attributes:
19
+ COMPASS: Native Compass binary/text format (.dat, .mak, .plt)
20
+ JSON: JSON serialization format
21
+ GEOJSON: GeoJSON geographic format
22
+ """
17
23
 
18
- class CompassFileType(IntEnum):
19
- DAT = 0
20
- MAK = 1
21
- PLT = 2
24
+ COMPASS = "compass"
25
+ JSON = "json"
26
+ GEOJSON = "geojson"
22
27
 
23
- @classmethod
24
- def from_str(cls, value: str) -> Self:
25
- try:
26
- return cls[value.upper()]
27
- except KeyError as e:
28
- raise ValueError(f"Unknown value: {value.upper()}") from e
28
+
29
+ class CompassFileType(str, Enum):
30
+ """Types of Compass files.
31
+
32
+ Attributes:
33
+ DAT: Survey data file containing shots
34
+ MAK: Project/make file linking DAT files
35
+ PLT: Plot file with processed survey data
36
+ """
37
+
38
+ DAT = "dat"
39
+ MAK = "mak"
40
+ PLT = "plt"
41
+
42
+ @property
43
+ def extension(self) -> str:
44
+ """Get the file extension for this type (with dot)."""
45
+ return {
46
+ CompassFileType.DAT: FileExtension.DAT.value,
47
+ CompassFileType.MAK: FileExtension.MAK.value,
48
+ CompassFileType.PLT: FileExtension.PLT.value,
49
+ }[self]
29
50
 
30
51
  @classmethod
31
- def from_path(cls, filepath: str | Path):
32
- if not isinstance(filepath, Path):
33
- filepath = Path(filepath)
52
+ def from_extension(cls, ext: str) -> "CompassFileType | None":
53
+ """Get file type from extension.
54
+
55
+ Args:
56
+ ext: File extension (with or without dot, case-insensitive)
34
57
 
35
- return cls.from_str(filepath.suffix.upper()[1:]) # Remove the leading `.`
58
+ Returns:
59
+ CompassFileType or None if not recognized
60
+ """
61
+ ext_lower = ext.lower().lstrip(".")
62
+ mapping = {
63
+ "dat": cls.DAT,
64
+ "mak": cls.MAK,
65
+ "plt": cls.PLT,
66
+ }
67
+ return mapping.get(ext_lower)
36
68
 
37
69
 
38
- # ============================== Azimuth ============================== #
70
+ class FileExtension(str, Enum):
71
+ """File extensions for various file formats (with dot).
39
72
 
40
- # export const azimuthUnits: { [string]: DisplayAzimuthUnit } = {
41
- # D: 'degrees',
42
- # Q: 'quads',
43
- # G: 'gradians',
44
- # }
73
+ Attributes:
74
+ DAT: Compass survey data file extension
75
+ MAK: Compass project/make file extension
76
+ PLT: Compass plot file extension
77
+ JSON: JSON file extension
78
+ GEOJSON: GeoJSON file extension
79
+ """
45
80
 
81
+ DAT = ".dat"
82
+ MAK = ".mak"
83
+ PLT = ".plt"
84
+ JSON = ".json"
85
+ GEOJSON = ".geojson"
86
+
87
+
88
+ class FormatIdentifier(str, Enum):
89
+ """Format identifiers used in JSON files.
90
+
91
+ Attributes:
92
+ COMPASS_DAT: Format identifier for DAT files in JSON
93
+ COMPASS_MAK: Format identifier for MAK/project files in JSON
94
+ """
95
+
96
+ COMPASS_DAT = "compass_dat"
97
+ COMPASS_MAK = "compass_mak"
98
+
99
+
100
+ class AzimuthUnit(str, Enum):
101
+ """Unit for compass azimuth (bearing) measurements.
102
+
103
+ Attributes:
104
+ DEGREES: Standard degrees (0-360)
105
+ QUADS: Quadrant notation
106
+ GRADS: Gradians (400 per circle)
107
+ """
46
108
 
47
- class AzimuthUnits(CustomEnum):
48
109
  DEGREES = "D"
49
110
  QUADS = "Q"
50
- GRADIANS = "G"
111
+ GRADS = "R"
112
+
113
+ @staticmethod
114
+ def convert(degrees: float | None, to_unit: "AzimuthUnit") -> float | None:
115
+ """Convert degrees to the target unit.
51
116
 
117
+ Args:
118
+ degrees: Value in degrees (or None)
119
+ to_unit: Target unit to convert to
52
120
 
53
- # ============================== Inclination Unit ============================== #
121
+ Returns:
122
+ Converted value or None if input is None
123
+ """
124
+ if degrees is None:
125
+ return None
126
+ if to_unit == AzimuthUnit.GRADS:
127
+ return degrees * 400 / 360
128
+ return degrees
54
129
 
55
- # export const inclinationUnits: { [string]: DisplayInclinationUnit } = {
56
- # D: 'degrees',
57
- # G: 'percentGrade',
58
- # M: 'degreesAndMinutes',
59
- # R: 'gradians',
60
- # W: 'depthGauge',
61
- # }
62
130
 
131
+ class InclinationUnit(str, Enum):
132
+ """Unit for vertical angle (inclination) measurements.
133
+
134
+ Attributes:
135
+ DEGREES: Standard degrees (-90 to +90)
136
+ PERCENT_GRADE: Percentage gradient (tan(angle) * 100)
137
+ DEGREES_AND_MINUTES: Degrees with minutes notation
138
+ GRADS: Gradians
139
+ DEPTH_GAUGE: Depth gauge reading
140
+ """
63
141
 
64
- class InclinationUnits(CustomEnum):
65
142
  DEGREES = "D"
66
143
  PERCENT_GRADE = "G"
67
144
  DEGREES_AND_MINUTES = "M"
68
- GRADIANS = "R"
145
+ GRADS = "R"
69
146
  DEPTH_GAUGE = "W"
70
147
 
148
+ @staticmethod
149
+ def convert(value: float | None, to_unit: "InclinationUnit") -> float | None:
150
+ """Convert degrees to the target unit.
151
+
152
+ Args:
153
+ value: Value in degrees (or None)
154
+ to_unit: Target unit to convert to
71
155
 
72
- # ============================== Length Unit ============================== #
156
+ Returns:
157
+ Converted value or None if input is None
158
+ """
159
+ if value is None:
160
+ return None
161
+ if to_unit == InclinationUnit.PERCENT_GRADE:
162
+ return tan(radians(value)) * 100
163
+ if to_unit == InclinationUnit.GRADS:
164
+ return value * 200 / 180
165
+ return value
73
166
 
74
167
 
75
- # export const lengthUnits: { [string]: DisplayLengthUnit } = {
76
- # D: 'decimalFeet',
77
- # I: 'feetAndInches',
78
- # M: 'meters',
79
- # }
168
+ class LengthUnit(str, Enum):
169
+ """Unit for distance measurements.
80
170
 
171
+ Attributes:
172
+ DECIMAL_FEET: Standard feet with decimals
173
+ FEET_AND_INCHES: Feet and inches notation
174
+ METERS: Metric meters
175
+ """
81
176
 
82
- class LengthUnits(CustomEnum):
83
177
  DECIMAL_FEET = "D"
84
178
  FEET_AND_INCHES = "I"
85
179
  METERS = "M"
86
180
 
181
+ @staticmethod
182
+ def convert(feet: float | None, to_unit: "LengthUnit") -> float | None:
183
+ """Convert feet to the target unit.
184
+
185
+ Args:
186
+ feet: Value in feet (or None)
187
+ to_unit: Target unit to convert to
188
+
189
+ Returns:
190
+ Converted value or None if input is None
191
+ """
192
+ if feet is None:
193
+ return None
194
+ if to_unit == LengthUnit.METERS:
195
+ return feet * FEET_TO_METERS
196
+ return feet
197
+
198
+
199
+ class LrudAssociation(str, Enum):
200
+ """Indicates which station LRUD measurements are associated with.
201
+
202
+ Attributes:
203
+ FROM: LRUD measured at the FROM station
204
+ TO: LRUD measured at the TO station
205
+ """
206
+
207
+ FROM = "F"
208
+ TO = "T"
87
209
 
88
- # ============================== LRUD ============================== #
89
210
 
90
- # export const lrudItems: { [string]: LrudItem } = {
91
- # L: 'left',
92
- # R: 'right',
93
- # U: 'up',
94
- # D: 'down',
95
- # }
211
+ class LrudItem(str, Enum):
212
+ """Individual LRUD dimension identifiers.
96
213
 
214
+ Attributes:
215
+ LEFT: Distance to left wall
216
+ RIGHT: Distance to right wall
217
+ UP: Distance to ceiling
218
+ DOWN: Distance to floor
219
+ """
97
220
 
98
- class LRUD(CustomEnum):
99
221
  LEFT = "L"
100
222
  RIGHT = "R"
101
223
  UP = "U"
102
224
  DOWN = "D"
103
225
 
104
226
 
105
- # ============================== ShotItem ============================== #
227
+ class ShotItem(str, Enum):
228
+ """Components of a shot measurement for format ordering.
106
229
 
107
- # export const shotMeasurementItems: { [string]: ShotMeasurementItem } = {
108
- # L: 'length',
109
- # A: 'frontsightAzimuth',
110
- # D: 'frontsightInclination',
111
- # a: 'backsightAzimuth',
112
- # d: 'backsightInclination',
113
- # }
230
+ Attributes:
231
+ LENGTH: Distance between stations
232
+ FRONTSIGHT_AZIMUTH: Compass bearing forward
233
+ FRONTSIGHT_INCLINATION: Vertical angle forward
234
+ BACKSIGHT_AZIMUTH: Compass bearing backward
235
+ BACKSIGHT_INCLINATION: Vertical angle backward
236
+ """
114
237
 
115
-
116
- class ShotItem(CustomEnum):
117
238
  LENGTH = "L"
118
239
  FRONTSIGHT_AZIMUTH = "A"
119
240
  FRONTSIGHT_INCLINATION = "D"
@@ -121,28 +242,115 @@ class ShotItem(CustomEnum):
121
242
  BACKSIGHT_INCLINATION = "d"
122
243
 
123
244
 
124
- # ============================== StationSide ============================== #
245
+ class Severity(str, Enum):
246
+ """Severity level for parse errors.
247
+
248
+ Attributes:
249
+ ERROR: Critical parsing error
250
+ WARNING: Non-fatal warning
251
+ """
252
+
253
+ ERROR = "error"
254
+ WARNING = "warning"
255
+
256
+
257
+ class DrawOperation(str, Enum):
258
+ """Drawing operations for plot commands.
259
+
260
+ Attributes:
261
+ MOVE_TO: Move to location without drawing
262
+ LINE_TO: Draw line to location
263
+ """
264
+
265
+ MOVE_TO = "M"
266
+ LINE_TO = "D"
267
+
268
+
269
+ class Datum(str, Enum):
270
+ """Geodetic datum values supported by Compass.
271
+
272
+ These are the standard datum values that can be used in MAK project files.
273
+ The enum values match the exact strings used in Compass MAK files.
274
+
275
+ Attributes:
276
+ ADINDAN: Adindan datum
277
+ ARC_1950: Arc 1950 datum
278
+ ARC_1960: Arc 1960 datum
279
+ AUSTRALIAN_1966: Australian 1966 datum
280
+ AUSTRALIAN_1984: Australian 1984 datum
281
+ CAMP_AREA_ASTRO: Camp Area Astro datum
282
+ CAPE: Cape datum
283
+ EUROPEAN_1950: European 1950 datum
284
+ EUROPEAN_1979: European 1979 datum
285
+ GEODETIC_1949: Geodetic 1949 datum
286
+ HONG_KONG_1963: Hong Kong 1963 datum
287
+ HU_TZU_SHAN: Hu Tzu Shan datum
288
+ INDIAN: Indian datum
289
+ NORTH_AMERICAN_1927: North American 1927 datum (NAD27)
290
+ NORTH_AMERICAN_1983: North American 1983 datum (NAD83)
291
+ OMAN: Oman datum
292
+ ORDNANCE_SURVEY_1936: Ordnance Survey 1936 datum
293
+ PULKOVO_1942: Pulkovo 1942 datum
294
+ SOUTH_AMERICAN_1956: South American 1956 datum
295
+ SOUTH_AMERICAN_1969: South American 1969 datum
296
+ TOKYO: Tokyo datum
297
+ WGS_1972: WGS 1972 datum
298
+ WGS_1984: WGS 1984 datum
299
+ """
300
+
301
+ ADINDAN = "Adindan"
302
+ ARC_1950 = "Arc 1950"
303
+ ARC_1960 = "Arc 1960"
304
+ AUSTRALIAN_1966 = "Australian 1966"
305
+ AUSTRALIAN_1984 = "Australian 1984"
306
+ CAMP_AREA_ASTRO = "Camp Area Astro"
307
+ CAPE = "Cape"
308
+ EUROPEAN_1950 = "European 1950"
309
+ EUROPEAN_1979 = "European 1979"
310
+ GEODETIC_1949 = "Geodetic 1949"
311
+ HONG_KONG_1963 = "Hong Kong 1963"
312
+ HU_TZU_SHAN = "Hu Tzu Shan"
313
+ INDIAN = "Indian"
314
+ NORTH_AMERICAN_1927 = "North American 1927"
315
+ NORTH_AMERICAN_1983 = "North American 1983"
316
+ OMAN = "Oman"
317
+ ORDNANCE_SURVEY_1936 = "Ordnance Survey 1936"
318
+ PULKOVO_1942 = "Pulkovo 1942"
319
+ SOUTH_AMERICAN_1956 = "South American 1956"
320
+ SOUTH_AMERICAN_1969 = "South American 1969"
321
+ TOKYO = "Tokyo"
322
+ WGS_1972 = "WGS 1972"
323
+ WGS_1984 = "WGS 1984"
324
+
325
+ @classmethod
326
+ def normalize(cls, value: str | None) -> "Datum | None":
327
+ """Normalize and validate a datum string to a Datum enum value.
125
328
 
126
- # export const stationSides: { [string]: StationSide } = {
127
- # F: 'from',
128
- # T: 'to',
129
- # }
329
+ Performs case-insensitive matching with whitespace normalization.
130
330
 
331
+ Args:
332
+ value: The datum string to normalize (case-insensitive)
131
333
 
132
- class StationSide(CustomEnum):
133
- FROM = "F"
134
- TO = "T"
334
+ Returns:
335
+ The corresponding Datum enum value, or None if value is None
135
336
 
337
+ Raises:
338
+ ValueError: If the datum string is not recognized
339
+ """
340
+ if value is None:
341
+ return None
136
342
 
137
- # ============================== ShotFlag ============================== #
343
+ # Normalize: lowercase, strip whitespace, collapse multiple spaces
344
+ normalized = " ".join(value.strip().lower().split())
138
345
 
346
+ # Match against enum values (case-insensitive)
347
+ for datum in cls:
348
+ if datum.value.lower() == normalized:
349
+ return datum
139
350
 
140
- class ShotFlag(CustomEnum):
141
- EXCLUDE_PLOTING = "P"
142
- EXCLUDE_CLOSURE = "C"
143
- EXCLUDE_LENGTH = "L"
144
- TOTAL_EXCLUSION = "X"
145
- SPLAY = "S"
351
+ raise ValueError(f"Unknown datum: {value!r}")
146
352
 
147
- __start_token__ = r"#\|" # noqa: S105
148
- __end_token__ = r"#" # noqa: S105
353
+ @classmethod
354
+ def from_string(cls, value: str | None) -> "Datum | None":
355
+ """Alias for normalize() for backwards compatibility."""
356
+ return cls.normalize(value)
compass_lib/errors.py ADDED
@@ -0,0 +1,86 @@
1
+ # -*- coding: utf-8 -*-
2
+ """Error handling for Compass file parsing.
3
+
4
+ This module provides error classes for tracking parsing errors with
5
+ source location information for helpful error messages.
6
+ """
7
+
8
+ from dataclasses import dataclass
9
+
10
+ from compass_lib.enums import Severity
11
+
12
+
13
+ @dataclass(frozen=True)
14
+ class SourceLocation:
15
+ """Tracks the source location of text for error reporting.
16
+
17
+ Attributes:
18
+ source: The source file name or identifier
19
+ line: Line number (0-based)
20
+ column: Column number (0-based)
21
+ text: The text at this location
22
+ """
23
+
24
+ source: str
25
+ line: int
26
+ column: int
27
+ text: str
28
+
29
+ def __str__(self) -> str:
30
+ """Format as human-readable location string."""
31
+ return f"(in {self.source}, line {self.line + 1}, column {self.column + 1})"
32
+
33
+
34
+ @dataclass(frozen=True)
35
+ class CompassParseError:
36
+ """Represents a parsing error or warning with source location.
37
+
38
+ This is a data record for storing error information, not an exception.
39
+ Use CompassParseException for raising errors.
40
+
41
+ Attributes:
42
+ severity: ERROR or WARNING
43
+ message: Human-readable error message
44
+ location: Source location where error occurred (optional)
45
+ """
46
+
47
+ severity: Severity
48
+ message: str
49
+ location: SourceLocation | None = None
50
+
51
+ def __str__(self) -> str:
52
+ """Format as human-readable error string."""
53
+ base = f"{self.severity.value}: {self.message}"
54
+ if self.location:
55
+ base += f" {self.location}"
56
+ if self.location.text:
57
+ base += f"\n {self.location.text}"
58
+ return base
59
+
60
+
61
+ class CompassParseException(Exception): # noqa: N818
62
+ """Exception raised for critical parsing errors.
63
+
64
+ Attributes:
65
+ message: Error message
66
+ location: Source location where error occurred
67
+ """
68
+
69
+ def __init__(self, message: str, location: SourceLocation | None = None):
70
+ self.message = message
71
+ self.location = location
72
+ super().__init__(str(self))
73
+
74
+ def __str__(self) -> str:
75
+ """Format as human-readable exception string."""
76
+ if self.location:
77
+ return f"{self.message} {self.location}"
78
+ return self.message
79
+
80
+ def to_error(self) -> CompassParseError:
81
+ """Convert exception to CompassParseError record."""
82
+ return CompassParseError(
83
+ severity=Severity.ERROR,
84
+ message=self.message,
85
+ location=self.location,
86
+ )