db_query / tests /test_kml_to_tab.py
DavMelchi's picture
Parse structured KML descriptions into TAB fields
cc3d5fb
import tempfile
import zipfile
from io import BytesIO
from pathlib import Path
import pyogrio
import pytest
from utils.kml_to_tab import KmlToTabError, convert_kml_to_tab_zip
MIXED_KML = b"""<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2">
<Document>
<Placemark>
<name>Site A</name>
<description>Point feature</description>
<Point>
<coordinates>50.606051,26.261322,0</coordinates>
</Point>
</Placemark>
<Placemark>
<name>Sector A</name>
<description>Polygon feature</description>
<Polygon>
<outerBoundaryIs>
<LinearRing>
<coordinates>
50.606051,26.261322,0
50.607051,26.261322,0
50.607051,26.262322,0
50.606051,26.261322,0
</coordinates>
</LinearRing>
</outerBoundaryIs>
</Polygon>
</Placemark>
</Document>
</kml>
"""
RSRP_KML = b"""<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2">
<Document xmlns="">
<Style id="normalPlacemark">
<IconStyle>
<color>ff00ffff</color>
<scale>0.5</scale>
<Icon>
<href>http://kml-icons.actix.com/Dot.png</href>
</Icon>
</IconStyle>
</Style>
<Placemark>
<description>DriveTest-LTE_UE_RSRP
-105.599998474121</description>
<styleUrl>normalPlacemark</styleUrl>
<Point>
<coordinates>-5.687045,11.305296</coordinates>
</Point>
</Placemark>
<Style id="normalPlacemark">
<IconStyle>
<color>ff0000ff</color>
<scale>0.5</scale>
<Icon>
<href>http://kml-icons.actix.com/Dot.png</href>
</Icon>
</IconStyle>
</Style>
<Placemark>
<description>DriveTest-LTE_UE_RSRP
-116.099998474121</description>
<styleUrl>normalPlacemark</styleUrl>
<Point>
<coordinates>-5.687901,11.305419</coordinates>
</Point>
</Placemark>
</Document>
</kml>
"""
STRUCTURED_DESCRIPTION_KML = b"""<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2">
<Document>
<Placemark>
<name>Busaiteen_1</name>
<description>&lt;b&gt;Sector Details:&lt;/b&gt;&lt;br&gt;&lt;b&gt;code:&lt;/b&gt; 1004&lt;br&gt;&lt;b&gt;name:&lt;/b&gt; Busaiteen_1&lt;br&gt;&lt;b&gt;Azimut:&lt;/b&gt; 30&lt;br&gt;&lt;b&gt;Longitude:&lt;/b&gt; 50.606051&lt;br&gt;&lt;b&gt;Latitude:&lt;/b&gt; 26.261322&lt;br&gt;&lt;b&gt;size:&lt;/b&gt; 1000&lt;br&gt;&lt;b&gt;color:&lt;/b&gt; 7fff0000&lt;br&gt;</description>
<Polygon>
<outerBoundaryIs>
<LinearRing>
<coordinates>
50.606051,26.261322,0
50.607051,26.261322,0
50.607051,26.262322,0
50.606051,26.261322,0
</coordinates>
</LinearRing>
</outerBoundaryIs>
</Polygon>
</Placemark>
</Document>
</kml>
"""
def test_convert_kml_to_tab_zip_splits_mixed_geometries():
result = convert_kml_to_tab_zip(MIXED_KML, "mixed sample.kml")
with zipfile.ZipFile(BytesIO(result.zip_bytes)) as zf:
names = sorted(zf.namelist())
assert "mixed_sample_point.tab" in names
assert "mixed_sample_point.dat" in names
assert "mixed_sample_point.map" in names
assert "mixed_sample_point.id" in names
assert "mixed_sample_polygon.tab" in names
assert "mixed_sample_polygon.dat" in names
assert "mixed_sample_polygon.map" in names
assert "mixed_sample_polygon.id" in names
assert [(layer.geometry_type, layer.feature_count) for layer in result.layers] == [
("Point", 1),
("Polygon", 1),
]
def test_convert_kml_to_tab_zip_preserves_measurement_values():
result = convert_kml_to_tab_zip(RSRP_KML, "rsrp.kml")
with tempfile.TemporaryDirectory() as tmp_dir_name:
tmp_dir = Path(tmp_dir_name)
with zipfile.ZipFile(BytesIO(result.zip_bytes)) as zf:
zf.extractall(tmp_dir)
metadata, _fids, _geometry, field_data = pyogrio.raw.read(tmp_dir / "rsrp.tab")
fields = metadata["fields"].tolist()
data = dict(zip(fields, field_data))
assert "value" in fields
assert "metric" not in fields
assert "parameter" not in fields
assert "legend" not in fields
assert "kml_color" not in fields
assert "style_rgb" not in fields
assert data["value"].tolist() == [-105.599998474121, -116.099998474121]
def test_convert_kml_to_tab_zip_expands_structured_description_fields():
result = convert_kml_to_tab_zip(STRUCTURED_DESCRIPTION_KML, "sectors.kml")
with tempfile.TemporaryDirectory() as tmp_dir_name:
tmp_dir = Path(tmp_dir_name)
with zipfile.ZipFile(BytesIO(result.zip_bytes)) as zf:
zf.extractall(tmp_dir)
metadata, _fids, _geometry, field_data = pyogrio.raw.read(
tmp_dir / "sectors.tab"
)
fields = metadata["fields"].tolist()
data = dict(zip(fields, field_data))
assert "value" not in fields
for field in [
"code",
"description_name",
"Azimut",
"Longitude",
"Latitude",
"size",
"color",
]:
assert field in fields
assert data["code"].tolist() == ["1004"]
assert data["description_name"].tolist() == ["Busaiteen_1"]
assert data["Azimut"].tolist() == ["30"]
assert data["Longitude"].tolist() == ["50.606051"]
assert data["Latitude"].tolist() == ["26.261322"]
assert data["size"].tolist() == ["1000"]
assert data["color"].tolist() == ["7fff0000"]
def test_convert_kml_to_tab_zip_rejects_empty_input():
with pytest.raises(KmlToTabError, match="vide"):
convert_kml_to_tab_zip(b"", "empty.kml")