Skip to content

Commit

Permalink
Merge branch 'develop' into 216-add-output-verbosity
Browse files Browse the repository at this point in the history
  • Loading branch information
cleder committed Oct 5, 2024
2 parents c59d4d3 + 79227e7 commit c733635
Show file tree
Hide file tree
Showing 18 changed files with 192 additions and 127 deletions.
8 changes: 4 additions & 4 deletions .github/workflows/run-all-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ['3.8', '3.9', '3.10', '3.11', '3.12', '3.13-dev']
python-version: ['3.8', '3.9', '3.10', '3.11', '3.12', '3.13-dev', '3.14-dev']

steps:
- uses: actions/checkout@v4
Expand All @@ -29,7 +29,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ['3.8', '3.9', '3.10', '3.11', '3.12']
python-version: ['3.8', '3.9', '3.10', '3.11', '3.12', '3.13-dev']

steps:
- uses: actions/checkout@v4
Expand Down Expand Up @@ -87,10 +87,10 @@ jobs:
- name: Install dependencies
run: |
python -m pip install --upgrade pip wheel
pip install -e ".[typing, complexity, linting]"
pip install -e ".[typing, complexity, linting, tests]"
- name: Typecheck
run: |
mypy fastkml
mypy fastkml tests
- name: Linting
run: |
flake8 fastkml examples docs
Expand Down
8 changes: 6 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ repos:
hooks:
- id: pyprojectsort
- repo: https://github.com/abravalheri/validate-pyproject
rev: v0.19
rev: v0.20.2
hooks:
- id: validate-pyproject
- repo: https://github.com/ikamensh/flynt/
Expand All @@ -50,7 +50,7 @@ repos:
hooks:
- id: isort
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: 'v0.6.5'
rev: 'v0.6.8'
hooks:
- id: ruff
- repo: https://github.com/PyCQA/flake8
Expand Down Expand Up @@ -82,6 +82,10 @@ repos:
rev: "1.18.0"
hooks:
- id: blacken-docs
- repo: https://github.com/crate-ci/typos
rev: v1.25.0
hooks:
- id: typos
# - repo: https://github.com/Lucas-C/pre-commit-hooks-markup
# rev: v1.0.1
# hooks:
Expand Down
2 changes: 1 addition & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ Optional
pip install --pre "fastkml[lxml]"

Limitations
============
===========

Currently, the only major feature missing for the full Google Earth experience
is the `gx extension
Expand Down
6 changes: 6 additions & 0 deletions _typos.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[default.extend-words]
lod = "lod"
Lod = "Lod"

[files]
extend-exclude = ["tests/ogc_conformance/data/kml/*.kml"]
2 changes: 1 addition & 1 deletion docs/HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ Changelog
-----------------

- specify minor python versions tested with Travis CI
- add support for tesselation, altitudeMode and extrude to Geometries
- add support for tessellation, altitudeMode and extrude to Geometries
- move implementation of geometry from kml.Placemark to geometry.Geometry
- add support for heterogenous GeometryCollection
- python 3 compatible
Expand Down
21 changes: 14 additions & 7 deletions docs/contributing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,19 @@ especially in the following ways:
Setting Up Your Environment
---------------------------

First, clone the repository:
Fork the repository and clone your fork to your local machine:

.. code-block:: bash
git clone https://github.com/yourusername/fastkml.git
cd fastkml
git checkout develop
Next, set up a virtual environment. This helps to manage dependencies and avoid conflicts:

.. code-block:: bash
python3 -m venv venv
python3 -m venv .venv
source venv/bin/activate # On Windows use `venv\Scripts\activate`
Then, install the required packages:
Expand Down Expand Up @@ -55,16 +56,22 @@ To run the tests, simply use:
pytest
coverage
~~~~~~~~

You can also run the tests with coverage_ to see which lines are covered by the
tests. This is useful for writing new tests to cover any uncovered lines::
You can also run the tests with `coverage <https://coverage.readthedocs.io/>`_
to see which lines are covered by the tests.
This is useful for writing new tests to cover any uncovered lines:

.. code-block:: bash
pytest --cov=fastkml --cov-report=term
To get a report on the individual lines that are not covered, use the
``--cov-report=term-missing`` option, or generate an HTML report with
``--cov-report=html``.
Some editor extensions can also show the coverage directly in the editor, notably
`coverage-gutter <https://marketplace.visualstudio.com/items?itemName=ryanluker.vscode-coverage-gutters>`_
for VSCode, which needs the output to be in the ``xml`` format produced with
``--cov-report=xml``.


Tips
----
Expand Down
2 changes: 1 addition & 1 deletion fastkml/about.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,4 @@
The only purpose of this module is to provide a version number for the package.
"""
__version__ = "1.0.a13"
__version__ = "1.0.a14"
108 changes: 53 additions & 55 deletions fastkml/geometry.py
Original file line number Diff line number Diff line change
Expand Up @@ -924,15 +924,15 @@ class InnerBoundaryIs(_XMLObject):
"""Represents the inner boundary of a polygon in KML."""

_default_nsid = config.KML
kml_geometries: List[LinearRing]
kml_geometry: Optional[LinearRing]

def __init__(
self,
*,
ns: Optional[str] = None,
name_spaces: Optional[Dict[str, str]] = None,
geometries: Optional[Iterable[geo.LinearRing]] = None,
kml_geometries: Optional[Iterable[LinearRing]] = None,
geometry: Optional[geo.LinearRing] = None,
kml_geometry: Optional[LinearRing] = None,
**kwargs: Any,
) -> None:
"""
Expand All @@ -944,37 +944,31 @@ def __init__(
The namespace for the KML element, by default None.
name_spaces : Optional[Dict[str, str]], optional
The namespace dictionary for the KML element, by default None.
geometries : Optional[Iterable[geo.LinearRing]], optional
The geometries to be converted to KML geometries, by default None.
kml_geometries : Optional[Iterable[LinearRing]], optional
The KML geometries, by default None.
geometry : Optional[geo.LinearRing], optional
The geometry to be converted to a KML geometry, by default None.
kml_geometry : Optional[LinearRing], optional
The KML geometry, by default None.
**kwargs : Any
Additional keyword arguments.
Raises
------
GeometryError
If both `geometries` and `kml_geometries` are provided.
If both `geometry` and `kml_geometry` are provided.
Notes
-----
- If `geometries` is provided, it will be converted to KML geometries and
stored in `kml_geometries`.
- If `geometries` is not provided, `kml_geometries` will be an empty list.
- If `geometry` is provided, it will be converted to KML geometries and
stored in `kml_geometry`.
- If `geometry` and `kml_geometry` are both provided, a GeometryError will be
raised.
"""
if geometries is not None and kml_geometries is not None:
if geometry is not None and kml_geometry is not None:
raise GeometryError(MsgMutualExclusive)
if kml_geometries is None:
kml_geometries = (
[
LinearRing(ns=ns, name_spaces=name_spaces, geometry=lr)
for lr in geometries
]
if geometries
else None
)
self.kml_geometries = list(kml_geometries) if kml_geometries else []
if kml_geometry is None:
kml_geometry = LinearRing(ns=ns, name_spaces=name_spaces, geometry=geometry)
self.kml_geometry = kml_geometry
super().__init__(
ns=ns,
name_spaces=name_spaces,
Expand All @@ -983,15 +977,15 @@ def __init__(

def __bool__(self) -> bool:
"""Return True if any of the inner boundary geometries exist."""
return any(b.geometry for b in self.kml_geometries)
return bool(self.kml_geometry)

def __repr__(self) -> str:
"""Create a string (c)representation for InnerBoundaryIs."""
return (
f"{self.__class__.__module__}.{self.__class__.__name__}("
f"ns={self.ns!r}, "
f"name_spaces={self.name_spaces!r}, "
f"kml_geometries={self.kml_geometries!r}, "
f"kml_geometry={self.kml_geometry!r}, "
f"**{self._get_splat()},"
")"
)
Expand All @@ -1002,26 +996,24 @@ def get_tag_name(cls) -> str:
return "innerBoundaryIs"

@property
def geometries(self) -> Optional[Iterable[geo.LinearRing]]:
def geometry(self) -> Optional[geo.LinearRing]:
"""
Return the list of LinearRing objects representing the inner boundary.
If no inner boundary geometries exist, returns None.
"""
if not self.kml_geometries:
return None
return [lr.geometry for lr in self.kml_geometries if lr.geometry]
return self.kml_geometry.geometry if self.kml_geometry else None


registry.register(
InnerBoundaryIs,
item=RegistryItem(
ns_ids=("kml",),
classes=(LinearRing,),
attr_name="kml_geometries",
attr_name="kml_geometry",
node_name="LinearRing",
get_kwarg=xml_subelement_list_kwarg,
set_element=xml_subelement_list,
get_kwarg=xml_subelement_kwarg,
set_element=xml_subelement,
),
)

Expand Down Expand Up @@ -1057,8 +1049,8 @@ class Polygon(_Geometry):

extrude: Optional[bool]
tessellate: Optional[bool]
outer_boundary_is: Optional[OuterBoundaryIs]
inner_boundary_is: Optional[InnerBoundaryIs]
outer_boundary: Optional[OuterBoundaryIs]
inner_boundaries: List[InnerBoundaryIs]

def __init__(
self,
Expand All @@ -1070,8 +1062,8 @@ def __init__(
extrude: Optional[bool] = None,
tessellate: Optional[bool] = None,
altitude_mode: Optional[AltitudeMode] = None,
outer_boundary_is: Optional[OuterBoundaryIs] = None,
inner_boundary_is: Optional[InnerBoundaryIs] = None,
outer_boundary: Optional[OuterBoundaryIs] = None,
inner_boundaries: Optional[Iterable[InnerBoundaryIs]] = None,
geometry: Optional[geo.Polygon] = None,
**kwargs: Any,
) -> None:
Expand All @@ -1094,9 +1086,9 @@ def __init__(
The tessellate flag of the element.
altitude_mode : Optional[AltitudeMode]
The altitude mode of the element.
outer_boundary_is : Optional[OuterBoundaryIs]
outer_boundary : Optional[OuterBoundaryIs]
The outer boundary of the element.
inner_boundary_is : Optional[InnerBoundaryIs]
inner_boundaries : Optional[Iterable[InnerBoundaryIs]]
The inner boundaries of the element.
geometry : Optional[geo.Polygon]
The geometry object of the element.
Expand All @@ -1113,13 +1105,15 @@ def __init__(
None
"""
if outer_boundary_is is not None and geometry is not None:
if outer_boundary is not None and geometry is not None:
raise GeometryError(MsgMutualExclusive)
if geometry is not None:
outer_boundary_is = OuterBoundaryIs(geometry=geometry.exterior)
inner_boundary_is = InnerBoundaryIs(geometries=geometry.interiors)
self.outer_boundary_is = outer_boundary_is
self.inner_boundary_is = inner_boundary_is
outer_boundary = OuterBoundaryIs(geometry=geometry.exterior)
inner_boundaries = [
InnerBoundaryIs(geometry=interior) for interior in geometry.interiors
]
self.outer_boundary = outer_boundary
self.inner_boundaries = list(inner_boundaries) if inner_boundaries else []
self.extrude = extrude
self.tessellate = tessellate
super().__init__(
Expand All @@ -1141,7 +1135,7 @@ def __bool__(self) -> bool:
True if the outer boundary is defined, False otherwise.
"""
return bool(self.outer_boundary_is)
return bool(self.outer_boundary)

@property
def geometry(self) -> Optional[geo.Polygon]:
Expand All @@ -1154,15 +1148,19 @@ def geometry(self) -> Optional[geo.Polygon]:
The geometry object representing the geometry of the Polygon.
"""
if not self.outer_boundary_is:
if not self.outer_boundary:
return None
if not self.inner_boundary_is:
if not self.inner_boundaries:
return geo.Polygon.from_linear_rings(
cast(geo.LinearRing, self.outer_boundary_is.geometry),
cast(geo.LinearRing, self.outer_boundary.geometry),
)
return geo.Polygon.from_linear_rings( # type: ignore[misc]
cast(geo.LinearRing, self.outer_boundary_is.geometry),
*self.inner_boundary_is.geometries,
return geo.Polygon.from_linear_rings(
cast(geo.LinearRing, self.outer_boundary.geometry),
*[
interior.geometry
for interior in self.inner_boundaries
if interior.geometry is not None
],
)

def __repr__(self) -> str:
Expand All @@ -1184,8 +1182,8 @@ def __repr__(self) -> str:
f"extrude={self.extrude!r}, "
f"tessellate={self.tessellate!r}, "
f"altitude_mode={self.altitude_mode}, "
f"outer_boundary_is={self.outer_boundary_is!r}, "
f"inner_boundary_is={self.inner_boundary_is!r}, "
f"outer_boundary={self.outer_boundary!r}, "
f"inner_boundaries={self.inner_boundaries!r}, "
f"**{self._get_splat()!r},"
")"
)
Expand All @@ -1196,7 +1194,7 @@ def __repr__(self) -> str:
item=RegistryItem(
ns_ids=("kml",),
classes=(OuterBoundaryIs,),
attr_name="outer_boundary_is",
attr_name="outer_boundary",
node_name="outerBoundaryIs",
get_kwarg=xml_subelement_kwarg,
set_element=xml_subelement,
Expand All @@ -1207,10 +1205,10 @@ def __repr__(self) -> str:
item=RegistryItem(
ns_ids=("kml",),
classes=(InnerBoundaryIs,),
attr_name="inner_boundary_is",
attr_name="inner_boundaries",
node_name="innerBoundaryIs",
get_kwarg=xml_subelement_kwarg,
set_element=xml_subelement,
get_kwarg=xml_subelement_list_kwarg,
set_element=xml_subelement_list,
),
)
registry.register(
Expand Down
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,8 @@ ignore_missing_imports = true
implicit_reexport = false
no_implicit_optional = true
overrides = [
{ disable_error_code = "attr-defined, union-attr", module = "tests.*" },
{ disable_error_code = "attr-defined, union-attr", module = "tests.oldunit_test" },
{ disable_error_code = "union-attr", module = "tests.*" },
]
show_error_codes = true
strict_equality = true
Expand Down
Loading

0 comments on commit c733635

Please sign in to comment.