The geo interface documentation says that properties is optional, yet it appears to be required by Fiona.
If I define a schema like so...
schema = {
"geometry": "Polygon",
# No properties defined here.
}
This already gives an error if I try to use this schema:
import fiona
from fiona.crs import from_epsg
f = fiona.open("tmp.shp", "w", schema={"geometry": "Polygon"}, crs=from_epsg(3035), driver="GeoJSON")
~/Workspace/anaconda/envs/et/lib/python3.7/site-packages/fiona/env.py in wrapper(*args, **kwargs)
404 with Env.from_defaults(session=session):
405 log.debug("Credentialized: {!r}".format(getenv()))
--> 406 return f(*args, **kwargs)
407 return wrapper
408
~/Workspace/anaconda/envs/et/lib/python3.7/site-packages/fiona/__init__.py in open(fp, mode, driver, schema, crs, encoding, layer, vfs, enabled_drivers, crs_wkt, **kwargs)
256 # Make an ordered dict of schema properties.
257 this_schema = schema.copy()
--> 258 this_schema['properties'] = OrderedDict(schema['properties'])
259 else:
260 this_schema = None
KeyError: 'properties'
If I amend the schema to have an empty properties field:
schema = {
"geometry": "Polygon",
"properties": {},
}
then the f = fiona.open("tmp.shp", "w", schema={"geometry": "Polygon"}, crs=fiona.crs.from_epsg(3035), driver="GeoJSON") call works, but I still get an error when trying to add a shape without a properties key. The following code...
import fiona
from fiona.crs import from_epsg
from shapely.geometry import Polygon, mapping
with fiona.open(
"tmp.shp",
"w",
driver="GeoJSON",
crs=from_epsg(3035),
schema=schema) as source:
polygon = Polygon(
[
(0, 0),
(1, 0),
(1, 1),
(1, 0)
]
)
shape = dict(geometry=mapping(invalid_shape))
source.write(shape)
gives the error
~/Workspace/anaconda/envs/et/lib/python3.7/site-packages/fiona/collection.py in write(self, record)
351 def write(self, record):
352 """Stages a record for writing to disk."""
--> 353 self.writerecords([record])
354
355 def validate_record(self, record):
~/Workspace/anaconda/envs/et/lib/python3.7/site-packages/fiona/collection.py in writerecords(self, records)
345 if self.mode not in ('a', 'w'):
346 raise IOError("collection not open for writing")
--> 347 self.session.writerecs(records, self)
348 self._len = self.session.get_length()
349 self._bounds = self.session.get_extent()
fiona/ogrext.pyx in fiona.ogrext.WritingSession.writerecs()
KeyError: 'properties'
It seems that the properties key is required both in the schema and in the written data, even though the spec doesn't seem to require it. Merely using empty dicts appears to fix this issue, but Fiona probably shouldn't require these keys at all.
Ubuntu 18.04.
Fiona 1.8.6 via pip on Python 3.7.3 via conda.
Thanks @SeanDS . Features and datasets without non-geometry properties haven't been on our radar. I'm not sure if all formats allow them, but the library probably doesn't need to require them.
How should unexpected keys be handled? For example:
feature = {
"geometry": {"type": "Point", "coordinates": [0, 0]},
"property": {"name": "example"}, # a mistake, should be properties
}
collection.write(feature)
In the current behaviour an exception would be raised. I guess this should still raise if the feature doesn't match the properties in the schema?
@snorfalorpagus good question. The GeoJSON driver can handle extra keys in a limited way (see "NATIVE_DATA" under https://gdal.org/drivers/vector/geojson.html#open-options), but no other driver can. In fiona 2 your code won't be valid, we'll have a real Feature class with a proper constructor with specific keyword arguments. Meanwhile, for 1.8 and 1.9 let's be pragmatic: don't require properties in the schema, but do require that features match the schema. How about that?