Skip to content

Commit

Permalink
Refactor code to use the new find_all utility function
Browse files Browse the repository at this point in the history
  • Loading branch information
cleder committed Oct 26, 2024
1 parent fa9f72f commit 9e452f6
Show file tree
Hide file tree
Showing 7 changed files with 109 additions and 34 deletions.
1 change: 1 addition & 0 deletions docs/Document-clean.kml
8 changes: 3 additions & 5 deletions docs/usage_guide.rst → docs/create_kml_files.rst
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
Usage guide
===========
Creating KML files
==================

Read a shapefile and build a 3D KML visualization.
--------------------------------------------------

This example shows how to read a shapefile and build a 3D KML visualization from it.

You will need to install the following packages:

- `pyshp <https://pypi.org/project/pyshp/>`_
You will need to install `pyshp <https://pypi.org/project/pyshp/>`_ (``pip install pyshp``).

For this example we will use the
`Data on CO2 and Greenhouse Gas Emissions <https://github.com/owid/co2-data>`_ by
Expand Down
3 changes: 2 additions & 1 deletion docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ requirements, namely:
:maxdepth: 2

quickstart
usage_guide
create_kml_files
working_with_kml
configuration
modules
contributing
Expand Down
53 changes: 53 additions & 0 deletions docs/working_with_kml.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
Working with KML Files
======================

Import the necessary modules:

.. code-block:: pycon
>>> from fastkml.utils import find_all
>>> from fastkml import KML
>>> from fastkml import Placemark, Point
Open a KML file:

.. code-block:: pycon
>>> k = KML.parse("docs/Document-clean.kml")
Extract all placemarks and print their geometries:

.. code-block:: pycon
>>> placemarks = list(find_all(k, of_type=Placemark))
>>> for p in placemarks:
... print(p.geometry) # doctest: +ELLIPSIS
...
POINT Z (-123.93563168 49.16716103 5.0)
POLYGON Z ((-123.940449937288 49.16927524669021 17.0, ...
>>> pts = list(find_all(k, of_type=Point))
>>> for point in pts:
... print(point.geometry)
...
POINT Z (-123.93563168 49.16716103 5.0)
POINT Z (-123.1097 49.2774 0.0)
POINT Z (-123.028369 49.26107900000001 0.0)
POINT Z (-123.3215766 49.2760338 0.0)
POINT Z (-123.2643704 49.3301853 0.0)
POINT Z (-123.2477084 49.2890857 0.0)
You can also define what you are looking for by specifying additional parameters:


.. code-block:: pycon
>>> al = list(find_all(k, name="Vancouver Film Studios"))
>>> al[0].name
'Vancouver Film Studios'
>>> al[0].get_tag_name()
'Placemark'
>>> list(find_all(k, href="http://www.vancouverfilmstudios.com/")) # doctest: +ELLIPSIS
[fastkml.atom.Link(ns=...
24 changes: 19 additions & 5 deletions fastkml/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,24 @@
functionality that KML on google earth provides.
"""
from fastkml.about import __version__ # noqa: F401
from fastkml.atom import Author
from fastkml.atom import Contributor
from fastkml.atom import Link
from fastkml.atom import Author as AtomAuthor
from fastkml.atom import Contributor as AtomContributor
from fastkml.atom import Link as AtomLink
from fastkml.containers import Document
from fastkml.containers import Folder
from fastkml.data import Data
from fastkml.data import ExtendedData
from fastkml.data import Schema
from fastkml.data import SchemaData
from fastkml.features import Placemark
from fastkml.geometry import LinearRing
from fastkml.geometry import LineString
from fastkml.geometry import MultiGeometry
from fastkml.geometry import Point
from fastkml.geometry import Polygon
from fastkml.kml import KML
from fastkml.links import Icon
from fastkml.links import Link
from fastkml.overlays import GroundOverlay
from fastkml.overlays import PhotoOverlay
from fastkml.styles import BalloonStyle
Expand Down Expand Up @@ -72,9 +79,16 @@
"PolyStyle",
"LabelStyle",
"BalloonStyle",
"AtomLink",
"Icon",
"Link",
"Author",
"Contributor",
"Point",
"LineString",
"LinearRing",
"Polygon",
"MultiGeometry",
"AtomAuthor",
"AtomContributor",
"Camera",
"LookAt",
]
44 changes: 21 additions & 23 deletions fastkml/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

def has_attribute_values(obj: object, **kwargs: Any) -> bool:
"""
Check if an object has the given attribute values.
Check if an object has all of the given attribute values.
Args:
obj: The object to check.
Expand All @@ -21,12 +21,9 @@ def has_attribute_values(obj: object, **kwargs: Any) -> bool:
"""
try:
for key, value in kwargs.items():
if getattr(obj, key) != value:
return False
return all(getattr(obj, key) == value for key, value in kwargs.items())
except AttributeError:
return False
return True


def find_all(
Expand All @@ -47,22 +44,23 @@ def find_all(
An iterable of all instances of the given type in the given object.
"""
if of_type is None or isinstance(obj, of_type):
if has_attribute_values(obj, **kwargs):
yield obj
else:
if (of_type is None or isinstance(obj, of_type)) and has_attribute_values(
obj,
**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)
if callable(attr):
continue
if attr is obj:
continue
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)
if callable(attr):
continue
if attr is obj:
continue
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 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)
10 changes: 10 additions & 0 deletions tests/utils_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,16 @@ def __init__(self, x: int) -> None:
a1 = A(1)

result = list(find_all(a1, of_type=None))
assert result == [a1, 1]

def test_find_all_no_type_attr_x(self) -> None:
class A:
def __init__(self, x: int) -> None:
self.x = x

a1 = A(1)

result = list(find_all(a1, x=1))
assert result == [a1]

def test_find_schema_by_url(self) -> None:
Expand Down

0 comments on commit 9e452f6

Please sign in to comment.