Skip to content

Commit

Permalink
Merge branch 'release/v0.8.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
jlhumber committed Aug 26, 2024
2 parents 66091f1 + 90c6ebd commit 74ed84c
Show file tree
Hide file tree
Showing 24 changed files with 667 additions and 416 deletions.
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2021-2023 Integrated Informatics Inc
Copyright (c) 2021-2024 Integrated Informatics Inc

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
78 changes: 39 additions & 39 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,6 @@ either of these options are enabled, the geometry inserted into the
Feature Class **must** include a value for the option specified.

```python
from typing import Tuple
from fudgeo.enumeration import GeometryType, SQLFieldType
from fudgeo.geopkg import FeatureClass, Field, GeoPackage, SpatialReferenceSystem

Expand All @@ -99,7 +98,7 @@ SRS_WKT: str = (
SRS: SpatialReferenceSystem = SpatialReferenceSystem(
name='WGS_1984_UTM_Zone_23N', organization='EPSG',
org_coord_sys_id=32623, definition=SRS_WKT)
fields: Tuple[Field, ...] = (
fields: tuple[Field, ...] = (
Field('road_id', SQLFieldType.integer),
Field('name', SQLFieldType.text, size=100),
Field('begin_easting', SQLFieldType.double),
Expand Down Expand Up @@ -137,13 +136,12 @@ portion of the code is omitted...
```python
from random import choice, randint
from string import ascii_uppercase, digits
from typing import List, Tuple

from fudgeo.geometry import LineStringM
from fudgeo.geopkg import GeoPackage

# Generate some random points and attributes
rows: List[Tuple[LineStringM, int, str, float, float, float, float, bool]] = []
rows: list[tuple[LineStringM, int, str, float, float, float, float, bool]] = []
for i in range(10000):
name = ''.join(choice(ascii_uppercase + digits) for _ in range(10))
road_id = randint(0, 1000)
Expand Down Expand Up @@ -171,68 +169,66 @@ of this package.


```python
from typing import List, Tuple
from fudgeo.geometry import LineStringZM, Point, Polygon

# Point in WGS 84
pt: Point = Point(x=-119, y=34)

# Line with ZM Values for use with UTM Zone 23N (WGS 84)
coords: List[Tuple[float, float, float, float]] = [
coords: list[tuple[float, float, float, float]] = [
(300000, 1, 10, 0), (300000, 4000000, 20, 1000),
(700000, 4000000, 30, 2000), (700000, 1, 40, 3000)]
line: LineStringZM = LineStringZM(coords, srs_id=32623)

# list of rings where a ring is simply the list of points it contains.
rings: List[List[Tuple[float, float]]] = [
rings: list[list[tuple[float, float]]] = [
[(300000, 1), (300000, 4000000), (700000, 4000000), (700000, 1), (300000, 1)]]
poly: Polygon = Polygon(rings, srs_id=32623)
```

### Select Features from GeoPackage (SQL)
### Select Features from GeoPackage

When selecting features from a GeoPackage feature class use SQL. For
the most part (mainly simple geometries e.g. those without *Z* or *M*) this
can be done via a basic `SELECT` statement like:
When selecting features from a GeoPackage feature class use SQL or use the
helper method `select`.

For simple geometries (e.g. those without *Z* or *M*) this can be done via a
basic `SELECT` statement or the `select` method.

```python
from fudgeo.geometry import Point
from fudgeo.geopkg import FeatureClass, GeoPackage

gpkg = GeoPackage(...)

# NOTE for fudgeo version v0.8.0 and above use helper method
fc = FeatureClass(geopackage=gpkg, name='point_fc')
cursor = fc.select(fields=('example_id',), include_geometry=True)
features: list[tuple[Point, int]] = cursor.fetchall()

# NOTE for fudgeo prior to v0.8.0
cursor = gpkg.connection.execute("""SELECT SHAPE, example_id FROM point_fc""")
features = cursor.fetchall()
features: list[tuple[Point, int]] = cursor.fetchall()
```

This will return a list of tuples where each tuple contains a `Point`
object and an integer for `example_id` field.
When using SQL with extended geometry types (e.g. those with *Z* and/or *M*)
then ensure `SQLite` knows how to convert the geopackage stored geometry to a
`fudgeo` geometry by including the converter, this is done like so:

When working with extended geometry types (those with *Z* and/or *M*)
then the approach is to ensure `SQLite` knows how to convert the
geopackage stored geometry to a `fudgeo` geometry, this is done like so:

```python
from typing import List, Tuple
from fudgeo.geometry import LineStringM
from fudgeo.geopkg import GeoPackage
from fudgeo.geopkg import FeatureClass, GeoPackage

gpkg: GeoPackage = GeoPackage('../data/example.gpkg')
gpkg = GeoPackage('../data/example.gpkg')
# NOTE for fudgeo version v0.8.0 and above use helper method
fc = FeatureClass(geopackage=gpkg, name='test')
cursor = fc.select(fields=('road_id',), include_geometry=True)
features: list[tuple[LineStringM, int]] = cursor.fetchall()

# NOTE for fudgeo prior to v0.8.0
cursor = gpkg.connection.execute(
"""SELECT SHAPE "[LineStringM]", road_id FROM test""")
features: List[Tuple[LineStringM, int]] = cursor.fetchall()
```

or a little more general, accounting for extended geometry types and
possibility of the geometry column being something other tha `SHAPE`:

```python
from typing import List, Tuple
from fudgeo.geometry import LineStringM
from fudgeo.geopkg import FeatureClass, GeoPackage

gpkg: GeoPackage = GeoPackage('../data/example.gpkg')
fc: FeatureClass = FeatureClass(geopackage=gpkg, name='road_l')
cursor = gpkg.connection.execute(f"""
SELECT {fc.geometry_column_name} "[{fc.geometry_type}]", road_id
FROM {fc.escaped_name}""")
features: List[Tuple[LineStringM, int]] = cursor.fetchall()
features: list[tuple[LineStringM, int]] = cursor.fetchall()
```


Expand All @@ -245,7 +241,6 @@ Spatial Indexes apply to individual feature classes. A spatial index can be
added at create time or added on an existing feature class.

```python
from typing import Tuple
from fudgeo.enumeration import SQLFieldType
from fudgeo.geopkg import FeatureClass, Field, GeoPackage, SpatialReferenceSystem

Expand All @@ -267,7 +262,7 @@ SRS_WKT: str = (
SRS: SpatialReferenceSystem = SpatialReferenceSystem(
name='WGS_1984_UTM_Zone_23N', organization='EPSG',
org_coord_sys_id=32623, definition=SRS_WKT)
fields: Tuple[Field, ...] = (
fields: tuple[Field, ...] = (
Field('id', SQLFieldType.integer),
Field('name', SQLFieldType.text, size=100))

Expand Down Expand Up @@ -422,6 +417,11 @@ Support provided for the following constraint types:

## Release History

### v0.8.0
* drop support for Python 3.7 and 3.8
* modernize type hinting
* add `select` method to `FeatureClass` and `Table` objects

### v0.7.2
* bump `user_version` to reflect adopted version 1.4.0 of OGC GeoPackage
* updated r-tree triggers based on changes made in 1.4.0
Expand Down
4 changes: 2 additions & 2 deletions fudgeo/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
"""


__version__ = '0.7.2'
__version__ = '0.8.0'


if __name__ == '__main__':
if __name__ == '__main__': # pragma: no cover
pass
77 changes: 77 additions & 0 deletions fudgeo/alias.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# -*- coding: utf-8 -*-
"""
Type Hint Aliases
"""


from datetime import datetime
from typing import Optional, TYPE_CHECKING, Union


if TYPE_CHECKING: # pragma: no cover
# noinspection PyUnresolvedReferences
from fudgeo.geopkg import FeatureClass, Field, Table
# noinspection PyUnresolvedReferences
from fudgeo.extension.metadata import (
GeoPackageReference, TableReference, ColumnReference,
RowReference, RowColumnReference)
# noinspection PyUnresolvedReferences
from fudgeo.extension.schema import (
EnumerationConstraint, GlobConstraint, RangeConstraint)
# noinspection PyUnresolvedReferences
from fudgeo.geometry.linestring import (
LineString, LineStringZ, LineStringM, LineStringZM)
# noinspection PyUnresolvedReferences
from fudgeo.geometry.polygon import (
LinearRing, LinearRingZ, LinearRingM, LinearRingZM,
Polygon, PolygonZ, PolygonM, PolygonZM)


INT = Optional[int]
BOOL = Optional[bool]
DATE = Optional[datetime]
FLOAT = Optional[float]
STRING = Optional[str]
BYTE_ARRAY = Optional[bytearray]


TABLE = Union['Table', 'FeatureClass']
FIELDS = Union[tuple['Field', ...], list['Field']]
FIELD_NAMES = Union[tuple[str, ...], list[str]]


REFERENCE_RECORD = tuple[
str, STRING, STRING, INT, datetime, int, INT]
REFERENCE = Union[
'GeoPackageReference', 'TableReference', 'ColumnReference',
'RowReference', 'RowColumnReference']
REFERENCES = Union[REFERENCE, tuple[REFERENCE, ...], list[REFERENCE]]


RECORDS = list[
tuple[str, str, STRING, FLOAT, INT, FLOAT, INT, STRING]]
CONSTRAINT = Union[
'EnumerationConstraint', 'GlobConstraint', 'RangeConstraint']
CONSTRAINTS = Union[
CONSTRAINT, list[CONSTRAINT], tuple[CONSTRAINT, ...]]


NONES = tuple[None, None, None, None]
DOUBLE = tuple[float, float]
TRIPLE = tuple[float, float, float]
QUADRUPLE = tuple[float, float, float, float]
COORDINATES = Union[list[DOUBLE], list[TRIPLE], list[QUADRUPLE]]


GEOMS = Union[
list['LineString'], list['LinearRing'], list['Polygon']]
GEOMS_Z = Union[
list['LineStringZ'], list['LinearRingZ'], list['PolygonZ']]
GEOMS_M = Union[
list['LineStringM'], list['LinearRingM'], list['PolygonM']]
GEOMS_ZM = Union[
list['LineStringZM'], list['LinearRingZM'], list['PolygonZM']]


if __name__ == '__main__': # pragma: no cover
pass
16 changes: 6 additions & 10 deletions fudgeo/constant.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,9 @@


from struct import pack
from typing import Dict, List, Set, Tuple, Union

from fudgeo.enumeration import EnvelopeCode

DOUBLE = Tuple[float, float]
TRIPLE = Tuple[float, float, float]
QUADRUPLE = Tuple[float, float, float, float]
COORDINATES = Union[List[DOUBLE], List[TRIPLE], List[QUADRUPLE]]

COMMA_SPACE: str = ', '
GPKG_EXT: str = '.gpkg'
Expand Down Expand Up @@ -68,22 +63,23 @@
WKB_MULTI_POLYGON_ZM_PRE: bytes = pack(BYTE_CODE, 1, 3006)


POINT_PREFIX_ZM: Dict[Tuple[bool, bool], bytes] = {
POINT_PREFIX_ZM: dict[tuple[bool, bool], bytes] = {
(False, False): WKB_POINT_PRE,
(True, False): WKB_POINT_Z_PRE,
(False, True): WKB_POINT_M_PRE,
(True, True): WKB_POINT_ZM_PRE,
}
POINT_PREFIXES: Set[bytes] = {
POINT_PREFIXES: set[bytes] = {
WKB_POINT_PRE, WKB_POINT_Z_PRE, WKB_POINT_M_PRE, WKB_POINT_ZM_PRE}


HEADER_OFFSET: int = 8
ENVELOPE_LENGTH: Dict[int, int] = {
ENVELOPE_LENGTH: dict[int, int] = {
EnvelopeCode.empty: 0, EnvelopeCode.xy: 32, EnvelopeCode.xyz: 48,
EnvelopeCode.xym: 48, EnvelopeCode.xyzm: 64}
ENVELOPE_COUNT: Dict[int, int] = {k: v // 8 for k, v in ENVELOPE_LENGTH.items()}
ENVELOPE_OFFSET = {k: v + HEADER_OFFSET for k, v in ENVELOPE_LENGTH.items()}
ENVELOPE_COUNT: dict[int, int] = {k: v // 8 for k, v in ENVELOPE_LENGTH.items()}
ENVELOPE_OFFSET: dict[int, int] = {
k: v + HEADER_OFFSET for k, v in ENVELOPE_LENGTH.items()}


if __name__ == '__main__': # pragma: no cover
Expand Down
2 changes: 1 addition & 1 deletion fudgeo/extension/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@
"""


if __name__ == '__main__':
if __name__ == '__main__': # pragma: no cover
pass
Loading

0 comments on commit 74ed84c

Please sign in to comment.