diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d7fcf74d..c67b7bdf 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,7 +1,7 @@ --- repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.4.0 + rev: v4.5.0 hooks: - id: check-added-large-files - id: check-docstring-first @@ -21,7 +21,7 @@ repos: - id: requirements-txt-fixer - id: trailing-whitespace - repo: https://github.com/ikamensh/flynt/ - rev: "0.78" + rev: "1.0.1" hooks: - id: flynt - repo: https://github.com/MarcoGorelli/absolufy-imports @@ -29,21 +29,21 @@ repos: hooks: - id: absolufy-imports - repo: https://github.com/hakancelikdev/unimport - rev: 0.15.0 + rev: 1.0.0 hooks: - id: unimport args: [--remove, --include-star-import, --ignore-init, --gitignore] - repo: https://github.com/asottile/pyupgrade - rev: v3.3.1 + rev: v3.15.0 hooks: - id: pyupgrade args: ["--py3-plus", "--py37-plus"] - repo: https://github.com/psf/black - rev: 23.3.0 + rev: 23.9.1 hooks: - id: black - repo: https://github.com/PyCQA/flake8 - rev: 6.0.0 + rev: 6.1.0 hooks: - id: flake8 - repo: https://github.com/pycqa/isort @@ -51,11 +51,11 @@ repos: hooks: - id: isort - repo: https://github.com/charliermarsh/ruff-pre-commit - rev: 'v0.0.259' + rev: 'v0.0.292' hooks: - id: ruff - repo: https://github.com/PyCQA/flake8 - rev: 6.0.0 + rev: 6.1.0 hooks: - id: flake8 - repo: https://github.com/pre-commit/pygrep-hooks diff --git a/fastkml/geometry.py b/fastkml/geometry.py index 837deb8d..07333c3b 100644 --- a/fastkml/geometry.py +++ b/fastkml/geometry.py @@ -376,7 +376,7 @@ def _get_linear_ring(self, element: Element) -> Optional[geo.LinearRing]: if lr is not None: coords = self._get_coordinates(lr) return geo.LinearRing(coords) - return None + return None # type: ignore[unreachable] @no_type_check def _get_geometry(self, element: Element) -> Optional[GeometryType]: @@ -413,6 +413,11 @@ def _get_multigeometry(self, element: Element) -> Optional[MultiGeometryType]: # MultiGeometry geoms: List[Union[AnyGeometryType, None]] = [] if element.tag == f"{self.ns}MultiGeometry": + multigeometries = element.findall(f"{self.ns}MultiGeometry") + for multigeometry in multigeometries: + geom = Geometry(ns=self.ns) + geom.from_element(multigeometry) + geoms.append(geom.geometry) points = element.findall(f"{self.ns}Point") for point in points: self._get_geometry_spec(point) @@ -445,23 +450,23 @@ def _get_multigeometry(self, element: Element) -> Optional[MultiGeometryType]: geom_types = {geom.geom_type for geom in clean_geoms} if len(geom_types) > 1: return geo.GeometryCollection( - clean_geoms, + clean_geoms, # type: ignore[arg-type] ) if "Point" in geom_types: return geo.MultiPoint.from_points( - *clean_geoms, + *clean_geoms, # type: ignore[arg-type] ) elif "LineString" in geom_types: return geo.MultiLineString.from_linestrings( - *clean_geoms, + *clean_geoms, # type: ignore[arg-type] ) elif "Polygon" in geom_types: return geo.MultiPolygon.from_polygons( - *clean_geoms, + *clean_geoms, # type: ignore[arg-type] ) elif "LinearRing" in geom_types: return geo.GeometryCollection( - clean_geoms, + clean_geoms, # type: ignore[arg-type] ) return None diff --git a/pyproject.toml b/pyproject.toml index 0a29180a..4ec400ee 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -47,3 +47,7 @@ module = [ "fastkml.tests.oldunit_test", "fastkml.tests.config_test" ] ignore_errors = true + +[tool.ruff] +[tool.ruff.extend-per-file-ignores] +"tests/oldunit_test.py" = ["E501"] diff --git a/tests/oldunit_test.py b/tests/oldunit_test.py index da3e00ff..348c372e 100644 --- a/tests/oldunit_test.py +++ b/tests/oldunit_test.py @@ -1381,6 +1381,319 @@ def test_geometrycollection(self) -> None: assert "coordinates>0.000000,1.000000 + + + + + + -122.366278,37.818844,0 -122.365248,37.819267,0 -122.365640,37.819875,0 -122.366278,37.818844,0 + + + + + + -122.365,37.819,0 + + + + + -122.365278,37.819000,0 -122.365248,37.819267,0 + + + + + + + -122.365248,37.819267,0 -122.365640,37.819875,0 -122.366278,37.818844,0 -122.365248,37.819267,0 + + + + + + + + """ + + k = kml.KML() + k.from_string(doc) + placemark = list(list(k.features())[0].features())[0] + + first_multigeometry = placemark.geometry + assert len(list(first_multigeometry.geoms)) == 3 + + second_multigeometry = [ + g for g in first_multigeometry.geoms if g.geom_type == "GeometryCollection" + ][0] + assert len(list(second_multigeometry.geoms)) == 2 + + +class TestGetGeometry: + def test_altitude_mode(self): + doc = """ + 0.000000,1.000000 + clampToGround + """ + + g = Geometry() + assert g.altitude_mode is None + g.from_string(doc) + assert g.altitude_mode.value == "clampToGround" + + def test_extrude(self): + doc = """ + 0.000000,1.000000 + 1 + """ + + g = Geometry() + assert g.extrude is False + g.from_string(doc) + assert g.extrude is True + + def test_tesselate(self): + doc = """ + 0.000000,1.000000 + 1 + """ + + g = Geometry() + assert g.tessellate is False + g.from_string(doc) + assert g.tessellate is True + + def test_point(self): + doc = """ + 0.000000,1.000000 + """ + + g = Geometry() + g.from_string(doc) + assert g.geometry.__geo_interface__ == { + "type": "Point", + "bbox": (0.0, 1.0, 0.0, 1.0), + "coordinates": (0.0, 1.0), + } + + def test_linestring(self): + doc = """ + 0.000000,0.000000 1.000000,1.000000 + """ + + g = Geometry() + g.from_string(doc) + assert g.geometry.__geo_interface__ == { + "type": "LineString", + "bbox": (0.0, 0.0, 1.0, 1.0), + "coordinates": ((0.0, 0.0), (1.0, 1.0)), + } + + def test_linearring(self): + doc = """ + 0.000000,0.000000 1.000000,0.000000 1.000000,1.000000 0.000000,0.000000 + + """ + + g = Geometry() + g.from_string(doc) + assert g.geometry.__geo_interface__ == { + "type": "LinearRing", + "bbox": (0.0, 0.0, 1.0, 1.0), + "coordinates": ((0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 0.0)), + } + + def test_polygon(self): + doc = """ + + + 0.000000,0.000000 1.000000,0.000000 1.000000,1.000000 0.000000,0.000000 + + + + """ + + g = Geometry() + g.from_string(doc) + assert g.geometry.__geo_interface__ == { + "type": "Polygon", + "bbox": (0.0, 0.0, 1.0, 1.0), + "coordinates": (((0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 0.0)),), + } + doc = """ + + + -1.000000,-1.000000 2.000000,-1.000000 2.000000,2.000000 -1.000000,-1.000000 + + + + + 0.000000,0.000000 1.000000,0.000000 1.000000,1.000000 0.000000,0.000000 + + + + """ + + g.from_string(doc) + assert g.geometry.__geo_interface__ == { + "type": "Polygon", + "bbox": (-1.0, -1.0, 2.0, 2.0), + "coordinates": ( + ((-1.0, -1.0), (2.0, -1.0), (2.0, 2.0), (-1.0, -1.0)), + ((0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 0.0)), + ), + } + + def test_multipoint(self): + doc = """ + + + 0.000000,1.000000 + + + 1.000000,1.000000 + + + """ + + g = Geometry() + g.from_string(doc) + assert len(g.geometry) == 2 + + def test_multilinestring(self): + doc = """ + + + 0.000000,0.000000 1.000000,0.000000 + + + 0.000000,1.000000 1.000000,1.000000 + + + """ + + g = Geometry() + g.from_string(doc) + assert len(g.geometry) == 2 + + def test_multipolygon(self): + doc = """ + + + + + -1.000000,-1.000000 2.000000,-1.000000 2.000000,2.000000 -1.000000,-1.000000 + + + + + 0.000000,0.000000 1.000000,0.000000 1.000000,1.000000 0.000000,0.000000 + + + + + + + 3.000000,0.000000 4.000000,0.000000 4.000000,1.000000 3.000000,0.000000 + + + + + """ + + g = Geometry() + g.from_string(doc) + assert len(g.geometry) == 2 + + def test_geometrycollection(self): + doc = """ + + + + + 3,0 4,0 4,1 3,0 + + + + + 0.000000,1.000000 + + + 0.000000,0.000000 1.000000,1.000000 + + + 0.0,0.0 1.0,0.0 1.0,1.0 0.0,1.0 0.0,0.0 + + + """ + + g = Geometry() + g.from_string(doc) + assert len(g.geometry) == 4 + doc = """ + + + 3.0,0.0 4.0,0.0 4.0,1.0 3.0,0.0 + + + 0.0,0.0 1.0,0.0 1.0,1.0 0.0,0.0 + + + """ + + g = Geometry() + g.from_string(doc) + assert len(g.geometry) == 2 + assert g.geometry.geom_type == "GeometryCollection" + + def test_nested_multigeometry(self): + doc = """ + + + + + + -122.366278,37.818844,0 -122.365248,37.819267,0 -122.365640,37.819875,0 -122.366278,37.818844,0 + + + + + + -122.365,37.819,0 + + + + + -122.365278,37.819000,0 -122.365248,37.819267,0 + + + + + + + -122.365248,37.819267,0 -122.365640,37.819875,0 -122.366278,37.818844,0 -122.365248,37.819267,0 + + + + + + + + """ + + k = kml.KML() + k.from_string(doc) + placemark = list(list(k.features())[0].features())[0] + + first_multigeometry = placemark.geometry + assert len(list(first_multigeometry.geoms)) == 3 + + second_multigeometry = [ + g for g in first_multigeometry.geoms if g.geom_type == "GeometryCollection" + ][0] + assert len(list(second_multigeometry.geoms)) == 2 + + class TestGetGxGeometry: def test_track(self) -> None: doc = """