Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Undo deprecation of dicts #1177

Merged
merged 2 commits into from
Jan 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ All issue numbers are relative to https://github.com/Toblerity/Fiona/issues.
1.9b2 (TBD)
-----------

- Functions that take Feature or Geometry objects will continue to take dicts
or objects that provide __geo_interface__ (#1177). This reverses the
deprecation introduced in 1.9a2.
- Python ignores SIGPIPE by default. By never catching BrokenPipeError via
`except Exception` when, for example, piping the output of rio-shapes to
the Unix head program, we avoid getting an unhandled BrokenPipeError message
Expand Down
4 changes: 2 additions & 2 deletions fiona/_geometry.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ include "gdal.pxi"
import logging

from fiona.errors import UnsupportedGeometryTypeError
from fiona.model import _guard_model_object, GEOMETRY_TYPES, Geometry, OGRGeometryType
from fiona.model import decode_object, GEOMETRY_TYPES, Geometry, OGRGeometryType
from fiona._err cimport exc_wrap_int


Expand Down Expand Up @@ -363,7 +363,7 @@ cdef class OGRGeomBuilder:

def geometryRT(geom):
# For testing purposes only, leaks the JSON data
geometry = _guard_model_object(geom)
geometry = decode_object(geom)
cdef void *cogr_geometry = OGRGeomBuilder().build(geometry)
result = GeomBuilder().build(cogr_geometry)
_deleteOgrGeom(cogr_geometry)
Expand Down
30 changes: 10 additions & 20 deletions fiona/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -380,12 +380,17 @@ def decode_object(obj):
Feature, Geometry, or dict

"""
if (obj.get("type", None) == "Feature") or "geometry" in obj:
return Feature.from_dict(**obj)
elif obj.get("type", None) in list(GEOMETRY_TYPES.values())[:8]:
return Geometry.from_dict(**obj)
else:
if isinstance(obj, Object):
return obj
else:
obj = obj.get("__geo_interface__", obj)

if (obj.get("type", None) == "Feature") or "geometry" in obj:
return Feature.from_dict(**obj)
elif obj.get("type", None) in list(GEOMETRY_TYPES.values())[:8]:
return Geometry.from_dict(**obj)
else:
return obj


def to_dict(val):
Expand All @@ -396,18 +401,3 @@ def to_dict(val):
return val
else:
return obj


def _guard_model_object(obj):
"""Convert dict to Geometry or Feature.

For use during the 1.9-2.0 transition. Will be removed in 2.0.

"""
if not isinstance(obj, Object):
warn(
"Support for feature and geometry dicts is deprecated. Instances of Feature and Geometry will be required in 2.0.",
FionaDeprecationWarning,
stacklevel=2,
)
return decode_object(obj)
51 changes: 32 additions & 19 deletions fiona/ogrext.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ from fiona.env import Env
from fiona.errors import (
DriverError, DriverIOError, SchemaError, CRSError, FionaValueError,
TransactionError, GeometryTypeValidationError, DatasetDeleteError,
AttributeFilterError, FeatureWarning, FionaDeprecationWarning)
from fiona.model import _guard_model_object, Feature, Geometry, Properties
AttributeFilterError, FeatureWarning, FionaDeprecationWarning, UnsupportedGeometryTypeError)
from fiona.model import decode_object, Feature, Geometry, Properties
from fiona.path import vsi_path
from fiona.rfc3339 import parse_date, parse_datetime, parse_time
from fiona.rfc3339 import FionaDateType, FionaDateTimeType, FionaTimeType
Expand Down Expand Up @@ -508,7 +508,7 @@ cdef _deleteOgrFeature(void *cogr_feature):

def featureRT(feat, collection):
# For testing purposes only, leaks the JSON data
feature = _guard_model_object(feat)
feature = decode_object(feat)
cdef void *cogr_feature = OGRFeatureBuilder().build(feature, collection)
cdef void *cogr_geometry = OGR_F_GetGeometryRef(cogr_feature)
if cogr_geometry == NULL:
Expand Down Expand Up @@ -1273,19 +1273,28 @@ cdef class WritingSession(Session):
log.debug("Writing started")

def writerecs(self, records, collection):
"""Writes buffered records to OGR."""
"""Writes records to collection storage.

Parameters
----------
records : Iterable
A stream of feature records.
collection : Collection
The collection in which feature records are stored.

Returns
-------
None

"""
cdef void *cogr_driver
cdef void *cogr_feature
cdef int features_in_transaction = 0

cdef void *cogr_layer = self.cogr_layer

if cogr_layer == NULL:
raise ValueError("Null layer")

schema_geom_type = collection.schema['geometry']
cogr_driver = GDALGetDatasetDriver(self.cogr_ds)
driver_name = OGR_Dr_GetName(cogr_driver).decode("utf-8")

valid_geom_types = collection._valid_geom_types

def validate_geometry_type(record):
Expand All @@ -1295,6 +1304,7 @@ cdef class WritingSession(Session):

transactions_supported = GDALDatasetTestCapability(self.cogr_ds, ODsCTransactions)
log.debug("Transaction supported: {}".format(transactions_supported))

if transactions_supported:
log.debug("Starting transaction (initial)")
result = GDALDatasetStartTransaction(self.cogr_ds, 0)
Expand All @@ -1304,13 +1314,7 @@ cdef class WritingSession(Session):
schema_props_keys = set(collection.schema['properties'].keys())

for _rec in records:
record = _guard_model_object(_rec)

# Check for optional elements
# if 'properties' not in _rec:
# _rec['properties'] = {}
# if 'geometry' not in _rec:
# _rec['geometry'] = None
record = decode_object(_rec)

# Validate against collection's schema.
if set(record.properties.keys()) != schema_props_keys:
Expand All @@ -1328,24 +1332,33 @@ cdef class WritingSession(Session):

cogr_feature = OGRFeatureBuilder().build(record, collection)
result = OGR_L_CreateFeature(cogr_layer, cogr_feature)

if result != OGRERR_NONE:
msg = get_last_error_msg()
raise RuntimeError("GDAL Error: {msg} \n \n Failed to write record: "
"{record}".format(msg=msg, record=record))
raise RuntimeError(
"GDAL Error: {msg}. Failed to write record: {record}".format(
msg=msg, record=record
)
)

_deleteOgrFeature(cogr_feature)

if transactions_supported:
features_in_transaction += 1

if features_in_transaction == DEFAULT_TRANSACTION_SIZE:
log.debug("Committing transaction (intermediate)")
result = GDALDatasetCommitTransaction(self.cogr_ds)

if result == OGRERR_FAILURE:
raise TransactionError("Failed to commit transaction")

log.debug("Starting transaction (intermediate)")
result = GDALDatasetStartTransaction(self.cogr_ds, 0)

if result == OGRERR_FAILURE:
raise TransactionError("Failed to start transaction")

features_in_transaction = 0

if transactions_supported:
Expand Down Expand Up @@ -1475,7 +1488,7 @@ cdef class Iterator:
OGR_L_SetSpatialFilterRect(
cogr_layer, bbox[0], bbox[1], bbox[2], bbox[3])
elif mask:
mask_geom = _guard_model_object(mask)
mask_geom = decode_object(mask)
cogr_geometry = OGRGeomBuilder().build(mask_geom)
OGR_L_SetSpatialFilter(cogr_layer, cogr_geometry)
OGR_G_DestroyGeometry(cogr_geometry)
Expand Down
6 changes: 3 additions & 3 deletions fiona/transform.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from fiona._transform import _transform, _transform_geom
from fiona.compat import DICT_TYPES
from fiona.errors import FionaDeprecationWarning
from fiona.model import _guard_model_object, Geometry
from fiona.model import decode_object, Geometry


def transform(src_crs, dst_crs, xs, ys):
Expand Down Expand Up @@ -108,7 +108,7 @@ def transform_geom(
return _transform_geom(
src_crs,
dst_crs,
_guard_model_object(geom),
decode_object(geom),
antimeridian_cutting,
antimeridian_offset,
precision,
Expand All @@ -117,7 +117,7 @@ def transform_geom(
return _transform_geom(
src_crs,
dst_crs,
(_guard_model_object(g) for g in geom),
(decode_object(g) for g in geom),
antimeridian_cutting,
antimeridian_offset,
precision,
Expand Down
8 changes: 3 additions & 5 deletions tests/test_feature.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
import fiona
from fiona import collection
from fiona.collection import Collection
from fiona.errors import FionaDeprecationWarning
from fiona.model import Feature
from fiona.ogrext import featureRT

Expand All @@ -36,10 +35,9 @@ def test_geometry(self):
"geometry": {"type": "Point", "coordinates": (0.0, 0.0)},
"properties": {"title": "foo"},
}
with pytest.warns(FionaDeprecationWarning):
g = featureRT(f, self.c)
assert g.geometry.type == "Point"
assert g.geometry.coordinates == (0.0, 0.0)
g = featureRT(f, self.c)
assert g.geometry.type == "Point"
assert g.geometry.coordinates == (0.0, 0.0)

def test_properties(self):
f = Feature.from_dict(
Expand Down
7 changes: 3 additions & 4 deletions tests/test_geometry.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,9 @@ def test_geometry_collection_round_trip():
],
}

with pytest.warns(DeprecationWarning):
result = geometryRT(geom)
assert len(result["geometries"]) == 2
assert [g["type"] for g in result["geometries"]] == ["Point", "LineString"]
result = geometryRT(geom)
assert len(result["geometries"]) == 2
assert [g["type"] for g in result["geometries"]] == ["Point", "LineString"]


def test_point_wkb():
Expand Down
11 changes: 5 additions & 6 deletions tests/test_transform.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,15 +119,14 @@ def test_transform_issue971():
}
],
}
with pytest.warns(FionaDeprecationWarning):
geom_transformed = transform.transform_geom(source_crs, dest_src, geom)
assert geom_transformed.geometries[0].coordinates[0] == pytest.approx(
(9.18427, 52.94630)
)
geom_transformed = transform.transform_geom(source_crs, dest_src, geom)
assert geom_transformed.geometries[0].coordinates[0] == pytest.approx(
(9.18427, 52.94630)
)


def test_transform_geom_precision_deprecation():
"""Get a deprecation warning in 1.9"""
"""Get a precision deprecation warning in 1.9."""
with pytest.warns(FionaDeprecationWarning):
transform.transform_geom(
"epsg:4326",
Expand Down