Skip to content

Commit

Permalink
Merge pull request #387 from cleder/develop
Browse files Browse the repository at this point in the history
1.0.0 release candidate 2
  • Loading branch information
cleder authored Nov 17, 2024
2 parents bbd4de6 + 4cba662 commit ceb46b3
Show file tree
Hide file tree
Showing 11 changed files with 224 additions and 89 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/run-all-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ jobs:
pytest tests --cov=fastkml --cov=tests --cov-fail-under=95 --cov-report=xml
- name: "Upload coverage to Codecov"
if: ${{ matrix.python-version==3.11 }}
uses: codecov/codecov-action@v4
uses: codecov/codecov-action@v5
with:
fail_ci_if_error: true
verbose: true
Expand Down
2 changes: 1 addition & 1 deletion fastkml/about.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,6 @@
The only purpose of this module is to provide a version number for the package.
"""

__version__ = "1.0.0rc1"
__version__ = "1.0.0rc2"

__all__ = ["__version__"]
8 changes: 2 additions & 6 deletions fastkml/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,20 +189,16 @@ def to_string(
str,
config.etree.tostring(
element,
encoding="UTF-8",
encoding="unicode",
pretty_print=prettyprint,
).decode(
"UTF-8",
),
)
except TypeError:
return cast(
str,
config.etree.tostring(
element,
encoding="UTF-8",
).decode(
"UTF-8",
encoding="unicode",
),
)

Expand Down
21 changes: 11 additions & 10 deletions fastkml/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -1092,23 +1092,24 @@ def datetime_subelement_kwarg(
kwarg: str,
classes: Tuple[Type[object], ...],
strict: bool,
) -> Dict[str, List["KmlDateTime"]]:
) -> Dict[str, "KmlDateTime"]:
"""Extract a KML datetime from a subelement of an XML element."""
cls = classes[0]
node = element.find(f"{ns}{node_name}")
if node is None:
return {}
node_text = node.text.strip() if node.text else ""
if node_text:
if kdt := cls.parse(node_text): # type: ignore[attr-defined]
return {kwarg: kdt}
handle_error(
error=ValueError(f"Invalid DateTime value: {node_text}"),
strict=strict,
element=element,
node=node,
expected="DateTime",
)
try:
return {kwarg: cls.parse(node_text)} # type: ignore[attr-defined]
except ValueError as exc:
handle_error(
error=exc,
strict=strict,
element=element,
node=node,
expected="DateTime",
)
return {}


Expand Down
43 changes: 43 additions & 0 deletions fastkml/kml.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"""

import logging
import zipfile
from pathlib import Path
from typing import IO
from typing import Any
Expand Down Expand Up @@ -244,6 +245,48 @@ def parse(
element=root,
)

def write(
self,
file_path: Path,
*,
prettyprint: bool = True,
precision: Optional[int] = None,
verbosity: Verbosity = Verbosity.normal,
) -> None:
"""
Write KML to a file.
Args:
----
file_path: The file name where to save the file.
Can be any string value
prettyprint : bool, default=True
Whether to pretty print the XML.
precision (Optional[int]): The precision used for floating-point values.
verbosity (Verbosity): The verbosity level for generating the KML element.
"""
element = self.etree_element(precision=precision, verbosity=verbosity)

try:
xml_content = config.etree.tostring(
element,
encoding="unicode",
pretty_print=prettyprint,
)
except TypeError:
xml_content = config.etree.tostring(
element,
encoding="unicode",
)

if file_path.suffix == ".kmz":
with zipfile.ZipFile(file_path, "w", zipfile.ZIP_DEFLATED) as kmz:
kmz.writestr("doc.kml", xml_content)
else:
with file_path.open("w", encoding="UTF-8") as file:
file.write(xml_content)


registry.register(
KML,
Expand Down
8 changes: 3 additions & 5 deletions fastkml/times.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@

# regular expression to parse a gYearMonth string
# year and month may be separated by an optional dash
# year is always 4 digits, month is always 2 digits
# year is always 4 digits, month, day is always 2 digits
year_month_day = re.compile(
r"^(?P<year>\d{4})(?:-)?(?P<month>\d{2})?(?:-)?(?P<day>\d{2})?$",
)
Expand Down Expand Up @@ -205,10 +205,8 @@ def parse(cls, datestr: str) -> Optional["KmlDateTime"]:
resolution = DateTimeResolution.year_month
if year_month_day_match.group("month") is None:
resolution = DateTimeResolution.year
elif len(datestr) > 10: # noqa: PLR2004
dt = arrow.get(datestr).datetime
resolution = DateTimeResolution.datetime
return cls(dt, resolution) if dt else None
return cls(dt, resolution)
return cls(arrow.get(datestr).datetime, DateTimeResolution.datetime)

@classmethod
def get_ns_id(cls) -> str:
Expand Down
40 changes: 29 additions & 11 deletions fastkml/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,32 @@ def has_attribute_values(obj: object, **kwargs: Any) -> bool:
return False


def get_all_attrs(obj: object) -> Generator[object, None, None]:
"""
Get all attributes of an object.
Args:
----
obj: The object to get attributes from.
Returns:
-------
An iterable of all attributes of the object or, if the attribute itself is
iterable, iterate over the attribute values.
"""
try:
attrs = (attr for attr in obj.__dict__ if not attr.startswith("_"))
except AttributeError:
return
for attr_name in attrs:
attr = getattr(obj, attr_name)
try:
yield from attr
except TypeError:
yield attr


def find_all(
obj: object,
*,
Expand All @@ -55,17 +81,9 @@ def find_all(
**kwargs,
):
yield obj
try:
attrs = (attr for attr in obj.__dict__ if not attr.startswith("_"))
except AttributeError:
return
for attr_name in attrs:
attr = getattr(obj, attr_name)
try:
for item in attr:
yield from find_all(item, of_type=of_type, **kwargs)
except TypeError:
yield from find_all(attr, of_type=of_type, **kwargs)

for attr in get_all_attrs(obj):
yield from find_all(attr, of_type=of_type, **kwargs)


def find(
Expand Down
6 changes: 2 additions & 4 deletions tests/atom_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,9 @@ class TestStdLibrary(StdLibrary):
"""Test with the standard library."""

def test_atom_link_ns(self) -> None:
ns = "{http://www.opengis.net/kml/2.2}"
link = atom.Link(ns=ns)
assert link.ns == ns
link = atom.Link()
assert link.to_string().startswith(
'<kml:link xmlns:kml="http://www.opengis.net/kml/2.2"',
'<atom:link xmlns:atom="http://www.w3.org/2005/Atom"',
)

def test_atom_link(self) -> None:
Expand Down
Loading

0 comments on commit ceb46b3

Please sign in to comment.