rename geometries property to geometry_types

This commit is contained in:
Emily Soth 2025-05-12 16:21:11 -07:00
parent 214a617e0d
commit 138337f088
7 changed files with 49 additions and 49 deletions

View File

@ -326,7 +326,7 @@ class VectorInput(FileInput):
are allowed). It is assumed that only the first layer is used.
Attributes:
geometries: A set of geometry type(s) that are allowed for this vector
geometry_types: A set of geometry type(s) that are allowed for this vector
fields: An iterable of `Input`s representing the fields that this
vector is expected to have. The `key` of each input must match the
corresponding field name.
@ -337,7 +337,7 @@ class VectorInput(FileInput):
specific unit of projection (such as meters) is required, indicate
it here.
"""
geometries: set = dataclasses.field(default_factory=dict)
geometry_types: set = dataclasses.field(default_factory=dict)
fields: typing.Union[typing.Iterable[Input], None] = None
projected: typing.Union[bool, None] = None
projection_units: typing.Union[pint.Unit, None] = None
@ -383,7 +383,7 @@ class VectorInput(FileInput):
}
allowed_geom_types = []
for geom in self.geometries:
for geom in self.geometry_types:
allowed_geom_types += geom_map[geom]
# NOTE: this only checks the layer geometry type, not the types of the
@ -393,7 +393,7 @@ class VectorInput(FileInput):
# Currently not supporting ogr.wkbUnknown which allows mixed types.
layer = gdal_dataset.GetLayer()
if layer.GetGeomType() not in allowed_geom_types:
return get_message('WRONG_GEOM_TYPE').format(allowed=self.geometries)
return get_message('WRONG_GEOM_TYPE').format(allowed=self.geometry_types)
if self.fields:
field_patterns = []
@ -420,7 +420,7 @@ class RasterOrVectorInput(SingleBandRasterInput, VectorInput):
"""An invest model input that can be either a raster or a vector.
Attributes:
geometries: A set of geometry type(s) that are allowed for this vector
geometry_types: A set of geometry type(s) that are allowed for this vector
fields: An iterable of `Input`s representing the fields that this
vector is expected to have. The `key` of each input must match the
corresponding field name.
@ -432,7 +432,7 @@ class RasterOrVectorInput(SingleBandRasterInput, VectorInput):
it here.
"""
band: typing.Union[Input, None] = None
geometries: set = dataclasses.field(default_factory=dict)
geometry_types: set = dataclasses.field(default_factory=dict)
fields: typing.Union[typing.Iterable[Input], None] = None
projected: typing.Union[bool, None] = None
projection_units: typing.Union[pint.Unit, None] = None
@ -1037,12 +1037,12 @@ class VectorOutput(Output):
are allowed). It is assumed that only the first layer is used.
Attributes:
geometries: A set of geometry type(s) that are produced in this vector
geometry_types: A set of geometry type(s) that are produced in this vector
fields: An iterable of `Output`s representing the fields created in
this vector. The `key` of each input must match the corresponding
field name.
"""
geometries: set = dataclasses.field(default_factory=set)
geometry_types: set = dataclasses.field(default_factory=set)
fields: typing.Union[typing.Iterable[Output], None] = None
@dataclasses.dataclass
@ -1178,7 +1178,7 @@ class ModelSpec:
"""Serialize objects that are otherwise not JSON serializeable."""
if isinstance(obj, pint.Unit):
return format_unit(obj)
# Sets are present in 'geometries' attributes of some args
# Sets are present in 'geometry_types' attributes of some args
# We don't need to worry about deserializing back to a set/array
# so casting to string is okay.
elif isinstance(obj, set):
@ -1272,7 +1272,7 @@ def build_input_spec(argkey, arg):
elif t == 'vector':
return VectorInput(
**base_attrs,
geometries=arg['geometries'],
geometry_types=arg['geometries'],
fields=[build_input_spec(key, field_spec)
for key, field_spec in arg['fields'].items()],
projected=arg.get('projected', None),
@ -1308,7 +1308,7 @@ def build_input_spec(argkey, arg):
elif t == {'raster', 'vector'}:
return RasterOrVectorInput(
**base_attrs,
geometries=arg['geometries'],
geometry_types=arg['geometries'],
fields=[build_input_spec(key, field_spec)
for key, field_spec in arg['fields'].items()],
band=build_input_spec('1', arg['bands'][1]),
@ -1366,7 +1366,7 @@ def build_output_spec(key, spec):
elif t == 'vector':
return VectorOutput(
**base_attrs,
geometries=spec['geometries'],
geometry_types=spec['geometries'],
fields=[build_output_spec(key, field_spec)
for key, field_spec in spec['fields'].items()])
@ -1678,7 +1678,7 @@ def serialize_args_spec(spec):
"""Serialize objects that are otherwise not JSON serializeable."""
if isinstance(obj, pint.Unit):
return format_unit(obj)
# Sets are present in 'geometries' attributes of some args
# Sets are present in 'geometry_types' attributes of some args
# We don't need to worry about deserializing back to a set/array
# so casting to string is okay.
elif isinstance(obj, set):
@ -1690,7 +1690,7 @@ def serialize_args_spec(spec):
return json.dumps(spec, default=fallback_serializer)
# accepted geometries for a vector will be displayed in this order
# accepted geometry_types for a vector will be displayed in this order
GEOMETRY_ORDER = [
'POINT',
'MULTIPOINT',
@ -1721,18 +1721,18 @@ def format_required_string(required):
return gettext('conditionally required')
def format_geometries_string(geometries):
"""Represent a set of allowed vector geometries as user-friendly text.
def format_geometry_types_string(geometry_types):
"""Represent a set of allowed vector geometry types as user-friendly text.
Args:
geometries (set(str)): set of geometry names
geometry_types (set(str)): set of geometry names
Returns:
string
"""
# sort the geometries so they always display in a consistent order
# sort the geometry types so they always display in a consistent order
sorted_geoms = sorted(
geometries,
geometry_types,
key=lambda g: GEOMETRY_ORDER.index(g))
return '/'.join(gettext(geom).lower() for geom in sorted_geoms)
@ -1886,7 +1886,7 @@ def describe_arg_from_spec(name, spec):
The first line has the arg name, type, required state, description,
and units if applicable. Depending on the type, there may be additional
lines that are indented, that describe details of the arg such as
vector fields and geometries, option_string options, etc.
vector fields and geometry types, option_string options, etc.
"""
type_string = format_type_string(spec.__class__)
in_parentheses = [type_string]
@ -1905,7 +1905,7 @@ def describe_arg_from_spec(name, spec):
in_parentheses.append(f'{translated_units}: **{units_string}**')
if spec.__class__ is VectorInput:
in_parentheses.append(format_geometries_string(spec.geometries))
in_parentheses.append(format_geometry_types_string(spec.geometry_types))
# Represent the required state as a string, defaulting to required
# It doesn't make sense to include this for boolean checkboxes

View File

@ -9,7 +9,7 @@ MODEL_SPEC = spec.ModelSpec(inputs=[
spec.FileInput(id='bar'),
spec.DirectoryInput(id='data_dir', contents={}),
spec.SingleBandRasterInput(id='raster', band=spec.Input()),
spec.VectorInput(id='vector', fields={}, geometries={}),
spec.VectorInput(id='vector', fields={}, geometry_types={}),
spec.CSVInput(id='simple_table'),
spec.CSVInput(
id='spatial_table',
@ -18,7 +18,7 @@ MODEL_SPEC = spec.ModelSpec(inputs=[
spec.RasterOrVectorInput(
id='path',
fields={},
geometries={'POINT', 'POLYGON'},
geometry_types={'POINT', 'POLYGON'},
band=spec.NumberInput()
)
]

View File

@ -2,7 +2,7 @@ from natcap.invest import spec
MODEL_SPEC = spec.ModelSpec(inputs=[
spec.VectorInput(
id='vector', fields={}, geometries={})],
id='vector', fields={}, geometry_types={})],
outputs={},
model_id='vector_model',
model_title='',

View File

@ -204,7 +204,7 @@ class ValidateModelSpecs(unittest.TestCase):
# vector type should have:
# - a fields property that maps each field header to a nested
# type dictionary describing the data in that field
# - a geometries property: the set of valid geometry types
# - a geometry_types property: the set of valid geometry types
self.assertTrue(hasattr(output_spec, 'fields'))
for field in output_spec.fields:
self.validate_output(
@ -212,8 +212,8 @@ class ValidateModelSpecs(unittest.TestCase):
f'{key}.fields.{field}',
parent_type=t)
self.assertTrue(hasattr(output_spec, 'geometries'))
self.assertIsInstance(output_spec.geometries, set)
self.assertTrue(hasattr(output_spec, 'geometry_types'))
self.assertIsInstance(output_spec.geometry_types, set)
elif t is spec.CSVOutput:
# csv type may have a columns property.
@ -374,7 +374,7 @@ class ValidateModelSpecs(unittest.TestCase):
# vector type should have:
# - a fields property that maps each field header to a nested
# type dictionary describing the data in that field
# - a geometries property: the set of valid geometry types
# - a geometry_types property: the set of valid geometry types
self.assertTrue(hasattr(arg, 'fields'))
for field in arg.fields:
self.validate_args(
@ -382,11 +382,11 @@ class ValidateModelSpecs(unittest.TestCase):
f'{name}.fields.{field}',
parent_type=t)
self.assertTrue(hasattr(arg, 'geometries'))
self.assertIsInstance(arg.geometries, set)
self.assertTrue(hasattr(arg, 'geometry_types'))
self.assertIsInstance(arg.geometry_types, set)
attrs.remove('fields')
attrs.remove('geometries')
attrs.remove('geometry_types')
# may optionally have a 'projected' attribute that says
# whether the vector must be linearly projected

View File

@ -171,7 +171,7 @@ class TestDescribeArgFromSpec(unittest.TestCase):
def test_vector_spec(self):
vector_spec = spec.VectorInput(
fields={},
geometries={"LINESTRING"},
geometry_types={"LINESTRING"},
about="Description",
name="Bar"
)
@ -193,7 +193,7 @@ class TestDescribeArgFromSpec(unittest.TestCase):
about="Average annual precipitation over the area"
)
],
geometries={"POLYGON", "MULTIPOLYGON"},
geometry_types={"POLYGON", "MULTIPOLYGON"},
about="Description",
name="Bar"
)
@ -251,7 +251,7 @@ class TestDescribeArgFromSpec(unittest.TestCase):
about="Description",
name="Bar",
band=spec.IntegerInput(),
geometries={"POLYGON"},
geometry_types={"POLYGON"},
fields={}
)
out = spec.describe_arg_from_spec(multi_spec.name, multi_spec)
@ -328,7 +328,7 @@ class TestMetadataFromSpec(unittest.TestCase):
id="admin_boundaries.gpkg",
about=("A copy of the user's administrative boundaries "
"vector with a single layer."),
geometries=spec.POLYGONS,
geometry_types=spec.POLYGONS,
fields=[
spec.NumberInput(
id="SUP_DEMadm_cap",

View File

@ -69,10 +69,10 @@ class UsageLoggingTests(unittest.TestCase):
model_id='', model_title='', userguide=None, aliases=None,
inputs=[
spec.SingleBandRasterInput(id='raster', band=spec.Input()),
spec.VectorInput(id='vector', geometries={}, fields={}),
spec.VectorInput(id='vector', geometry_types={}, fields={}),
spec.StringInput(id='not_a_gis_input'),
spec.SingleBandRasterInput(id='blank_raster_path', band=spec.Input()),
spec.VectorInput(id='blank_vector_path', geometries={}, fields={})
spec.VectorInput(id='blank_vector_path', geometry_types={}, fields={})
],
outputs={},
input_field_order=[],

View File

@ -615,7 +615,7 @@ class VectorValidation(unittest.TestCase):
filepath = os.path.join(self.workspace_dir, 'file.txt')
error_msg = VectorInput(
geometries={'POINT'}, fields={}).validate(filepath)
geometry_types={'POINT'}, fields={}).validate(filepath)
self.assertEqual(error_msg, validation.MESSAGES['FILE_NOT_FOUND'])
def test_invalid_vector(self):
@ -627,7 +627,7 @@ class VectorValidation(unittest.TestCase):
bad_vector.write('not a vector')
error_msg = VectorInput(
geometries={'POINT'}, fields={}).validate(filepath)
geometry_types={'POINT'}, fields={}).validate(filepath)
self.assertEqual(error_msg, validation.MESSAGES['NOT_GDAL_VECTOR'])
def test_missing_fieldnames(self):
@ -655,7 +655,7 @@ class VectorValidation(unittest.TestCase):
vector = None
error_msg = VectorInput(
geometries={'POINT'},
geometry_types={'POINT'},
fields=[
Input(id='col_a'),
Input(id='col_b'),
@ -681,14 +681,14 @@ class VectorValidation(unittest.TestCase):
vector = None
error_msg = VectorInput(
fields={}, geometries={'POINT'}, projected=True, projection_units=spec.u.foot
fields={}, geometry_types={'POINT'}, projected=True, projection_units=spec.u.foot
).validate(filepath)
expected_msg = validation.MESSAGES['WRONG_PROJECTION_UNIT'].format(
unit_a='foot', unit_b='metre')
self.assertEqual(error_msg, expected_msg)
self.assertIsNone(VectorInput(
fields={}, geometries={'POINT'}, projected=True, projection_units=spec.u.meter
fields={}, geometry_types={'POINT'}, projected=True, projection_units=spec.u.meter
).validate(filepath))
def test_wrong_geom_type(self):
@ -703,9 +703,9 @@ class VectorValidation(unittest.TestCase):
layer = None
vector = None
self.assertIsNone(VectorInput(
geometries={'POLYGON', 'POINT'}, fields=None).validate(filepath))
geometry_types={'POLYGON', 'POINT'}, fields=None).validate(filepath))
self.assertEqual(
VectorInput(fields=None, geometries={'MULTIPOINT'}).validate(filepath),
VectorInput(fields=None, geometry_types={'MULTIPOINT'}).validate(filepath),
validation.MESSAGES['WRONG_GEOM_TYPE'].format(allowed={'MULTIPOINT'}))
@ -1551,7 +1551,7 @@ class TestGetValidatedDataframe(unittest.TestCase):
IntegerInput(id='a'),
IntegerInput(id='b')
],
geometries=['POINT']
geometry_types=['POINT']
)
])
@ -1586,7 +1586,7 @@ class TestGetValidatedDataframe(unittest.TestCase):
id='col2',
band=NumberInput(),
fields={},
geometries=['POLYGON']
geometry_types=['POLYGON']
)
])
with self.assertRaises(ValueError) as cm:
@ -1777,7 +1777,7 @@ class TestValidationFromSpec(unittest.TestCase):
),
VectorInput(
id="vector",
geometries=spec.POINTS,
geometry_types=spec.POINTS,
fields=[
RatioInput(id="field_a"),
RatioInput(id="field_b", required="some_number == 2")
@ -2050,7 +2050,7 @@ class TestValidationFromSpec(unittest.TestCase):
VectorInput(
id='vector_a',
fields={},
geometries={'POINT'}
geometry_types={'POINT'}
)
],
args_with_spatial_overlap={
@ -2166,7 +2166,7 @@ class TestValidationFromSpec(unittest.TestCase):
id='vector_a',
required=False,
fields=[],
geometries={'POINT'}
geometry_types={'POINT'}
)
],
args_with_spatial_overlap={