Source code for ezgpx.writers.writer

"""
This module contains the Writer class.
"""

import warnings
import xml.etree.ElementTree as ET
from dataclasses import dataclass
from datetime import datetime, timezone
from typing import Any, Protocol

from ..constants.precisions import (
    DEFAULT_PRECISION,
    DEFAULT_TIME_FORMAT,
)


[docs] @dataclass class GPXLike(Protocol): """Protocol for GPX objects."""
[docs] class Writer: """ File writer. """ def __init__(self, gpx: GPXLike) -> None: """ Initialise Writer instance. Args: gpx (GPXLike): GPX instance to write. """ self.gpx: GPXLike = gpx self.precisions: dict = gpx._precisions self.time_format: str = gpx._time_format self.file_path: str = None
[docs] def get_value(self, attribute: Any) -> Any | None: """ Safely get attribute value. """ try: return attribute.value except AttributeError: return None
[docs] def set_not_none(self, element: ET.Element, field: str, value): """ TODO Args: element (ET.Element): _description_ field (str): _description_ value (_type_): _description_ """ if value is not None: element.set(field, value)
[docs] def add_subelement( self, element: ET.Element, sub_element: str, text: str ) -> tuple[ET.Element, ET.Element | None]: """ Add sub-element to GPX element. Args: element (ET.Element): GPX element. sub_element (str): GPX sub-element. text (str): GPX sub-element text. Returns: tuple[ET.Element, ET.Element | None]: GPX element and GPX sub-element (if not None). """ sub_element_ = None if text is not None: sub_element_ = ET.SubElement(element, sub_element) sub_element_.text = text return element, sub_element_
[docs] def add_subelement_number( self, element: ET.Element, sub_element: str, number: int | float, precision: int = DEFAULT_PRECISION, ) -> tuple[ET.Element, ET.Element | None]: """ Add sub-element to GPX element. Args: element (ET.Element): GPX element. sub_element (str): GPX sub-element. number (int | float, optional): GPX sub-element value. precision (int, optional): Precision. Defaults to DEFAULT_PRECISION. Returns: tuple[ET.Element, ET.Element | None]: GPX element and GPX sub-element (if not None). """ sub_element_ = None if number is not None: sub_element_ = ET.SubElement(element, sub_element) if isinstance(number, int): sub_element_.text = str(number) elif isinstance(number, float): sub_element_.text = f"{number:.{precision}f}" else: warnings.warn("Invalid number type.") return element, sub_element_
[docs] def add_subelement_time( self, element: ET.Element, sub_element: str, time: datetime, format_: str = DEFAULT_TIME_FORMAT, ) -> tuple[ET.Element, ET.Element | None]: """ Add sub-element to GPX element. Args: element (ET.Element): GPX element. sub_element (str): GPX sub-element. time (datetime, optional): GPX sub-element value. format (str, optional): Format. Defaults to DEFAULT_TIME_FORMAT. Returns: tuple[ET.Element, ET.Element | None]: GPX element and GPX sub-element (if not None). """ sub_element_ = None if time is not None: sub_element_ = ET.SubElement(element, sub_element) time_utc = time.astimezone(timezone.utc) # Convert to UTC sub_element_.text = time_utc.strftime(format_) return element, sub_element_