Skip to content

Commit 78ef420

Browse files
authored
Fix/revert to line by line parsing (#26)
* Reverted the parsing strategy to go line by line, such that K-codes do not overrule the other data. * Bump version * Tidy documentation * Fix broken test
1 parent 0cdc52e commit 78ef420

11 files changed

Lines changed: 298 additions & 245 deletions

File tree

CHANGES.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# NGI Python SGF Parser Package
22

3+
_2025-05-13_
4+
5+
Version 0.0.8
6+
7+
- Reverted the parsing strategy to go line by line, such that K-codes do not overrule the other data.
8+
39
_2025-04-11_
410

511
Version 0.0.7

poetry.lock

Lines changed: 218 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "sgf-parser"
3-
version = "0.0.7"
3+
version = "0.0.8"
44
description = "Parser for the Swedish Geotechnical Society / Svenska Geotekniska Föreningen (SGF) data format"
55
authors = [{ name = "Jostein Leira", email = "jostein@leira.net" }]
66
requires-python = ">=3.11,<4"

src/sgf_parser/models/method.py

Lines changed: 42 additions & 149 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88

99
from sgf_parser.datetime_parser import convert_str_to_datetime, convert_str_to_time
1010
from sgf_parser.models import MethodType
11-
from sgf_parser.models.types import FlushingVariant, HammeringVariant, RotationVariant
1211

1312

1413
class MethodData(BaseModel, abc.ABC):
@@ -135,11 +134,8 @@ def __repr__(self):
135134

136135
# class Method(BaseModel, abc.ABC):
137136
class Method(BaseModel):
138-
_flushing_variant: FlushingVariant | None = None
139137
_current_flushing_active_state: bool = False
140-
_hammering_variant: HammeringVariant | None = None
141138
_current_hammer_active_state: bool = False
142-
_rotation_variant: RotationVariant | None = None
143139
_current_increased_rotation_state: bool = False
144140

145141
def __init__(self, **kwargs):
@@ -148,31 +144,6 @@ def __init__(self, **kwargs):
148144
def post_processing(self):
149145
pass
150146

151-
def detect_flushing_rule(self) -> FlushingVariant:
152-
"""
153-
Call this with the method data before parsing the method data.
154-
155-
The result of calling this method will set the self.detected_flushing_variant to either use the "K" code if any
156-
regulating the flushing are present, the "AR" (flushing on/off) code or the "I" (flushing pressure) code.
157-
"""
158-
if self._flushing_variant:
159-
return self._flushing_variant
160-
161-
if any(
162-
[
163-
row.comment_code in (72, 73, 76, 77)
164-
or any(x in (72, 73, 76, 77) for x in self.extract_codes(row.remarks))
165-
for row in self.method_data
166-
]
167-
):
168-
self._flushing_variant = FlushingVariant.CODE_K
169-
elif any([getattr(row, "flushing") is not None for row in self.method_data]):
170-
self._flushing_variant = FlushingVariant.CODE_AR
171-
else:
172-
self._flushing_variant = FlushingVariant.CODE_I
173-
174-
return self._flushing_variant
175-
176147
@classmethod
177148
def extract_codes(cls, remarks: str | None) -> tuple[int, ...]:
178149
"""
@@ -195,10 +166,10 @@ def is_flushing_active(
195166
196167
The following priority should be used to figure out if flushing is active:
197168
198-
1. Check K (kode) regulating flushing in file, use only K codes
199-
2. If no K codes present in file, then check if "AR" code is present and has
169+
1. Check K (kode) regulating flushing in file
170+
2. If no K code present, then check if "AR" code is present and has
200171
a value (0 or 0.0 = off, 1 or 1.0 = on)
201-
3. If no "AR" code is present in the file, then check if "I" (flushing pressure) > 0.1
172+
3. If no "AR" code is present, then check if "I" (flushing pressure) > 0.1
202173
4. Otherwise, return False
203174
204175
Codes used:
@@ -207,49 +178,28 @@ def is_flushing_active(
207178
Kode 76 (hammer and flushing on)
208179
Kode 77 (hammer and flushing off)
209180
"""
210-
if self._flushing_variant == FlushingVariant.CODE_K:
211-
if data_row.comment_code in (72, 76) or any(x in (72, 76) for x in self.extract_codes(data_row.remarks)):
181+
if data_row.comment_code in (72, 76) or any(x in (72, 76) for x in self.extract_codes(data_row.remarks)):
182+
self._current_flushing_active_state = True
183+
return self._current_flushing_active_state
184+
# TODO: check remark for extra codes
185+
elif data_row.comment_code in (73, 77) or any(x in (73, 77) for x in self.extract_codes(data_row.remarks)):
186+
self._current_flushing_active_state = False
187+
return self._current_flushing_active_state
188+
189+
if data_row.flushing is not None:
190+
self._current_flushing_active_state = data_row.flushing
191+
return self._current_flushing_active_state
192+
193+
if data_row.flushing_pressure is not None:
194+
if data_row.flushing_pressure > Decimal("0.1"):
212195
self._current_flushing_active_state = True
213-
# TODO: check remark for extra codes
214-
elif data_row.comment_code in (73, 77) or any(x in (73, 77) for x in self.extract_codes(data_row.remarks)):
196+
else:
215197
self._current_flushing_active_state = False
216198

217-
elif self._flushing_variant == FlushingVariant.CODE_AR:
218-
if data_row.flushing is not None:
219-
self._current_flushing_active_state = data_row.flushing
220-
221-
elif self._flushing_variant == FlushingVariant.CODE_I:
222-
if data_row.flushing_pressure is not None:
223-
if data_row.flushing_pressure > Decimal("0.1"):
224-
self._current_flushing_active_state = True
225-
else:
226-
self._current_flushing_active_state = False
199+
return self._current_flushing_active_state
227200

228201
return self._current_flushing_active_state
229202

230-
def detect_hammering_rule(self) -> HammeringVariant | None:
231-
"""
232-
Call this with the method data loaded before parsing the hammering in the method data.
233-
234-
The result of calling this method will set the self._hammering_variant to either use the "K" code if
235-
any regulating the hammering are present, the "AP" (hammering on/off) code.
236-
"""
237-
if self._hammering_variant:
238-
return self._hammering_variant
239-
240-
if any(
241-
[
242-
row.comment_code in (74, 75, 76, 77)
243-
or any(x in (74, 75, 76, 77) for x in self.extract_codes(row.remarks))
244-
for row in self.method_data
245-
]
246-
):
247-
self._hammering_variant = HammeringVariant.K
248-
else:
249-
self._hammering_variant = HammeringVariant.AP
250-
251-
return self._hammering_variant
252-
253203
def is_hammer_active(
254204
self,
255205
data_row, #: models.MethodCPTData| models.MethodTOTData| models.MethodRPData| models.MethodSRSData,
@@ -269,46 +219,18 @@ def is_hammer_active(
269219
Kode 76 (hammer and flushing on)
270220
Kode 77 (hammer and flushing off)
271221
"""
272-
if self._hammering_variant == HammeringVariant.K:
273-
if data_row.comment_code in (74, 76) or any(x in (74, 76) for x in self.extract_codes(data_row.remarks)):
274-
self._current_hammer_active_state = True
275-
return self._current_hammer_active_state
276-
elif data_row.comment_code in (75, 77) or any(x in (75, 77) for x in self.extract_codes(data_row.remarks)):
277-
self._current_hammer_active_state = False
278-
return self._current_hammer_active_state
279-
280-
elif self._hammering_variant == HammeringVariant.AP:
281-
if data_row.hammering is not None:
282-
self._current_hammer_active_state = data_row.hammering
283-
return self._current_hammer_active_state
284-
285-
return self._current_hammer_active_state
286-
287-
def detect_increased_rotation_rule(self) -> RotationVariant | None:
288-
"""
289-
Call this with the method data before updating the increased rotation in the method data.
222+
if data_row.comment_code in (74, 76) or any(x in (74, 76) for x in self.extract_codes(data_row.remarks)):
223+
self._current_hammer_active_state = True
224+
return self._current_hammer_active_state
225+
elif data_row.comment_code in (75, 77) or any(x in (75, 77) for x in self.extract_codes(data_row.remarks)):
226+
self._current_hammer_active_state = False
227+
return self._current_hammer_active_state
290228

291-
The result of calling this method will set the self._increased_rotation_variant to either use the
292-
"K" code if any regulating the increased rotation are present, the "AQ" (increased rotation on/off) code
293-
or the "R" (rotation rate) code.
294-
"""
229+
if data_row.hammering is not None:
230+
self._current_hammer_active_state = data_row.hammering
231+
return self._current_hammer_active_state
295232

296-
if self._rotation_variant:
297-
return self._rotation_variant
298-
299-
if any(
300-
[
301-
row.comment_code in (70, 71) or any(x in (70, 71) for x in self.extract_codes(row.remarks))
302-
for row in self.method_data
303-
]
304-
):
305-
self._rotation_variant = RotationVariant.K
306-
elif any([row.increased_rotation_rate is not None for row in self.method_data]):
307-
self._rotation_variant = RotationVariant.AQ
308-
else:
309-
self._rotation_variant = RotationVariant.R
310-
311-
return self._rotation_variant
233+
return self._current_hammer_active_state
312234

313235
def is_increased_rotation_active(
314236
self,
@@ -328,53 +250,24 @@ def is_increased_rotation_active(
328250
Kode 70 (increased rotation speed on)
329251
Kode 71 (increased rotation speed off)
330252
"""
331-
if self._rotation_variant == RotationVariant.K:
332-
if data_row.comment_code == 70:
253+
if data_row.comment_code == 70:
254+
self._current_increased_rotation_state = True
255+
return self._current_increased_rotation_state
256+
elif data_row.comment_code == 71:
257+
self._current_increased_rotation_state = False
258+
return self._current_increased_rotation_state
259+
if data_row.increased_rotation_rate is not None:
260+
self._current_increased_rotation_state = data_row.increased_rotation_rate
261+
return self._current_increased_rotation_state
262+
if data_row.rotation_rate is not None:
263+
if data_row.rotation_rate > 35:
333264
self._current_increased_rotation_state = True
334-
elif data_row.comment_code == 71:
265+
else:
335266
self._current_increased_rotation_state = False
336-
elif self._rotation_variant == RotationVariant.AQ:
337-
if data_row.increased_rotation_rate is not None:
338-
self._current_increased_rotation_state = data_row.increased_rotation_rate
339-
else:
340-
if data_row.rotation_rate is not None:
341-
if data_row.rotation_rate > 35:
342-
self._current_increased_rotation_state = True
343-
else:
344-
self._current_increased_rotation_state = False
267+
return self._current_increased_rotation_state
345268

346269
return self._current_increased_rotation_state
347270

348-
def flushing_update(self):
349-
"""
350-
Update flushing
351-
352-
"""
353-
self._flushing_variant = self.detect_flushing_rule()
354-
355-
for data in self.method_data:
356-
data.flushing = self.is_flushing_active(data)
357-
358-
def hammering_update(self):
359-
"""
360-
Update hammering
361-
362-
"""
363-
self._hammering_variant = self.detect_hammering_rule()
364-
365-
for data in self.method_data:
366-
data.hammering = self.is_hammer_active(data)
367-
368-
def rotation_update(self):
369-
"""
370-
Update rotation
371-
372-
"""
373-
self._rotation_variant = self.detect_increased_rotation_rule()
374-
375-
for data in self.method_data:
376-
data.increased_rotation_rate = self.is_increased_rotation_active(data)
377-
378271
@model_validator(mode="before")
379272
@classmethod
380273
def guess_date_format(cls, data: Any) -> Any:

src/sgf_parser/models/method_rp.py

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -39,16 +39,3 @@ def __init__(self, **kwargs):
3939
method_data_type: type[MethodRPData] = MethodRPData
4040

4141
method_data: list[MethodRPData] = []
42-
43-
def post_processing(self):
44-
"""
45-
Post-processing
46-
47-
"""
48-
49-
if not self.method_data:
50-
return
51-
52-
# Update flushing and increased rotation
53-
self.flushing_update()
54-
self.rotation_update()

src/sgf_parser/models/method_srs.py

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -93,20 +93,6 @@ def set_sounding_class(cls, data: Any) -> Any:
9393

9494
return data
9595

96-
def post_processing(self):
97-
"""
98-
Post-processing
99-
100-
"""
101-
102-
if not self.method_data:
103-
return
104-
105-
# Update flushing, hammering and increased rotation
106-
self.flushing_update()
107-
self.hammering_update()
108-
self.rotation_update()
109-
11096
@computed_field
11197
def depth_in_rock(self) -> Decimal | None:
11298
_rock_top_depth = None

src/sgf_parser/models/method_tot.py

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -159,17 +159,3 @@ def bedrock_elevation(self) -> Decimal | None:
159159
return Decimal(self.point_z) - _depth_in_soil
160160

161161
return None
162-
163-
def post_processing(self):
164-
"""
165-
Post-processing
166-
167-
"""
168-
169-
if not self.method_data:
170-
return
171-
172-
# Update flushing, hammering and increased rotation
173-
self.flushing_update()
174-
self.hammering_update()
175-
self.rotation_update()

src/sgf_parser/models/types.py

Lines changed: 0 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -81,35 +81,6 @@ class ParseState(enum.Enum):
8181
QUIT = 3
8282

8383

84-
class FlushingVariant(enum.StrEnum):
85-
"""
86-
Flushing variants
87-
"""
88-
89-
CODE_K = "K"
90-
CODE_AR = "AR"
91-
CODE_I = "I"
92-
93-
94-
class HammeringVariant(enum.StrEnum):
95-
"""
96-
Hammering variants
97-
"""
98-
99-
K = "K"
100-
AP = "AP"
101-
102-
103-
class RotationVariant(enum.StrEnum):
104-
"""
105-
Rotation variants
106-
"""
107-
108-
K = "K"
109-
AQ = "AQ"
110-
R = "R"
111-
112-
11384
class SoundingClass(enum.StrEnum):
11485
"""
11586
Soil-Rock-Sounding (Swedish Jord-bergsondering) classes

src/sgf_parser/parser.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,4 +142,10 @@ def parse_header(self, header: dict[str, Any]) -> Method:
142142
def parse_data(self, method: Method, row: str) -> MethodData:
143143
row_dict = self._convert_str_to_dict(row)
144144
method_data = method.method_data_type.model_validate(row_dict)
145+
if hasattr(method_data, "flushing"):
146+
method_data.flushing = method.is_flushing_active(method_data)
147+
if hasattr(method_data, "hammering"):
148+
method_data.hammering = method.is_hammer_active(method_data)
149+
if hasattr(method_data, "increased_rotation_rate"):
150+
method_data.increased_rotation_rate = method.is_increased_rotation_active(method_data)
145151
return method_data

tests/integration/test_parse.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -510,9 +510,9 @@ def test_return_one_method_one_placeholder(
510510
datetime(2018, 11, 20, 10, 50,21),
511511
{
512512
# load=A, hammering=AP, load=W, turning=H, rotation_rate=R
513-
Decimal("3.625"): {"load":Decimal("1.020"), "turning":Decimal("152"), "penetration_rate": Decimal("154.208"), "comment_code": None, "remarks": None, "hammering": None},
514-
Decimal("3.700"): {"load": Decimal("1.020"), "turning": Decimal("24"), "penetration_rate": Decimal("10.287"), "hammering": None,},
515-
Decimal("3.775"): {"load": Decimal("5.681"), "turning": Decimal("24"), "penetration_rate": Decimal("1.506"), "hammering": None, "comment_code": 91, "remarks": "Sond kan ej drivas normalt"},
513+
Decimal("3.625"): {"load":Decimal("1.020"), "turning":Decimal("152"), "penetration_rate": Decimal("154.208"), "comment_code": None, "remarks": None, "hammering": False},
514+
Decimal("3.700"): {"load": Decimal("1.020"), "turning": Decimal("24"), "penetration_rate": Decimal("10.287"), "hammering": False,},
515+
Decimal("3.775"): {"load": Decimal("5.681"), "turning": Decimal("24"), "penetration_rate": Decimal("1.506"), "hammering": False, "comment_code": 91, "remarks": "Sond kan ej drivas normalt"},
516516
},
517517
),
518518
),

0 commit comments

Comments
 (0)