Skip to content

Commit

Permalink
Refactor validation logic, improve style registration, and enhance te…
Browse files Browse the repository at this point in the history
…st strategies
  • Loading branch information
cleder committed Nov 10, 2024
1 parent c3a309b commit d0c318f
Show file tree
Hide file tree
Showing 11 changed files with 407 additions and 97 deletions.
10 changes: 5 additions & 5 deletions docs/working_with_kml.rst
Original file line number Diff line number Diff line change
Expand Up @@ -195,9 +195,6 @@ Now we can remove the CascadingStyle from the document and have a look at the re
</kml:Pair>
</kml:StyleMap>
<kml:Style id="__managed_style_25EBAAC82614827EFCCB">
<kml:BalloonStyle>
<kml:displayMode>hide</kml:displayMode>
</kml:BalloonStyle>
<kml:IconStyle>
<kml:scale>1.2</kml:scale>
<kml:Icon>
Expand All @@ -211,11 +208,11 @@ Now we can remove the CascadingStyle from the document and have a look at the re
<kml:PolyStyle>
<kml:color>80000000</kml:color>
</kml:PolyStyle>
</kml:Style>
<kml:Style id="__managed_style_14CDD4276C14827EFCCB">
<kml:BalloonStyle>
<kml:displayMode>hide</kml:displayMode>
</kml:BalloonStyle>
</kml:Style>
<kml:Style id="__managed_style_14CDD4276C14827EFCCB">
<kml:IconStyle>
<kml:Icon>
<kml:href>https://earth.google.com/earth/rpc/cc/icon?color=1976d2&amp;id=2000&amp;scale=4</kml:href>
Expand All @@ -228,6 +225,9 @@ Now we can remove the CascadingStyle from the document and have a look at the re
<kml:PolyStyle>
<kml:color>80000000</kml:color>
</kml:PolyStyle>
<kml:BalloonStyle>
<kml:displayMode>hide</kml:displayMode>
</kml:BalloonStyle>
</kml:Style>
<kml:Placemark id="04AFE6060F147CE66FBD">
<kml:name>Ort1</kml:name>
Expand Down
13 changes: 8 additions & 5 deletions fastkml/features.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
from pygeoif.types import GeoType

from fastkml import atom
from fastkml import config
from fastkml import gx
from fastkml.base import _XMLObject
from fastkml.data import ExtendedData
Expand Down Expand Up @@ -97,6 +98,8 @@ class Snippet(_XMLObject):
maximum number of lines to display.
"""

_default_nsid = config.KML

text: Optional[str]
max_lines: Optional[int] = None

Expand All @@ -109,7 +112,7 @@ def __init__(
**kwargs: Any,
) -> None:
"""
Initialize a Feature object.
Initialize a Snippet object.
Args:
----
Expand All @@ -130,7 +133,7 @@ def __init__(
"""
super().__init__(ns=ns, name_spaces=name_spaces, **kwargs)
self.text = text
self.text = text.strip() or None if text else None
self.max_lines = max_lines

def __repr__(self) -> str:
Expand Down Expand Up @@ -168,9 +171,9 @@ def __bool__(self) -> bool:
registry.register(
Snippet,
RegistryItem(
ns_ids=("kml",),
ns_ids=("kml", ""),
attr_name="text",
node_name="",
node_name="Snippet",
classes=(str,),
get_kwarg=node_text_kwarg,
set_element=node_text,
Expand Down Expand Up @@ -284,7 +287,7 @@ def __init__(
**kwargs,
)
self.name = name
self.description = description
self.description = description.strip() or None if description else None
self.style_url = style_url
self.styles = list(styles) if styles else []
self.view = view
Expand Down
4 changes: 2 additions & 2 deletions fastkml/styles.py
Original file line number Diff line number Diff line change
Expand Up @@ -1165,11 +1165,11 @@ def __bool__(self) -> bool:
attr_name="styles",
node_name="Style",
classes=(
BalloonStyle,
IconStyle,
LabelStyle,
LineStyle,
PolyStyle,
BalloonStyle,
),
get_kwarg=xml_subelement_list_kwarg,
set_element=xml_subelement_list,
Expand Down Expand Up @@ -1284,7 +1284,7 @@ def __bool__(self) -> bool:
RegistryItem(
ns_ids=("kml",),
attr_name="style",
node_name="style",
node_name="Style",
classes=(
StyleUrl,
Style,
Expand Down
3 changes: 3 additions & 0 deletions fastkml/validator.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
# along with this library; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
"""Validate KML files against the XML schema."""

import logging
import pathlib
from functools import lru_cache
Expand Down Expand Up @@ -98,6 +99,8 @@ def validate(
].getparent()
except config.etree.XPathEvalError:
parent = element
if parent is None:
parent = element
error_in_xml = config.etree.tostring(
parent,
encoding="UTF-8",
Expand Down
2 changes: 2 additions & 0 deletions tests/hypothesis/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
from fastkml.enums import DataType
from fastkml.enums import DateTimeResolution
from fastkml.enums import DisplayMode
from fastkml.enums import PairKey
from fastkml.enums import RefreshMode
from fastkml.enums import Units
from fastkml.enums import Verbosity
Expand Down Expand Up @@ -67,6 +68,7 @@
"Units": Units,
"ColorMode": ColorMode,
"DisplayMode": DisplayMode,
"PairKey": PairKey,
"tzutc": tzutc,
"tzfile": tzfile,
}
Expand Down
8 changes: 5 additions & 3 deletions tests/hypothesis/data_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -201,9 +201,11 @@ def test_fuzz_extended_data(
],
) -> None:
extended_data = fastkml.ExtendedData(
elements=sorted(elements, key=lambda t: t.__class__.__name__)
if elements
else None,
elements=(
sorted(elements, key=lambda t: t.__class__.__name__)
if elements
else None
),
)

assert_repr_roundtrip(extended_data)
Expand Down
17 changes: 6 additions & 11 deletions tests/hypothesis/gx_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
# along with this library; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
"""Test gx Track and MultiTrack."""

import typing

from hypothesis import given
Expand All @@ -37,24 +38,18 @@

track_items = st.builds(
TrackItem,
angle=st.one_of(
st.one_of(
st.builds(Angle),
st.builds(
Angle,
heading=st.floats(allow_nan=False, allow_infinity=False),
roll=st.floats(allow_nan=False, allow_infinity=False),
tilt=st.floats(allow_nan=False, allow_infinity=False),
),
),
angle=st.builds(
Angle,
heading=st.floats(allow_nan=False, allow_infinity=False),
roll=st.floats(allow_nan=False, allow_infinity=False),
tilt=st.floats(allow_nan=False, allow_infinity=False),
),
coord=points(srs=epsg4326),
when=kml_datetimes(),
)


class TestGx(Lxml):

@given(
id=st.one_of(st.none(), nc_name()),
target_id=st.one_of(st.none(), nc_name()),
Expand Down
90 changes: 79 additions & 11 deletions tests/hypothesis/strategies.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,14 @@

from hypothesis import strategies as st
from hypothesis.extra.dateutil import timezones
from pygeoif.hypothesis import strategies as geo_st

import fastkml.enums
import fastkml.links
import fastkml.styles
from fastkml.times import KmlDateTime
from fastkml.views import LatLonAltBox
from fastkml.views import Lod

ID_TEXT: Final = string.ascii_letters + string.digits + ".-_"

Expand Down Expand Up @@ -85,6 +90,80 @@
),
)

geometries = partial(
st.one_of,
(
geo_st.points(srs=geo_st.epsg4326),
geo_st.line_strings(srs=geo_st.epsg4326),
geo_st.linear_rings(srs=geo_st.epsg4326),
geo_st.polygons(srs=geo_st.epsg4326),
geo_st.multi_points(srs=geo_st.epsg4326),
geo_st.multi_line_strings(srs=geo_st.epsg4326),
geo_st.multi_polygons(srs=geo_st.epsg4326),
),
)
lods = partial(
st.builds,
Lod,
min_lod_pixels=st.integers(),
max_lod_pixels=st.integers(),
min_fade_extent=st.integers(),
max_fade_extent=st.integers(),
)

lat_lon_alt_boxes = partial(
st.builds,
LatLonAltBox,
north=st.floats(allow_nan=False, allow_infinity=False, min_value=0, max_value=90),
south=st.floats(allow_nan=False, allow_infinity=False, min_value=0, max_value=90),
east=st.floats(allow_nan=False, allow_infinity=False, min_value=0, max_value=180),
west=st.floats(allow_nan=False, allow_infinity=False, min_value=0, max_value=180),
min_altitude=st.floats(allow_nan=False, allow_infinity=False).filter(
lambda x: x != 0,
),
max_altitude=st.floats(allow_nan=False, allow_infinity=False).filter(
lambda x: x != 0,
),
altitude_mode=st.sampled_from(fastkml.enums.AltitudeMode),
)

kml_colors = partial(
st.text,
alphabet=string.hexdigits,
min_size=8,
max_size=8,
)

styles = partial(
st.one_of,
st.builds(
fastkml.styles.LabelStyle,
color=kml_colors(),
color_mode=st.sampled_from(fastkml.enums.ColorMode),
scale=st.floats(allow_nan=False, allow_infinity=False),
),
st.builds(
fastkml.styles.LineStyle,
color=kml_colors(),
color_mode=st.sampled_from(fastkml.enums.ColorMode),
width=st.floats(allow_nan=False, allow_infinity=False, min_value=0),
),
st.builds(
fastkml.styles.PolyStyle,
color=kml_colors(),
color_mode=st.sampled_from(fastkml.enums.ColorMode),
fill=st.booleans(),
outline=st.booleans(),
),
st.builds(
fastkml.styles.BalloonStyle,
bg_color=kml_colors(),
text_color=kml_colors(),
text=xml_text(min_size=1, max_size=256).filter(lambda x: x.strip() != ""),
display_mode=st.sampled_from(fastkml.enums.DisplayMode),
),
)


@st.composite
def query_strings(draw: st.DrawFn) -> str:
Expand All @@ -95,14 +174,3 @@ def query_strings(draw: st.DrawFn) -> str:
),
)
return urlencode(params)


@st.composite
def kml_colors(draw: st.DrawFn) -> str:
return draw(
st.text(
alphabet=string.hexdigits,
min_size=8,
max_size=8,
),
)
Loading

0 comments on commit d0c318f

Please sign in to comment.