Skip to content

Commit 5a73032

Browse files
committed
using strict types.
2 parents 3d63ab1 + 21001df commit 5a73032

File tree

10 files changed

+576
-233
lines changed

10 files changed

+576
-233
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ jobs:
1515
runs-on: ubuntu-latest
1616
strategy:
1717
matrix:
18-
python-version: ['3.7', '3.8', '3.9', '3.10', '3.11']
18+
python-version: ['3.8', '3.9', '3.10', '3.11']
1919

2020
steps:
2121
- uses: actions/checkout@v3

.pre-commit-config.yaml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
repos:
22
- repo: https://github.com/psf/black
3-
rev: 22.6.0
3+
rev: 22.12.0
44
hooks:
55
- id: black
66
language_version: python
77

88
- repo: https://github.com/PyCQA/isort
9-
rev: 5.10.1
9+
rev: 5.12.0
1010
hooks:
1111
- id: isort
1212
language_version: python
1313

1414
- repo: https://github.com/PyCQA/flake8
15-
rev: 5.0.4
15+
rev: 6.0.0
1616
hooks:
1717
- id: flake8
1818
language_version: python
@@ -26,7 +26,7 @@ repos:
2626
- toml
2727

2828
- repo: https://github.com/pre-commit/mirrors-mypy
29-
rev: v0.971
29+
rev: v0.991
3030
hooks:
3131
- id: mypy
3232
language_version: python

CHANGELOG.md

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,46 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](http://keepachangelog.com/)
66
and this project adheres to [Semantic Versioning](http://semver.org/).
77

8-
## [unreleased]
8+
## [0.6.0] - TBD
99

10+
### Added
11+
12+
- Enforce required keys and avoid defaults. This aim to follow the geojson specification to the letter.
13+
14+
```python
15+
# Before
16+
Feature(geometry=Point(coordinates=(0,0)))
17+
18+
# Now
19+
Feature(
20+
type="Feature",
21+
geometry=Point(
22+
type="Point",
23+
coordinates=(0,0)
24+
),
25+
properties=None,
26+
)
27+
```
28+
29+
- Add has_z function to Geometries (author @eseglem, https://github.com/developmentseed/geojson-pydantic/pull/103)
30+
- Add optional bbox to geometries.
31+
32+
### Changed
33+
34+
- Refactor and simplify WKT construction (author @eseglem, https://github.com/developmentseed/geojson-pydantic/pull/97)
35+
- Support empty geometry coordinates (author @eseglem, https://github.com/developmentseed/geojson-pydantic/pull/100)
36+
37+
### Fixed
38+
39+
- Do not validates arbitrary dictionaries. Make `Type` a mandatory key for objects (https://github.com/developmentseed/geojson-pydantic/pull/94)
40+
- Add Geometry discriminator when parsing geometry objects (author @eseglem, https://github.com/developmentseed/geojson-pydantic/pull/101)
41+
- Mixed Dimensionality WKTs (make sure the coordinates are either all 2D or 3D) (author @eseglem, https://github.com/developmentseed/geojson-pydantic/pull/107)
1042
- allow Feature's **id** to be either a String or a Number
1143

44+
### Removed
45+
46+
- python 3.7 support
47+
1248
## [0.5.0] - 2022-12-16
1349

1450
### Added

geojson_pydantic/features.py

Lines changed: 11 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,25 @@
11
"""pydantic models for GeoJSON Feature objects."""
22

3-
from typing import Any, Dict, Generic, Iterator, List, Optional, TypeVar, Union
3+
from typing import Any, Dict, Generic, Iterator, List, Literal, Optional, TypeVar, Union
44

5-
from pydantic import BaseModel, Field, validator
5+
from pydantic import BaseModel, Field, StrictInt, StrictStr, validator
66
from pydantic.generics import GenericModel
77

8+
from geojson_pydantic.geo_interface import GeoInterfaceMixin
89
from geojson_pydantic.geometries import Geometry, GeometryCollection
910
from geojson_pydantic.types import BBox
1011

1112
Props = TypeVar("Props", bound=Union[Dict[str, Any], BaseModel])
1213
Geom = TypeVar("Geom", bound=Union[Geometry, GeometryCollection])
1314

1415

15-
class Feature(GenericModel, Generic[Geom, Props]):
16+
class Feature(GenericModel, Generic[Geom, Props], GeoInterfaceMixin):
1617
"""Feature Model"""
1718

18-
type: str = Field(default="Feature", const=True)
19-
geometry: Optional[Geom] = None
20-
properties: Optional[Props] = None
21-
id: Optional[Union[int, str]] = None
19+
type: Literal["Feature"]
20+
geometry: Union[Geom, None] = Field(...)
21+
properties: Union[Props, None] = Field(...)
22+
id: Optional[Union[StrictInt, StrictStr]] = None
2223
bbox: Optional[BBox] = None
2324

2425
class Config:
@@ -32,36 +33,14 @@ def set_geometry(cls, geometry: Any) -> Any:
3233
"""set geometry from geo interface or input"""
3334
if hasattr(geometry, "__geo_interface__"):
3435
return geometry.__geo_interface__
35-
return geometry
36-
37-
@property
38-
def __geo_interface__(self) -> Dict[str, Any]:
39-
"""GeoJSON-like protocol for geo-spatial (GIS) vector data.
40-
41-
ref: https://gist.github.com/sgillies/2217756#__geo_interface
42-
"""
43-
geo: Dict[str, Any] = {
44-
"type": self.type,
45-
"geometry": self.geometry.__geo_interface__
46-
if self.geometry is not None
47-
else None,
48-
}
49-
if self.bbox:
50-
geo["bbox"] = self.bbox
51-
52-
if self.id:
53-
geo["id"] = self.id
54-
55-
if self.properties:
56-
geo["properties"] = self.properties
5736

58-
return geo
37+
return geometry
5938

6039

61-
class FeatureCollection(GenericModel, Generic[Geom, Props]):
40+
class FeatureCollection(GenericModel, Generic[Geom, Props], GeoInterfaceMixin):
6241
"""FeatureCollection Model"""
6342

64-
type: str = Field(default="FeatureCollection", const=True)
43+
type: Literal["FeatureCollection"]
6544
features: List[Feature[Geom, Props]]
6645
bbox: Optional[BBox] = None
6746

@@ -76,19 +55,3 @@ def __len__(self) -> int:
7655
def __getitem__(self, index: int) -> Feature:
7756
"""get feature at a given index"""
7857
return self.features[index]
79-
80-
@property
81-
def __geo_interface__(self) -> Dict[str, Any]:
82-
"""GeoJSON-like protocol for geo-spatial (GIS) vector data.
83-
84-
ref: https://gist.github.com/sgillies/2217756#__geo_interface
85-
"""
86-
features: List[Dict[str, Any]] = []
87-
for feat in self.features:
88-
features.append(feat.__geo_interface__)
89-
90-
geo: Dict[str, Any] = {"type": self.type, "features": features}
91-
if self.bbox:
92-
geo["bbox"] = self.bbox
93-
94-
return geo

geojson_pydantic/geo_interface.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
"""Mixin for __geo_interface__ on GeoJSON objects."""
2+
3+
from typing import Any, Dict, Protocol
4+
5+
6+
class _DictProtocol(Protocol):
7+
"""Protocol for use as the type of self in the mixin."""
8+
9+
def dict(self, *, exclude_unset: bool, **args: Any) -> Dict[str, Any]:
10+
"""Define a dict function so the mixin knows it exists."""
11+
...
12+
13+
14+
class GeoInterfaceMixin:
15+
"""Mixin for __geo_interface__ on GeoJSON objects."""
16+
17+
@property
18+
def __geo_interface__(self: _DictProtocol) -> Dict[str, Any]:
19+
"""GeoJSON-like protocol for geo-spatial (GIS) vector data.
20+
21+
ref: https://gist.github.com/sgillies/2217756#__geo_interface
22+
"""
23+
return self.dict(exclude_unset=True)

0 commit comments

Comments
 (0)