blob: 90c027f1851a818c4b56fe2d22431b590f0fb898 [file]
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
import json
import os.path
import geopandas
import pytest
from shapely.geometry import LineString, Point
from shapely.geometry.base import BaseGeometry
from shapely.wkt import loads as wkt_loads
from tests import (
geoparquet_input_location,
legacy_parquet_input_location,
plain_parquet_input_location,
)
from tests.test_base import TestBase
class TestGeoParquet(TestBase):
def test_interoperability_with_geopandas(self, tmp_path):
test_data = [
[1, Point(0, 0), LineString([(1, 2), (3, 4), (5, 6)])],
[2, LineString([(1, 2), (3, 4), (5, 6)]), Point(1, 1)],
[3, Point(1, 1), LineString([(1, 2), (3, 4), (5, 6)])],
]
df = self.spark.createDataFrame(
data=test_data, schema=["id", "g0", "g1"]
).repartition(1)
geoparquet_save_path = os.path.join(tmp_path, "test.parquet")
df.write.format("geoparquet").save(geoparquet_save_path)
# Load geoparquet file written by sedona using geopandas
gdf = geopandas.read_parquet(geoparquet_save_path)
assert gdf.dtypes["g0"].name == "geometry"
assert gdf.dtypes["g1"].name == "geometry"
# Load geoparquet file written by geopandas using sedona
gdf = geopandas.GeoDataFrame(
[
{"g": wkt_loads("POINT (1 2)"), "i": 10},
{"g": wkt_loads("LINESTRING (1 2, 3 4)"), "i": 20},
],
geometry="g",
)
geoparquet_save_path2 = os.path.join(tmp_path, "test_2.parquet")
gdf.to_parquet(geoparquet_save_path2)
df2 = self.spark.read.format("geoparquet").load(geoparquet_save_path2)
assert df2.count() == 2
row = df2.collect()[0]
assert isinstance(row["g"], BaseGeometry)
def test_load_geoparquet_with_spatial_filter(self):
df = (
self.spark.read.format("geoparquet")
.load(geoparquet_input_location)
.where(
"ST_Contains(geometry, ST_GeomFromText('POINT (35.174722 -6.552465)'))"
)
)
rows = df.collect()
assert len(rows) == 1
assert rows[0]["name"] == "Tanzania"
def test_load_plain_parquet_file(self):
with pytest.raises(Exception) as excinfo:
self.spark.read.format("geoparquet").load(plain_parquet_input_location)
assert "does not contain valid geo metadata" in str(excinfo.value)
def test_inspect_geoparquet_metadata(self):
df = self.spark.read.format("geoparquet.metadata").load(
geoparquet_input_location
)
rows = df.collect()
assert len(rows) == 1
row = rows[0]
assert row["path"].endswith(".parquet")
assert len(row["version"].split(".")) == 3
assert row["primary_column"] == "geometry"
column_metadata = row["columns"]["geometry"]
assert column_metadata["encoding"] == "WKB"
assert len(column_metadata["bbox"]) == 4
assert isinstance(json.loads(column_metadata["crs"]), dict)
def test_reading_legacy_parquet_files(self):
df = (
self.spark.read.format("geoparquet")
.option("legacyMode", "true")
.load(legacy_parquet_input_location)
)
rows = df.collect()
assert len(rows) > 0
for row in rows:
assert isinstance(row["geom"], BaseGeometry)
assert isinstance(row["struct_geom"]["g0"], BaseGeometry)
assert isinstance(row["struct_geom"]["g1"], BaseGeometry)