Skip to content

Commit

Permalink
Merge pull request #271 from cleder/263-refactor-stylespy
Browse files Browse the repository at this point in the history
#263 refactor stylespy
  • Loading branch information
cleder committed Nov 20, 2023
2 parents d354238 + 9e3e4a9 commit f5935b4
Show file tree
Hide file tree
Showing 12 changed files with 546 additions and 281 deletions.
5 changes: 4 additions & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,10 @@ repos:
- id: rst-directive-colons
- id: rst-inline-touching-normal
- id: text-unicode-replacement-char

- repo: https://github.com/rstcheck/rstcheck
rev: "v6.2.0"
hooks:
- id: rstcheck
# - repo: https://github.com/mgedmin/check-manifest
# rev: "0.49"
# hooks:
Expand Down
7 changes: 3 additions & 4 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -97,16 +97,15 @@ Requirements
-------------

* pygeoif_
* dateutils_
* lxml_
* arrow_

Optional
---------

* lxml_

You can install all of the requirements for working with FastKML by using
pip_::
You can install all of the requirements for working with FastKML by using pip_::

pip install -r requirements.txt

Expand All @@ -125,5 +124,5 @@ Please submit a PR with the features you'd like to see implemented.

.. _pygeoif: http://pypi.python.org/pypi/pygeoif/
.. _lxml: https://pypi.python.org/pypi/lxml
.. _dateutils: https://pypi.python.org/pypi/dateutils
.. _arrow: https://pypi.python.org/pypi/arrow
.. _pip: https://pypi.python.org/pypi/pip
107 changes: 107 additions & 0 deletions fastkml/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@
# You should have received a copy of the GNU Lesser General Public License
# along with this library; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
"""
Enums for the fastkml package.
This module contains the enums used in the fastkml package.
https://developers.google.com/kml/documentation/kmlreference#kml-fields
"""
from enum import Enum
from enum import unique
from typing import Union
Expand Down Expand Up @@ -119,3 +127,102 @@ def convert(self, value: str) -> Union[str, int, float, bool]:
return bool(int(value))
msg = f"Unknown data type {self}"
raise ValueError(msg)


@unique
class RefreshMode(REnum):
"""
Enum to represent the different refresh modes.
Specifies how the link is refreshed when the "camera" changes.
"""

on_change = "onChange"
on_interval = "onInterval"
on_expire = "onExpire"


@unique
class ViewRefreshMode(REnum):
"""
Enum to represent the different view refresh modes.
Specifies how the link is refreshed when the "camera" changes.
"""

never = "never"
on_stop = "onStop"
on_request = "onRequest"
on_region = "onRegion"


@unique
class ColorMode(REnum):
"""
Enum to represent the different color modes.
Specifies how the color is applied to the geometry.
"""

normal = "normal"
random = "random"


@unique
class DisplayMode(REnum):
"""
DisplayMode for BalloonStyle.
If <displayMode> is default, Google Earth uses the information supplied in <text>
to create a balloon .
If <displayMode> is hide, Google Earth does not display the balloon.
In Google Earth, clicking the List View icon for a Placemark whose balloon's
<displayMode> is hide causes Google Earth to fly to the Placemark.
"""

default = "default"
hide = "hide"


@unique
class Shape(REnum):
"""
Shape for PhotoOverlay.
The PhotoOverlay is projected onto the <shape>.
The <shape> can be one of the following:
- rectangle (default) - for an ordinary photo
- cylinder - for panoramas, which can be either partial or full cylinders
- sphere - for spherical panoramas
"""

rectangle = "rectangle"
cylinder = "cylinder"
sphere = "sphere"


@unique
class GridOrigin(REnum):
"""
GridOrigin for GroundOverlay.
Specifies where to begin numbering the tiles in each layer of the pyramid.
A value of lowerLeft specifies that row 1, column 1 of each layer is in
the bottom left corner of the grid.
"""

lower_left = "lowerLeft"
upper_left = "upperLeft"


@unique
class Units(REnum):
"""
Units for ScreenOverlay and Hotspot.
Specifies how the <x>, <y> values are interpreted.
"""

fraction = "fraction"
pixels = "pixels"
inset_pixels = "insetPixels"
98 changes: 46 additions & 52 deletions fastkml/kml.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,11 @@
from fastkml.base import _BaseObject
from fastkml.data import ExtendedData
from fastkml.data import Schema
from fastkml.enums import GridOrigin
from fastkml.enums import RefreshMode
from fastkml.enums import Shape
from fastkml.enums import Verbosity
from fastkml.enums import ViewRefreshMode
from fastkml.geometry import AnyGeometryType
from fastkml.geometry import LinearRing
from fastkml.geometry import LineString
Expand Down Expand Up @@ -437,19 +441,30 @@ def from_element(self, element: Element, strict: bool = False) -> None:
self.isopen = 1 if isopen.text in ["1", "true"] else 0
styles = element.findall(f"{self.ns}Style")
for style in styles:
s = Style(self.ns)
s.from_element(style)
s = Style.class_from_element(
ns=self.ns,
name_spaces=self.name_spaces,
element=style,
strict=strict,
)
self.append_style(s)
styles = element.findall(f"{self.ns}StyleMap")
for style in styles:
s = StyleMap(self.ns)
s.from_element(style)
s = StyleMap.class_from_element(
ns=self.ns,
name_spaces=self.name_spaces,
element=style,
strict=strict,
)
self.append_style(s)
style_url = element.find(f"{self.ns}styleUrl")
if style_url is not None:
s = StyleUrl(self.ns)
s.from_element(style_url)
self._style_url = s
self._style_url = StyleUrl.class_from_element(
ns=self.ns,
name_spaces=self.name_spaces,
element=style_url,
strict=strict,
)
snippet = element.find(f"{self.ns}Snippet")
if snippet is not None:
_snippet = {"text": snippet.text}
Expand Down Expand Up @@ -518,9 +533,9 @@ class Icon(_BaseObject):
__name__ = "Icon"

_href = None
_refresh_mode: str = None
_refresh_mode: Optional[RefreshMode]
_refresh_interval = None
_view_refresh_mode = None
_view_refresh_mode: Optional[ViewRefreshMode]
_view_refresh_time = None
_view_bound_scale = None
_view_format = None
Expand All @@ -532,9 +547,9 @@ def __init__(
id: Optional[str] = None,
target_id: Optional[str] = None,
href: Optional[str] = None,
refresh_mode: Optional[str] = None,
refresh_mode: Optional[RefreshMode] = None,
refresh_interval: Optional[float] = None,
view_refresh_mode: Optional[str] = None,
view_refresh_mode: Optional[ViewRefreshMode] = None,
view_refresh_time: Optional[float] = None,
view_bound_scale: Optional[float] = None,
view_format: Optional[str] = None,
Expand Down Expand Up @@ -566,7 +581,7 @@ def href(self, href) -> None:
raise ValueError

@property
def refresh_mode(self) -> Optional[str]:
def refresh_mode(self) -> Optional[RefreshMode]:
"""
Specifies a time-based refresh mode.
Expand All @@ -579,13 +594,8 @@ def refresh_mode(self) -> Optional[str]:
return self._refresh_mode

@refresh_mode.setter
def refresh_mode(self, refresh_mode) -> None:
if isinstance(refresh_mode, str):
self._refresh_mode = refresh_mode
elif refresh_mode is None:
self._refresh_mode = None
else:
raise ValueError
def refresh_mode(self, refresh_mode: Optional[RefreshMode]) -> None:
self._refresh_mode = refresh_mode

@property
def refresh_interval(self) -> Optional[float]:
Expand All @@ -602,7 +612,7 @@ def refresh_interval(self, refresh_interval: Optional[float]) -> None:
raise ValueError

@property
def view_refresh_mode(self):
def view_refresh_mode(self) -> Optional[ViewRefreshMode]:
"""
Specifies how the link is refreshed when the "camera" changes.
Expand All @@ -614,18 +624,13 @@ def view_refresh_mode(self):
- onRequest - Refresh the file only when the user explicitly requests it.
(For example, in Google Earth, the user right-clicks and selects Refresh
in the Context menu.)
- onRegion - Refresh the file when the Region becomes active.
- onRegion - Refresh the file when the Region becomes active.
"""
return self._view_refresh_mode

@view_refresh_mode.setter
def view_refresh_mode(self, view_refresh_mode) -> None:
if isinstance(view_refresh_mode, str):
self._view_refresh_mode = view_refresh_mode
elif view_refresh_mode is None:
self._view_refresh_mode = None
else:
raise ValueError
def view_refresh_mode(self, view_refresh_mode: Optional[ViewRefreshMode]) -> None:
self._view_refresh_mode = view_refresh_mode

@property
def view_refresh_time(self):
Expand Down Expand Up @@ -738,7 +743,7 @@ def etree_element(
href.text = self._href
if self._refresh_mode:
refresh_mode = config.etree.SubElement(element, f"{self.ns}refreshMode")
refresh_mode.text = self._refresh_mode
refresh_mode.text = self._refresh_mode.value
if self._refresh_interval:
refresh_interval = config.etree.SubElement(
element,
Expand All @@ -750,7 +755,7 @@ def etree_element(
element,
f"{self.ns}viewRefreshMode",
)
view_refresh_mode.text = self._view_refresh_mode
view_refresh_mode.text = self._view_refresh_mode.value
if self._view_refresh_time:
view_refresh_time = config.etree.SubElement(
element,
Expand Down Expand Up @@ -781,7 +786,7 @@ def from_element(self, element: Element) -> None:

refresh_mode = element.find(f"{self.ns}refreshMode")
if refresh_mode is not None:
self.refresh_mode = refresh_mode.text
self.refresh_mode = RefreshMode(refresh_mode.text)

refresh_interval = element.find(f"{self.ns}refreshInterval")
if refresh_interval is not None:
Expand All @@ -792,7 +797,7 @@ def from_element(self, element: Element) -> None:

view_refresh_mode = element.find(f"{self.ns}viewRefreshMode")
if view_refresh_mode is not None:
self.view_refresh_mode = view_refresh_mode.text
self.view_refresh_mode = ViewRefreshMode(view_refresh_mode.text)

view_refresh_time = element.find(f"{self.ns}viewRefreshTime")
if view_refresh_time is not None:
Expand Down Expand Up @@ -1078,7 +1083,7 @@ class PhotoOverlay(_Overlay):
_max_height = None
# Height in pixels of the original image.

_grid_origin = None
_grid_origin: Optional[GridOrigin]
# Specifies where to begin numbering the tiles in each layer of the pyramid.
# A value of lowerLeft specifies that row 1, column 1 of each layer is in
# the bottom left corner of the grid.
Expand All @@ -1089,7 +1094,7 @@ class PhotoOverlay(_Overlay):
# The icon drawn is specified by the <styleUrl> and <StyleSelector> fields,
# just as it is for <Placemark>.

_shape = "rectangle"
_shape: Optional[Shape]
# The PhotoOverlay is projected onto the <shape>.
# The <shape> can be one of the following:
# rectangle (default) -
Expand Down Expand Up @@ -1217,17 +1222,12 @@ def max_height(self, value) -> None:
raise ValueError

@property
def grid_origin(self) -> Optional[str]:
def grid_origin(self) -> Optional[GridOrigin]:
return self._grid_origin

@grid_origin.setter
def grid_origin(self, value) -> None:
if value in ("lowerLeft", "upperLeft"):
self._grid_origin = str(value)
elif value is None:
self._grid_origin = None
else:
raise ValueError
def grid_origin(self, value: Optional[GridOrigin]) -> None:
self._grid_origin = value

@property
def point(self) -> str:
Expand All @@ -1241,18 +1241,12 @@ def point(self, value) -> None:
raise ValueError

@property
def shape(self) -> Optional[str]:
def shape(self) -> Optional[Shape]:
return self._shape

@shape.setter
def shape(self, value) -> None:
if value in ("rectangle", "cylinder", "sphere"):
self._shape = str(value)
elif value is None:
self._shape = None
else:
msg = "Shape must be one of rectangle, cylinder, sphere"
raise ValueError(msg)
def shape(self, value: Optional[Shape]) -> None:
self._shape = value

def view_volume(self, left_fov, right_fov, bottom_fov, top_fov, near) -> None:
self.left_fov = left_fov
Expand Down Expand Up @@ -1599,7 +1593,7 @@ class Document(_Container):
__name__ = "Document"
_schemata = None

def schemata(self) -> None:
def schemata(self) -> Iterator["Schema"]:
if self._schemata:
yield from self._schemata

Expand Down

0 comments on commit f5935b4

Please sign in to comment.