Skip to content

Commit 5aaeea2

Browse files
committed
NPI-4492 slight revisions to simplify IGS log LOC block extractor and make it more testable
1 parent 9bafcae commit 5aaeea2

2 files changed

Lines changed: 74 additions & 14 deletions

File tree

gnssanalysis/gn_io/igslog.py

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import re as _re
66
from multiprocessing import Pool as _Pool
77
from typing import Optional, Union
8+
import warnings
89

910
import numpy as _np
1011
import pandas as _pd
@@ -59,6 +60,7 @@
5960
_re.IGNORECASE | _re.VERBOSE,
6061
)
6162

63+
# See example here: https://files.igs.org/pub/station/general/blank.log
6264
_REGEX_LOC_V2 = _re.compile(
6365
rb"""
6466
2.+\W+City\sor\sTown\s+\:\s*(\w[^\(\n\,/\?]+|).*\W+
@@ -222,15 +224,24 @@ def extract_id_block(
222224
return id_block
223225

224226

225-
def extract_location_block(data: bytes, file_path: str, version: Union[str, None] = None) -> _np.ndarray:
227+
def extract_location_block(
228+
data: bytes,
229+
file_path: str,
230+
version: Union[str, None] = None,
231+
raise_on_extract_failure: bool = True,
232+
raise_on_unexpected_element_count: bool = True,
233+
) -> list[str]:
226234
"""Extract the location block given the bytes object read from an IGS site log file
227235
228236
:param bytes data: The bytes object returned from an open() call on a IGS site log in "rb" mode
229237
:param str file_path: The path to the file from which the "data" bytes object was obtained
230238
:param str version: Version number of log file (e.g. "v2.0") - will be determined from input data unless
231239
provided here.
240+
:param bool raise_on_extract_failure: raise (default) rather than just warning, if regex extract fails
241+
:param bool raise_on_unexpected_element_count: raise (default) rather than just warning, if LOC elements count != 8
232242
:raises LogVersionError: Raises an error if an unknown version string is passed in
233-
:return _np.ndarray: The location block of the IGS site log, as a numpy NDArray of strings
243+
:raises ValueError: If an the location block regex does not match, or if the number of elements extracted is not 8
244+
:return list[str]: The location block of the IGS site log, as a list of strings
234245
"""
235246
if version == None:
236247
version = determine_log_version(data)
@@ -242,11 +253,26 @@ def extract_location_block(data: bytes, file_path: str, version: Union[str, None
242253
else:
243254
raise LogVersionError(f"Incorrect version string '{version}' passed to extract_location_block() function")
244255

245-
location_block = _REGEX_LOC.search(data)
246-
if location_block is None:
247-
logger.warning(f"LOC rejected from {file_path}")
248-
return _np.array([]).reshape(0, 12)
249-
return location_block
256+
loc_block_match = _REGEX_LOC.search(data)
257+
if loc_block_match is None:
258+
if raise_on_extract_failure:
259+
raise ValueError(f"Failed to extract LOC block from {file_path}")
260+
warnings.warn(f"Failed to extract LOC block from {file_path}")
261+
return []
262+
263+
# List of location properties.
264+
# See example under '2. Site Location Information' here: https://files.igs.org/pub/station/general/blank.log
265+
loc_block_decoded = [group.decode(encoding="utf8", errors="ignore") for group in loc_block_match.groups()]
266+
267+
loc_element_count = len(loc_block_decoded)
268+
if loc_element_count != 8:
269+
# TODO consider using t-strings in Python 3.14
270+
loc_count_warning = "Expected 8 elements in LOC block, got: {block_length}, file: {file_path}"
271+
if raise_on_unexpected_element_count:
272+
raise ValueError(loc_count_warning.format(block_length=loc_element_count, file_path=file_path))
273+
warnings.warn(loc_count_warning.format(block_length=loc_element_count, file_path=file_path))
274+
275+
return loc_block_decoded
250276

251277

252278
def extract_receiver_block(data: bytes, file_path: str) -> Union[list[tuple[bytes]], _np.ndarray]:
@@ -304,7 +330,6 @@ def parse_igs_log_data(data: bytes, file_path: str, file_code: str) -> Union[_np
304330
file_path=file_path,
305331
version=version,
306332
)
307-
blk_loc = [group.decode(encoding="utf8", errors="ignore") for group in blk_loc.groups()]
308333
# Combine ID and Location information:
309334
blk_id_loc = _np.asarray([0] + blk_id + blk_loc, dtype=object)[_np.newaxis]
310335
# Extract and re-format information from receiver block:

tests/test_igslog.py

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,16 +42,51 @@ def test_extract_id_block(self):
4242
def test_extract_location_block(self):
4343
# Version 1 Location description results:
4444
v1_location_block = igslog.extract_location_block(v1_data, "/example/path", "v1.0")
45-
self.assertEqual(v1_location_block.group(1), b"Les Abymes")
46-
self.assertEqual(v1_location_block.group(2), b"Guadeloupe")
45+
self.assertEqual(v1_location_block[0], "Les Abymes")
46+
self.assertEqual(v1_location_block[1], "Guadeloupe")
47+
48+
self.assertEqual(v1_location_block[2], "2919786.0") # X
49+
self.assertEqual(v1_location_block[3], "-5383745.0") # Y
50+
self.assertEqual(v1_location_block[4], "1774604.0") # Z
51+
52+
self.assertEqual(len(v1_location_block), 8)
53+
54+
# Source values:
55+
# City or Town : Les Abymes
56+
# State or Province : Guadeloupe (971)
57+
# Country : Guadeloupe
58+
# Tectonic Plate : CARIBBEAN
59+
# Approximate Position (ITRF)
60+
# X coordinate (m) : 2919786.0
61+
# Y coordinate (m) : -5383745.0
62+
# Z coordinate (m) : 1774604.0
63+
# Latitude (N is +) : +161544.30
64+
# Longitude (E is +) : -0613139.11
65+
# Elevation (m,ellips.) : -25.0
66+
67+
# V2:
68+
# City or Town : Les Abymes
69+
# State or Province : Guadeloupe (971)
70+
# Country or Region : GLP
71+
# Tectonic Plate : CARIBBEAN
72+
# Approximate Position (ITRF)
73+
# X coordinate (m) : 2919786.0
74+
# Y coordinate (m) : -5383745.0
75+
# Z coordinate (m) : 1774604.0
76+
# Latitude (N is +) : +161544.30
77+
# Longitude (E is +) : -0613139.11
78+
# Elevation (m,ellips.) : -25.0
79+
# Additional Information :
4780

4881
# Version 2 Location description results:
4982
v2_location_block = igslog.extract_location_block(v2_data, "/example/path", "v2.0")
50-
self.assertEqual(v2_location_block.group(1), b"Les Abymes")
51-
self.assertEqual(v2_location_block.group(2), b"GLP")
83+
self.assertEqual(v2_location_block[0], "Les Abymes")
84+
self.assertEqual(v2_location_block[1], "GLP")
5285

53-
# Coordinate information remains the same:
54-
self.assertEqual(v2_location_block.group(3), v1_location_block.group(3))
86+
# Coordinate information remains the same compared to v1.0:
87+
self.assertEqual(v2_location_block[2], v1_location_block[2])
88+
self.assertEqual(v2_location_block[3], v1_location_block[3])
89+
self.assertEqual(v2_location_block[4], v1_location_block[4])
5590

5691
# Check LogVersionError is rasied on no data:
5792
with self.assertRaises(igslog.LogVersionError):

0 commit comments

Comments
 (0)