rename InputSpec to Input

This commit is contained in:
Emily Soth 2025-05-02 12:09:43 -07:00
parent 96229ab99e
commit 18d8d10992
16 changed files with 497 additions and 503 deletions

View File

@ -3515,7 +3515,7 @@ def validate(args, limit_to=None):
'slr_field' in sufficient_keys):
fieldnames = validation.load_fields_from_vector(
args['slr_vector_path'])
error_msg = spec_utils.OptionStringInputSpec(
error_msg = spec_utils.OptionStringInput(
options=fieldnames).validate(args['slr_field'])
if error_msg:
validation_warnings.append((['slr_field'], error_msg))

View File

@ -200,10 +200,10 @@ def build_datastack_archive(args, model_id, datastack_path):
files_found = {}
LOGGER.debug(f'Keys: {sorted(args.keys())}')
spatial_types = {spec_utils.SingleBandRasterInputSpec, spec_utils.VectorInputSpec,
spec_utils.RasterOrVectorInputSpec}
spatial_types = {spec_utils.SingleBandRasterInput, spec_utils.VectorInput,
spec_utils.RasterOrVectorInput}
file_based_types = spatial_types.union({
spec_utils.CSVInputSpec, spec_utils.FileInputSpec, spec_utils.DirectoryInputSpec})
spec_utils.CSVInput, spec_utils.FileInput, spec_utils.DirectoryInput})
rewritten_args = {}
for key in args:
# Allow the model to override specific arguments in datastack archive
@ -260,7 +260,7 @@ def build_datastack_archive(args, model_id, datastack_path):
rewritten_args[key] = files_found[source_path]
continue
if input_spec.__class__ is spec_utils.CSVInputSpec:
if input_spec.__class__ is spec_utils.CSVInput:
# check the CSV for columns that may be spatial.
# But also, the columns specification might not be listed, so don't
# require that 'columns' exists in the MODEL_SPEC.
@ -342,7 +342,7 @@ def build_datastack_archive(args, model_id, datastack_path):
target_arg_value = target_csv_path
files_found[source_path] = target_arg_value
elif input_spec.__class__ is spec_utils.FileInputSpec:
elif input_spec.__class__ is spec_utils.FileInput:
target_filepath = os.path.join(
data_dir, f'{key}_file')
shutil.copyfile(source_path, target_filepath)
@ -351,7 +351,7 @@ def build_datastack_archive(args, model_id, datastack_path):
target_arg_value = target_filepath
files_found[source_path] = target_arg_value
elif input_spec.__class__ is spec_utils.DirectoryInputSpec:
elif input_spec.__class__ is spec_utils.DirectoryInput:
# copy the whole folder
target_directory = os.path.join(data_dir, f'{key}_directory')
os.makedirs(target_directory)

View File

@ -219,7 +219,7 @@ class Contents(IterableWithDotAccess):
pass
@dataclasses.dataclass
class InputSpec:
class Input:
id: str = ''
name: str = ''
about: str = ''
@ -227,13 +227,13 @@ class InputSpec:
allowed: Union[bool, str] = True
@dataclasses.dataclass
class OutputSpec:
class Output:
id: str = ''
about: str = ''
created_if: Union[bool, str] = True
@dataclasses.dataclass
class FileInputSpec(InputSpec):
class FileInput(Input):
permissions: str = 'r'
type: ClassVar[str] = 'file'
@ -268,8 +268,8 @@ class FileInputSpec(InputSpec):
).astype(pandas.StringDtype())
@dataclasses.dataclass
class SingleBandRasterInputSpec(FileInputSpec):
band: Union[InputSpec, None] = None
class SingleBandRasterInput(FileInput):
band: Union[Input, None] = None
projected: Union[bool, None] = None
projection_units: Union[pint.Unit, None] = None
type: ClassVar[str] = 'raster'
@ -290,7 +290,7 @@ class SingleBandRasterInputSpec(FileInputSpec):
A string error message if an error was found. ``None`` otherwise.
"""
file_warning = FileInputSpec.validate(self, filepath)
file_warning = FileInput.validate(self, filepath)
if file_warning:
return file_warning
@ -311,7 +311,7 @@ class SingleBandRasterInputSpec(FileInputSpec):
return None
@dataclasses.dataclass
class VectorInputSpec(FileInputSpec):
class VectorInput(FileInput):
geometries: set = dataclasses.field(default_factory=dict)
fields: Union[Fields, None] = None
projected: Union[bool, None] = None
@ -396,8 +396,8 @@ class VectorInputSpec(FileInputSpec):
@dataclasses.dataclass
class RasterOrVectorInputSpec(SingleBandRasterInputSpec, VectorInputSpec):
band: Union[InputSpec, None] = None
class RasterOrVectorInput(SingleBandRasterInput, VectorInput):
band: Union[Input, None] = None
geometries: set = dataclasses.field(default_factory=dict)
fields: Union[Fields, None] = None
projected: Union[bool, None] = None
@ -421,12 +421,12 @@ class RasterOrVectorInputSpec(SingleBandRasterInputSpec, VectorInputSpec):
except ValueError as err:
return str(err)
if gis_type == pygeoprocessing.RASTER_TYPE:
return SingleBandRasterInputSpec.validate(self, filepath)
return SingleBandRasterInput.validate(self, filepath)
else:
return VectorInputSpec.validate(self, filepath)
return VectorInput.validate(self, filepath)
@dataclasses.dataclass
class CSVInputSpec(FileInputSpec):
class CSVInput(FileInput):
columns: Union[Columns, None] = None
rows: Union[Rows, None] = None
index_col: Union[str, None] = None
@ -511,9 +511,9 @@ class CSVInputSpec(FileInputSpec):
f'Value(s) in the "{col}" column could not be interpreted '
f'as {type(col_spec).__name__}s. Original error: {err}')
if (isinstance(col_spec, SingleBandRasterInputSpec) or
isinstance(col_spec, VectorInputSpec) or
isinstance(col_spec, RasterOrVectorInputSpec)):
if (isinstance(col_spec, SingleBandRasterInput) or
isinstance(col_spec, VectorInput) or
isinstance(col_spec, RasterOrVectorInput)):
# recursively validate the files within the column
def check_value(value):
if pandas.isna(value):
@ -547,7 +547,7 @@ class CSVInputSpec(FileInputSpec):
@dataclasses.dataclass
class DirectoryInputSpec(InputSpec):
class DirectoryInput(Input):
contents: Union[Contents, None] = None
permissions: str = ''
must_exist: bool = True
@ -618,7 +618,7 @@ class DirectoryInputSpec(InputSpec):
@dataclasses.dataclass
class NumberInputSpec(InputSpec):
class NumberInput(Input):
units: Union[pint.Unit, None] = None
expression: Union[str, None] = None
type: ClassVar[str] = 'number'
@ -661,7 +661,7 @@ class NumberInputSpec(InputSpec):
return col.astype(float)
@dataclasses.dataclass
class IntegerInputSpec(InputSpec):
class IntegerInput(Input):
type: ClassVar[str] = 'integer'
def validate(self, value):
@ -688,7 +688,7 @@ class IntegerInputSpec(InputSpec):
@dataclasses.dataclass
class RatioInputSpec(InputSpec):
class RatioInput(Input):
type: ClassVar[str] = 'ratio'
def validate(self, value):
@ -716,7 +716,7 @@ class RatioInputSpec(InputSpec):
return col.astype(float)
@dataclasses.dataclass
class PercentInputSpec(InputSpec):
class PercentInput(Input):
type: ClassVar[str] = 'percent'
def validate(self, value):
@ -743,7 +743,7 @@ class PercentInputSpec(InputSpec):
return col.astype(float)
@dataclasses.dataclass
class BooleanInputSpec(InputSpec):
class BooleanInput(Input):
type: ClassVar[str] = 'boolean'
def validate(self, value):
@ -766,7 +766,7 @@ class BooleanInputSpec(InputSpec):
return col.astype('boolean')
@dataclasses.dataclass
class StringInputSpec(InputSpec):
class StringInput(Input):
regexp: Union[str, None] = None
type: ClassVar[str] = 'string'
@ -793,7 +793,7 @@ class StringInputSpec(InputSpec):
).astype(pandas.StringDtype())
@dataclasses.dataclass
class OptionStringInputSpec(InputSpec):
class OptionStringInput(Input):
options: Union[list, None] = None
type: ClassVar[str] = 'option_string'
@ -822,62 +822,62 @@ class OptionStringInputSpec(InputSpec):
).astype(pandas.StringDtype())
@dataclasses.dataclass
class OtherInputSpec(InputSpec):
class OtherInput(Input):
def validate(self, value):
pass
@dataclasses.dataclass
class SingleBandRasterOutputSpec(OutputSpec):
band: Union[InputSpec, None] = None
class SingleBandRasterOutput(Output):
band: Union[Input, None] = None
projected: Union[bool, None] = None
projection_units: Union[pint.Unit, None] = None
@dataclasses.dataclass
class VectorOutputSpec(OutputSpec):
class VectorOutput(Output):
geometries: set = dataclasses.field(default_factory=dict)
fields: Union[Fields, None] = None
projected: Union[bool, None] = None
projection_units: Union[pint.Unit, None] = None
@dataclasses.dataclass
class CSVOutputSpec(OutputSpec):
class CSVOutput(Output):
columns: Union[Columns, None] = None
rows: Union[Rows, None] = None
index_col: Union[str, None] = None
@dataclasses.dataclass
class DirectoryOutputSpec(OutputSpec):
class DirectoryOutput(Output):
contents: Union[Contents, None] = None
permissions: str = ''
must_exist: bool = True
@dataclasses.dataclass
class FileOutputSpec(OutputSpec):
class FileOutput(Output):
pass
@dataclasses.dataclass
class NumberOutputSpec(OutputSpec):
class NumberOutput(Output):
units: Union[pint.Unit, None] = None
expression: Union[str, None] = None
@dataclasses.dataclass
class IntegerOutputSpec(OutputSpec):
class IntegerOutput(Output):
pass
@dataclasses.dataclass
class RatioOutputSpec(OutputSpec):
class RatioOutput(Output):
pass
@dataclasses.dataclass
class PercentOutputSpec(OutputSpec):
class PercentOutput(Output):
pass
@dataclasses.dataclass
class StringOutputSpec(OutputSpec):
class StringOutput(Output):
regexp: Union[str, None] = None
@dataclasses.dataclass
class OptionStringOutputSpec(OutputSpec):
class OptionStringOutput(Output):
options: Union[list, None] = None
@dataclasses.dataclass
@ -934,42 +934,42 @@ def build_input_spec(argkey, arg):
t = arg['type']
if t == 'option_string':
return OptionStringInputSpec(
return OptionStringInput(
**base_attrs,
options=arg['options'])
elif t == 'freestyle_string':
return StringInputSpec(
return StringInput(
**base_attrs,
regexp=arg.get('regexp', None))
elif t == 'number':
return NumberInputSpec(
return NumberInput(
**base_attrs,
units=arg['units'],
expression=arg.get('expression', None))
elif t == 'integer':
return IntegerInputSpec(**base_attrs)
return IntegerInput(**base_attrs)
elif t == 'ratio':
return RatioInputSpec(**base_attrs)
return RatioInput(**base_attrs)
elif t == 'percent':
return PercentInputSpec(**base_attrs)
return PercentInput(**base_attrs)
elif t == 'boolean':
return BooleanInputSpec(**base_attrs)
return BooleanInput(**base_attrs)
elif t == 'raster':
return SingleBandRasterInputSpec(
return SingleBandRasterInput(
**base_attrs,
band=build_input_spec('1', arg['bands'][1]),
projected=arg.get('projected', None),
projection_units=arg.get('projection_units', None))
elif t == 'vector':
return VectorInputSpec(
return VectorInput(
**base_attrs,
geometries=arg['geometries'],
fields=Fields(
@ -990,14 +990,14 @@ def build_input_spec(argkey, arg):
build_input_spec(row_name, row_spec)
for row_name, row_spec in arg['rows'].items()])
return CSVInputSpec(
return CSVInput(
**base_attrs,
columns=columns,
rows=rows,
index_col=arg.get('index_col', None))
elif t == 'directory':
return DirectoryInputSpec(
return DirectoryInput(
contents=Contents(*[
build_input_spec(k, v) for k, v in arg['contents'].items()]),
permissions=arg.get('permissions', 'rx'),
@ -1005,10 +1005,10 @@ def build_input_spec(argkey, arg):
**base_attrs)
elif t == 'file':
return FileInputSpec(**base_attrs)
return FileInput(**base_attrs)
elif t == {'raster', 'vector'}:
return RasterOrVectorInputSpec(
return RasterOrVectorInput(
**base_attrs,
geometries=arg['geometries'],
fields=Fields(*[
@ -1047,29 +1047,29 @@ def build_output_spec(key, spec):
'no "type" property')
if t == 'number':
return NumberOutputSpec(
return NumberOutput(
**base_attrs,
units=spec['units'],
expression=None)
elif t == 'integer':
return IntegerOutputSpec(**base_attrs)
return IntegerOutput(**base_attrs)
elif t == 'ratio':
return RatioOutputSpec(**base_attrs)
return RatioOutput(**base_attrs)
elif t == 'percent':
return PercentOutputSpec(**base_attrs)
return PercentOutput(**base_attrs)
elif t == 'raster':
return SingleBandRasterOutputSpec(
return SingleBandRasterOutput(
**base_attrs,
band=build_output_spec(1, spec['bands'][1]),
projected=None,
projection_units=None)
elif t == 'vector':
return VectorOutputSpec(
return VectorOutput(
**base_attrs,
geometries=spec['geometries'],
fields=Fields(*[
@ -1078,7 +1078,7 @@ def build_output_spec(key, spec):
projection_units=None)
elif t == 'csv':
return CSVOutputSpec(
return CSVOutput(
**base_attrs,
columns=Columns(*[
build_output_spec(key, col_spec) for key, col_spec in spec['columns'].items()]),
@ -1086,7 +1086,7 @@ def build_output_spec(key, spec):
index_col=spec.get('index_col', None))
elif t == 'directory':
return DirectoryOutputSpec(
return DirectoryOutput(
contents=Contents(*[
build_output_spec(k, v) for k, v in spec['contents'].items()]),
permissions=None,
@ -1094,17 +1094,17 @@ def build_output_spec(key, spec):
**base_attrs)
elif t == 'freestyle_string':
return StringOutputSpec(
return StringOutput(
**base_attrs,
regexp=spec.get('regexp', None))
elif t == 'option_string':
return OptionStringOutputSpec(
return OptionStringOutput(
**base_attrs,
options=spec['options'])
elif t == 'file':
return FileOutputSpec(**base_attrs)
return FileOutput(**base_attrs)
else:
raise ValueError()
@ -1551,39 +1551,39 @@ def format_type_string(arg_type):
# some types need a more user-friendly name
# all types are listed here so that they can be marked up for translation
type_names = {
BooleanInputSpec: gettext('true/false'),
CSVInputSpec: gettext('CSV'),
DirectoryInputSpec: gettext('directory'),
FileInputSpec: gettext('file'),
StringInputSpec: gettext('text'),
IntegerInputSpec: gettext('integer'),
NumberInputSpec: gettext('number'),
OptionStringInputSpec: gettext('option'),
PercentInputSpec: gettext('percent'),
SingleBandRasterInputSpec: gettext('raster'),
RatioInputSpec: gettext('ratio'),
VectorInputSpec: gettext('vector'),
RasterOrVectorInputSpec: gettext('raster or vector')
BooleanInput: gettext('true/false'),
CSVInput: gettext('CSV'),
DirectoryInput: gettext('directory'),
FileInput: gettext('file'),
StringInput: gettext('text'),
IntegerInput: gettext('integer'),
NumberInput: gettext('number'),
OptionStringInput: gettext('option'),
PercentInput: gettext('percent'),
SingleBandRasterInput: gettext('raster'),
RatioInput: gettext('ratio'),
VectorInput: gettext('vector'),
RasterOrVectorInput: gettext('raster or vector')
}
type_sections = { # names of section headers to link to in the RST
BooleanInputSpec: 'truefalse',
CSVInputSpec: 'csv',
DirectoryInputSpec: 'directory',
FileInputSpec: 'file',
StringInputSpec: 'text',
IntegerInputSpec: 'integer',
NumberInputSpec: 'number',
OptionStringInputSpec: 'option',
PercentInputSpec: 'percent',
SingleBandRasterInputSpec: 'raster',
RatioInputSpec: 'ratio',
VectorInputSpec: 'vector',
RasterOrVectorInputSpec: 'raster'
BooleanInput: 'truefalse',
CSVInput: 'csv',
DirectoryInput: 'directory',
FileInput: 'file',
StringInput: 'text',
IntegerInput: 'integer',
NumberInput: 'number',
OptionStringInput: 'option',
PercentInput: 'percent',
SingleBandRasterInput: 'raster',
RatioInput: 'ratio',
VectorInput: 'vector',
RasterOrVectorInput: 'raster'
}
if arg_type is RasterOrVectorInputSpec:
if arg_type is RasterOrVectorInput:
return (
f'`{type_names[SingleBandRasterInputSpec]} <{INPUT_TYPES_HTML_FILE}#{type_sections[SingleBandRasterInputSpec]}>`__ or '
f'`{type_names[VectorInputSpec]} <{INPUT_TYPES_HTML_FILE}#{type_sections[VectorInputSpec]}>`__')
f'`{type_names[SingleBandRasterInput]} <{INPUT_TYPES_HTML_FILE}#{type_sections[SingleBandRasterInput]}>`__ or '
f'`{type_names[VectorInput]} <{INPUT_TYPES_HTML_FILE}#{type_sections[VectorInput]}>`__')
return f'`{type_names[arg_type]} <{INPUT_TYPES_HTML_FILE}#{type_sections[arg_type]}>`__'
@ -1615,9 +1615,9 @@ def describe_arg_from_spec(name, spec):
# For numbers and rasters that have units, display the units
units = None
if spec.__class__ is NumberInputSpec:
if spec.__class__ is NumberInput:
units = spec.units
elif spec.__class__ is SingleBandRasterInputSpec and spec.band.__class__ is NumberInputSpec:
elif spec.__class__ is SingleBandRasterInput and spec.band.__class__ is NumberInput:
units = spec.band.units
if units:
units_string = format_unit(units)
@ -1626,12 +1626,12 @@ def describe_arg_from_spec(name, spec):
translated_units = gettext("units")
in_parentheses.append(f'{translated_units}: **{units_string}**')
if spec.__class__ is VectorInputSpec:
if spec.__class__ is VectorInput:
in_parentheses.append(format_geometries_string(spec.geometries))
# Represent the required state as a string, defaulting to required
# It doesn't make sense to include this for boolean checkboxes
if spec.__class__ is not BooleanInputSpec:
if spec.__class__ is not BooleanInput:
required_string = format_required_string(spec.required)
in_parentheses.append(f'*{required_string}*')
@ -1646,7 +1646,7 @@ def describe_arg_from_spec(name, spec):
# Add details for the types that have them
indented_block = []
if spec.__class__ is OptionStringInputSpec:
if spec.__class__ is OptionStringInput:
# may be either a dict or set. if it's empty, the options are
# dynamically generated. don't try to document them.
if spec.options:
@ -1657,7 +1657,7 @@ def describe_arg_from_spec(name, spec):
formatted_options = format_options_string_from_list(spec.options)
indented_block.append(gettext('Options:') + f' {formatted_options}')
elif spec.__class__ is CSVInputSpec:
elif spec.__class__ is CSVInput:
if not spec.columns and not spec.rows:
first_line += gettext(
' Please see the sample data table for details on the format.')
@ -1776,7 +1776,7 @@ def generate_metadata(model_module, args_dict):
def _walk_spec(output_spec, workspace):
for spec_data in output_spec:
if spec_data.__class__ is DirectoryOutputSpec:
if spec_data.__class__ is DirectoryOutput:
if 'taskgraph.db' in [s.id for s in spec_data.contents]:
continue
_walk_spec(

View File

@ -121,10 +121,10 @@ def _calculate_args_bounding_box(args, model_spec):
# blank.
spatial_info = None
if (isinstance(model_spec.inputs.get(key),
spec_utils.SingleBandRasterInputSpec) and value.strip() != ''):
spec_utils.SingleBandRasterInput) and value.strip() != ''):
spatial_info = pygeoprocessing.get_raster_info(value)
elif (isinstance(model_spec.inputs.get(key),
spec_utils.VectorInputSpec) and value.strip() != ''):
spec_utils.VectorInput) and value.strip() != ''):
spatial_info = pygeoprocessing.get_vector_info(value)
if spatial_info:

View File

@ -408,11 +408,11 @@ class DatastackArchiveTests(unittest.TestCase):
self.assertTrue(
filecmp.cmp(archive_params[key], params[key], shallow=False))
spatial_csv_dict = spec_utils.CSVInputSpec(
spatial_csv_dict = spec_utils.CSVInput(
index_col='id',
columns=spec_utils.Columns(
spec_utils.IntegerInputSpec(id='id'),
spec_utils.FileInputSpec(id='path'))
spec_utils.IntegerInput(id='id'),
spec_utils.FileInput(id='path'))
).get_validated_dataframe(
archive_params['spatial_table']
).to_dict(orient='index')

View File

@ -2,25 +2,25 @@ from types import SimpleNamespace
from natcap.invest import spec_utils
MODEL_SPEC = SimpleNamespace(inputs=spec_utils.ModelInputs(
spec_utils.StringInputSpec(id='blank'),
spec_utils.IntegerInputSpec(id='a'),
spec_utils.StringInputSpec(id='b'),
spec_utils.StringInputSpec(id='c'),
spec_utils.FileInputSpec(id='foo'),
spec_utils.FileInputSpec(id='bar'),
spec_utils.DirectoryInputSpec(id='data_dir', contents={}),
spec_utils.SingleBandRasterInputSpec(id='raster', band=spec_utils.InputSpec()),
spec_utils.VectorInputSpec(id='vector', fields={}, geometries={}),
spec_utils.CSVInputSpec(id='simple_table'),
spec_utils.CSVInputSpec(
spec_utils.StringInput(id='blank'),
spec_utils.IntegerInput(id='a'),
spec_utils.StringInput(id='b'),
spec_utils.StringInput(id='c'),
spec_utils.FileInput(id='foo'),
spec_utils.FileInput(id='bar'),
spec_utils.DirectoryInput(id='data_dir', contents={}),
spec_utils.SingleBandRasterInput(id='raster', band=spec_utils.Input()),
spec_utils.VectorInput(id='vector', fields={}, geometries={}),
spec_utils.CSVInput(id='simple_table'),
spec_utils.CSVInput(
id='spatial_table',
columns=spec_utils.Columns(
spec_utils.IntegerInputSpec(id='ID'),
spec_utils.RasterOrVectorInputSpec(
spec_utils.IntegerInput(id='ID'),
spec_utils.RasterOrVectorInput(
id='path',
fields={},
geometries={'POINT', 'POLYGON'},
band=spec_utils.NumberInputSpec()
band=spec_utils.NumberInput()
)
)
)

View File

@ -2,6 +2,6 @@ from types import SimpleNamespace
from natcap.invest import spec_utils
MODEL_SPEC = SimpleNamespace(inputs=spec_utils.ModelInputs(
spec_utils.FileInputSpec(id='foo'),
spec_utils.FileInputSpec(id='bar'),
spec_utils.FileInput(id='foo'),
spec_utils.FileInput(id='bar'),
))

View File

@ -2,8 +2,8 @@ from types import SimpleNamespace
from natcap.invest import spec_utils
MODEL_SPEC = SimpleNamespace(inputs=spec_utils.ModelInputs(
spec_utils.FileInputSpec(id='some_file'),
spec_utils.DirectoryInputSpec(
spec_utils.FileInput(id='some_file'),
spec_utils.DirectoryInput(
id='data_dir',
contents=spec_utils.Contents())
))

View File

@ -2,5 +2,5 @@ from types import SimpleNamespace
from natcap.invest import spec_utils
MODEL_SPEC = SimpleNamespace(inputs=spec_utils.ModelInputs(
spec_utils.SingleBandRasterInputSpec(id='raster', band=spec_utils.InputSpec())
spec_utils.SingleBandRasterInput(id='raster', band=spec_utils.Input())
))

View File

@ -2,11 +2,11 @@ from types import SimpleNamespace
from natcap.invest import spec_utils
MODEL_SPEC = SimpleNamespace(inputs=spec_utils.ModelInputs(
spec_utils.IntegerInputSpec(id='a'),
spec_utils.StringInputSpec(id='b'),
spec_utils.StringInputSpec(id='c'),
spec_utils.StringInputSpec(id='d'),
spec_utils.DirectoryInputSpec(
spec_utils.IntegerInput(id='a'),
spec_utils.StringInput(id='b'),
spec_utils.StringInput(id='c'),
spec_utils.StringInput(id='d'),
spec_utils.DirectoryInput(
id='workspace_dir',
contents=spec_utils.Contents()
)

View File

@ -2,6 +2,6 @@ from types import SimpleNamespace
from natcap.invest import spec_utils
MODEL_SPEC = SimpleNamespace(inputs=spec_utils.ModelInputs(
spec_utils.StringInputSpec(id='foo'),
spec_utils.StringInputSpec(id='bar')
spec_utils.StringInput(id='foo'),
spec_utils.StringInput(id='bar')
))

View File

@ -2,6 +2,6 @@ from types import SimpleNamespace
from natcap.invest import spec_utils
MODEL_SPEC = SimpleNamespace(inputs=spec_utils.ModelInputs(
spec_utils.VectorInputSpec(
spec_utils.VectorInput(
id='vector', fields={}, geometries={})
))

View File

@ -16,100 +16,100 @@ PLUGIN_NAME = 'foo-model'
gdal.UseExceptions()
valid_nested_input_types = {
None: { # if no parent type (arg is top-level), then all types are valid
spec_utils.IntegerInputSpec,
spec_utils.NumberInputSpec,
spec_utils.RatioInputSpec,
spec_utils.PercentInputSpec,
spec_utils.StringInputSpec,
spec_utils.OptionStringInputSpec,
spec_utils.BooleanInputSpec,
spec_utils.SingleBandRasterInputSpec,
spec_utils.VectorInputSpec,
spec_utils.RasterOrVectorInputSpec,
spec_utils.CSVInputSpec,
spec_utils.DirectoryInputSpec,
spec_utils.FileInputSpec
spec_utils.IntegerInput,
spec_utils.NumberInput,
spec_utils.RatioInput,
spec_utils.PercentInput,
spec_utils.StringInput,
spec_utils.OptionStringInput,
spec_utils.BooleanInput,
spec_utils.SingleBandRasterInput,
spec_utils.VectorInput,
spec_utils.RasterOrVectorInput,
spec_utils.CSVInput,
spec_utils.DirectoryInput,
spec_utils.FileInput
},
spec_utils.SingleBandRasterInputSpec: {
spec_utils.IntegerInputSpec,
spec_utils.NumberInputSpec,
spec_utils.RatioInputSpec,
spec_utils.PercentInputSpec
spec_utils.SingleBandRasterInput: {
spec_utils.IntegerInput,
spec_utils.NumberInput,
spec_utils.RatioInput,
spec_utils.PercentInput
},
spec_utils.VectorInputSpec: {
spec_utils.IntegerInputSpec,
spec_utils.NumberInputSpec,
spec_utils.RatioInputSpec,
spec_utils.PercentInputSpec,
spec_utils.StringInputSpec,
spec_utils.OptionStringInputSpec
spec_utils.VectorInput: {
spec_utils.IntegerInput,
spec_utils.NumberInput,
spec_utils.RatioInput,
spec_utils.PercentInput,
spec_utils.StringInput,
spec_utils.OptionStringInput
},
spec_utils.CSVInputSpec: {
spec_utils.IntegerInputSpec,
spec_utils.NumberInputSpec,
spec_utils.RatioInputSpec,
spec_utils.PercentInputSpec,
spec_utils.StringInputSpec,
spec_utils.OptionStringInputSpec,
spec_utils.BooleanInputSpec,
spec_utils.SingleBandRasterInputSpec,
spec_utils.VectorInputSpec,
spec_utils.RasterOrVectorInputSpec
spec_utils.CSVInput: {
spec_utils.IntegerInput,
spec_utils.NumberInput,
spec_utils.RatioInput,
spec_utils.PercentInput,
spec_utils.StringInput,
spec_utils.OptionStringInput,
spec_utils.BooleanInput,
spec_utils.SingleBandRasterInput,
spec_utils.VectorInput,
spec_utils.RasterOrVectorInput
},
spec_utils.DirectoryInputSpec: {
spec_utils.CSVInputSpec,
spec_utils.DirectoryInputSpec,
spec_utils.FileInputSpec,
spec_utils.SingleBandRasterInputSpec,
spec_utils.VectorInputSpec,
spec_utils.RasterOrVectorInputSpec
spec_utils.DirectoryInput: {
spec_utils.CSVInput,
spec_utils.DirectoryInput,
spec_utils.FileInput,
spec_utils.SingleBandRasterInput,
spec_utils.VectorInput,
spec_utils.RasterOrVectorInput
}
}
valid_nested_output_types = {
None: { # if no parent type (arg is top-level), then all types are valid
spec_utils.IntegerOutputSpec,
spec_utils.NumberOutputSpec,
spec_utils.RatioOutputSpec,
spec_utils.PercentOutputSpec,
spec_utils.StringOutputSpec,
spec_utils.OptionStringOutputSpec,
spec_utils.SingleBandRasterOutputSpec,
spec_utils.VectorOutputSpec,
spec_utils.CSVOutputSpec,
spec_utils.DirectoryOutputSpec,
spec_utils.FileOutputSpec
spec_utils.IntegerOutput,
spec_utils.NumberOutput,
spec_utils.RatioOutput,
spec_utils.PercentOutput,
spec_utils.StringOutput,
spec_utils.OptionStringOutput,
spec_utils.SingleBandRasterOutput,
spec_utils.VectorOutput,
spec_utils.CSVOutput,
spec_utils.DirectoryOutput,
spec_utils.FileOutput
},
spec_utils.SingleBandRasterOutputSpec: {
spec_utils.IntegerOutputSpec,
spec_utils.NumberOutputSpec,
spec_utils.RatioOutputSpec,
spec_utils.PercentOutputSpec
spec_utils.SingleBandRasterOutput: {
spec_utils.IntegerOutput,
spec_utils.NumberOutput,
spec_utils.RatioOutput,
spec_utils.PercentOutput
},
spec_utils.VectorOutputSpec: {
spec_utils.IntegerOutputSpec,
spec_utils.NumberOutputSpec,
spec_utils.RatioOutputSpec,
spec_utils.PercentOutputSpec,
spec_utils.StringOutputSpec,
spec_utils.OptionStringOutputSpec
spec_utils.VectorOutput: {
spec_utils.IntegerOutput,
spec_utils.NumberOutput,
spec_utils.RatioOutput,
spec_utils.PercentOutput,
spec_utils.StringOutput,
spec_utils.OptionStringOutput
},
spec_utils.CSVOutputSpec: {
spec_utils.IntegerOutputSpec,
spec_utils.NumberOutputSpec,
spec_utils.RatioOutputSpec,
spec_utils.PercentOutputSpec,
spec_utils.StringOutputSpec,
spec_utils.OptionStringOutputSpec,
spec_utils.SingleBandRasterOutputSpec,
spec_utils.VectorOutputSpec
spec_utils.CSVOutput: {
spec_utils.IntegerOutput,
spec_utils.NumberOutput,
spec_utils.RatioOutput,
spec_utils.PercentOutput,
spec_utils.StringOutput,
spec_utils.OptionStringOutput,
spec_utils.SingleBandRasterOutput,
spec_utils.VectorOutput
},
spec_utils.DirectoryOutputSpec: {
spec_utils.CSVOutputSpec,
spec_utils.DirectoryOutputSpec,
spec_utils.FileOutputSpec,
spec_utils.SingleBandRasterOutputSpec,
spec_utils.VectorOutputSpec
spec_utils.DirectoryOutput: {
spec_utils.CSVOutput,
spec_utils.DirectoryOutput,
spec_utils.FileOutput,
spec_utils.SingleBandRasterOutput,
spec_utils.VectorOutput
}
}
@ -191,13 +191,13 @@ class ValidateModelSpecs(unittest.TestCase):
t = type(spec)
self.assertIn(t, valid_nested_output_types[parent_type])
if t is spec_utils.NumberOutputSpec:
if t is spec_utils.NumberOutput:
# number type should have a units property
self.assertTrue(hasattr(spec, 'units'))
# Undefined units should use the custom u.none unit
self.assertIsInstance(spec.units, pint.Unit)
elif t is spec_utils.SingleBandRasterOutputSpec:
elif t is spec_utils.SingleBandRasterOutput:
# raster type should have a bands property that maps each band
# index to a nested type dictionary describing the band's data
self.assertTrue(hasattr(spec, 'band'))
@ -206,7 +206,7 @@ class ValidateModelSpecs(unittest.TestCase):
f'{key}.band',
parent_type=t)
elif t is spec_utils.VectorOutputSpec:
elif t is spec_utils.VectorOutput:
# vector type should have:
# - a fields property that maps each field header to a nested
# type dictionary describing the data in that field
@ -222,7 +222,7 @@ class ValidateModelSpecs(unittest.TestCase):
self.assertTrue(hasattr(spec, 'geometries'))
self.assertIsInstance(spec.geometries, set)
elif t is spec_utils.CSVOutputSpec:
elif t is spec_utils.CSVOutput:
# csv type may have a columns property.
# the columns property maps each expected column header
# name/pattern to a nested type dictionary describing the data
@ -238,7 +238,7 @@ class ValidateModelSpecs(unittest.TestCase):
if spec.index_col:
self.assertIn(spec.index_col, [s.id for s in spec.columns])
elif t is spec_utils.DirectoryOutputSpec:
elif t is spec_utils.DirectoryOutput:
# directory type should have a contents property that maps each
# expected path name/pattern within the directory to a nested
# type dictionary describing the data at that filepath
@ -250,7 +250,7 @@ class ValidateModelSpecs(unittest.TestCase):
f'{key}.contents.{path}',
parent_type=t)
elif t is spec_utils.OptionStringOutputSpec:
elif t is spec_utils.OptionStringOutput:
# option_string type should have an options property that
# describes the valid options
self.assertTrue(hasattr(spec, 'options'))
@ -260,7 +260,7 @@ class ValidateModelSpecs(unittest.TestCase):
isinstance(option, str) or
isinstance(option, int))
elif t is spec_utils.FileOutputSpec:
elif t is spec_utils.FileOutput:
pass
# iterate over the remaining attributes
@ -298,7 +298,7 @@ class ValidateModelSpecs(unittest.TestCase):
t = type(arg)
self.assertIn(t, valid_nested_input_types[parent_type])
if t is spec_utils.OptionStringInputSpec:
if t is spec_utils.OptionStringInput:
# option_string type should have an options property that
# describes the valid options
self.assertTrue(hasattr(arg, 'options'))
@ -330,7 +330,7 @@ class ValidateModelSpecs(unittest.TestCase):
attrs.remove('options')
elif t is spec_utils.StringInputSpec:
elif t is spec_utils.StringInput:
# freestyle_string may optionally have a regexp attribute
# this is a regular expression that the string must match
if arg.regexp:
@ -338,7 +338,7 @@ class ValidateModelSpecs(unittest.TestCase):
re.compile(arg.regexp) # should be regex compilable
attrs.remove('regexp')
elif t is spec_utils.NumberInputSpec:
elif t is spec_utils.NumberInput:
# number type should have a units property
self.assertTrue(hasattr(arg, 'units'))
# Undefined units should use the custom u.none unit
@ -353,7 +353,7 @@ class ValidateModelSpecs(unittest.TestCase):
if arg.expression:
self.assertIsInstance(arg.expression, str)
elif t is spec_utils.SingleBandRasterInputSpec:
elif t is spec_utils.SingleBandRasterInput:
# raster type should have a bands property that maps each band
# index to a nested type dictionary describing the band's data
self.assertTrue(hasattr(arg, 'band'))
@ -377,7 +377,7 @@ class ValidateModelSpecs(unittest.TestCase):
arg.projection_units, pint.Unit)
attrs.remove('projection_units')
elif t is spec_utils.VectorInputSpec:
elif t is spec_utils.VectorInput:
# vector type should have:
# - a fields property that maps each field header to a nested
# type dictionary describing the data in that field
@ -411,7 +411,7 @@ class ValidateModelSpecs(unittest.TestCase):
arg.projection_units, pint.Unit)
attrs.remove('projection_units')
elif t is spec_utils.CSVInputSpec:
elif t is spec_utils.CSVInput:
# csv type should have a rows property, columns property, or
# neither. rows or columns properties map each expected header
# name/pattern to a nested type dictionary describing the data
@ -435,7 +435,7 @@ class ValidateModelSpecs(unittest.TestCase):
if arg.index_col:
self.assertIn(arg.index_col, [s.id for s in arg.columns])
elif t is spec_utils.DirectoryInputSpec:
elif t is spec_utils.DirectoryInput:
# directory type should have a contents property that maps each
# expected path name/pattern within the directory to a nested
# type dictionary describing the data at that filepath
@ -460,7 +460,7 @@ class ValidateModelSpecs(unittest.TestCase):
self.assertIsInstance(arg.must_exist, bool)
attrs.remove('must_exist')
elif t is spec_utils.FileInputSpec:
elif t is spec_utils.FileInput:
# file type may optionally have a 'permissions' attribute
# this is a string listing the permissions e.g. 'rwx'
if arg.permissions:
@ -509,13 +509,7 @@ class ValidateModelSpecs(unittest.TestCase):
for pyname in model_id_to_pyname.values():
model = importlib.import_module(pyname)
try:
_ = spec_utils.serialize_args_spec(model.MODEL_SPEC)
except TypeError as error:
self.fail(
f'Failed to avoid TypeError when serializing '
f'{pyname}.MODEL_SPEC: \n'
f'{error}')
spec_utils.serialize_args_spec(model.MODEL_SPEC)
class SpecUtilsTests(unittest.TestCase):

View File

@ -41,7 +41,7 @@ class TestDescribeArgFromSpec(unittest.TestCase):
"""Test building RST for various invest args specifications."""
def test_number_spec(self):
spec = spec_utils.NumberInputSpec(
spec = spec_utils.NumberInput(
name="Bar",
about="Description",
units=u.meter**3/u.month,
@ -54,7 +54,7 @@ class TestDescribeArgFromSpec(unittest.TestCase):
self.assertEqual(repr(out), repr(expected_rst))
def test_ratio_spec(self):
spec = spec_utils.RatioInputSpec(
spec = spec_utils.RatioInput(
name="Bar",
about="Description"
)
@ -64,7 +64,7 @@ class TestDescribeArgFromSpec(unittest.TestCase):
self.assertEqual(repr(out), repr(expected_rst))
def test_percent_spec(self):
spec = spec_utils.PercentInputSpec(
spec = spec_utils.PercentInput(
name="Bar",
about="Description",
required=False
@ -75,7 +75,7 @@ class TestDescribeArgFromSpec(unittest.TestCase):
self.assertEqual(repr(out), repr(expected_rst))
def test_integer_spec(self):
spec = spec_utils.IntegerInputSpec(
spec = spec_utils.IntegerInput(
name="Bar",
about="Description",
required=True
@ -86,7 +86,7 @@ class TestDescribeArgFromSpec(unittest.TestCase):
self.assertEqual(repr(out), repr(expected_rst))
def test_boolean_spec(self):
spec = spec_utils.BooleanInputSpec(
spec = spec_utils.BooleanInput(
name="Bar",
about="Description"
)
@ -96,7 +96,7 @@ class TestDescribeArgFromSpec(unittest.TestCase):
self.assertEqual(repr(out), repr(expected_rst))
def test_freestyle_string_spec(self):
spec = spec_utils.StringInputSpec(
spec = spec_utils.StringInput(
name="Bar",
about="Description"
)
@ -106,7 +106,7 @@ class TestDescribeArgFromSpec(unittest.TestCase):
self.assertEqual(repr(out), repr(expected_rst))
def test_option_string_spec_dictionary(self):
spec = spec_utils.OptionStringInputSpec(
spec = spec_utils.OptionStringInput(
name="Bar",
about="Description",
options={
@ -135,7 +135,7 @@ class TestDescribeArgFromSpec(unittest.TestCase):
self.assertEqual(repr(out), repr(expected_rst))
def test_option_string_spec_list(self):
spec = spec_utils.OptionStringInputSpec(
spec = spec_utils.OptionStringInput(
name="Bar",
about="Description",
options=["option_a", "Option_b"]
@ -148,8 +148,8 @@ class TestDescribeArgFromSpec(unittest.TestCase):
self.assertEqual(repr(out), repr(expected_rst))
def test_raster_spec(self):
spec = spec_utils.SingleBandRasterInputSpec(
band=spec_utils.IntegerInputSpec(),
spec = spec_utils.SingleBandRasterInput(
band=spec_utils.IntegerInput(),
about="Description",
name="Bar"
)
@ -159,8 +159,8 @@ class TestDescribeArgFromSpec(unittest.TestCase):
])
self.assertEqual(repr(out), repr(expected_rst))
spec = spec_utils.SingleBandRasterInputSpec(
band=spec_utils.NumberInputSpec(units=u.millimeter/u.year),
spec = spec_utils.SingleBandRasterInput(
band=spec_utils.NumberInput(units=u.millimeter/u.year),
about="Description",
name="Bar"
)
@ -171,7 +171,7 @@ class TestDescribeArgFromSpec(unittest.TestCase):
self.assertEqual(repr(out), repr(expected_rst))
def test_vector_spec(self):
spec = spec_utils.VectorInputSpec(
spec = spec_utils.VectorInput(
fields={},
geometries={"LINESTRING"},
about="Description",
@ -183,13 +183,13 @@ class TestDescribeArgFromSpec(unittest.TestCase):
])
self.assertEqual(repr(out), repr(expected_rst))
spec = spec_utils.VectorInputSpec(
spec = spec_utils.VectorInput(
fields=spec_utils.Fields(
spec_utils.IntegerInputSpec(
spec_utils.IntegerInput(
id="id",
about="Unique identifier for each feature"
),
spec_utils.NumberInputSpec(
spec_utils.NumberInput(
id="precipitation",
units=u.millimeter/u.year,
about="Average annual precipitation over the area"
@ -206,7 +206,7 @@ class TestDescribeArgFromSpec(unittest.TestCase):
self.assertEqual(repr(out), repr(expected_rst))
def test_csv_spec(self):
spec = spec_utils.CSVInputSpec(
spec = spec_utils.CSVInput(
about="Description.",
name="Bar"
)
@ -219,11 +219,11 @@ class TestDescribeArgFromSpec(unittest.TestCase):
# Test every type that can be nested in a CSV column:
# number, ratio, percent, code,
spec = spec_utils.CSVInputSpec(
spec = spec_utils.CSVInput(
about="Description",
name="Bar",
columns=spec_utils.Columns(
spec_utils.RatioInputSpec(
spec_utils.RatioInput(
id="b",
about="description"
)
@ -237,7 +237,7 @@ class TestDescribeArgFromSpec(unittest.TestCase):
def test_directory_spec(self):
self.maxDiff = None
spec = spec_utils.DirectoryInputSpec(
spec = spec_utils.DirectoryInput(
about="Description",
name="Bar",
contents={}
@ -249,10 +249,10 @@ class TestDescribeArgFromSpec(unittest.TestCase):
self.assertEqual(repr(out), repr(expected_rst))
def test_multi_type_spec(self):
spec = spec_utils.RasterOrVectorInputSpec(
spec = spec_utils.RasterOrVectorInput(
about="Description",
name="Bar",
band=spec_utils.IntegerInputSpec(),
band=spec_utils.IntegerInput(),
geometries={"POLYGON"},
fields={}
)
@ -278,7 +278,7 @@ def _generate_files_from_spec(output_spec, workspace):
"""A utility function to support the metadata test."""
for spec_data in output_spec:
print(spec_data.__class__)
if spec_data.__class__ is spec_utils.DirectoryOutputSpec:
if spec_data.__class__ is spec_utils.DirectoryOutput:
os.mkdir(os.path.join(workspace, spec_data.id))
_generate_files_from_spec(
spec_data.contents, os.path.join(workspace, spec_data.id))
@ -319,21 +319,21 @@ class TestMetadataFromSpec(unittest.TestCase):
# An example invest output spec
output_spec = spec_utils.ModelOutputs(
spec_utils.DirectoryOutputSpec(
spec_utils.DirectoryOutput(
id='output',
contents=spec_utils.Contents(
spec_utils.SingleBandRasterOutputSpec(
spec_utils.SingleBandRasterOutput(
id="urban_nature_supply_percapita.tif",
about="The calculated supply per capita of urban nature.",
band=spec_utils.NumberInputSpec(units=u.m**2)
band=spec_utils.NumberInput(units=u.m**2)
),
spec_utils.VectorOutputSpec(
spec_utils.VectorOutput(
id="admin_boundaries.gpkg",
about=("A copy of the user's administrative boundaries "
"vector with a single layer."),
geometries=spec_utils.POLYGONS,
fields=spec_utils.Fields(
spec_utils.NumberInputSpec(
spec_utils.NumberInput(
id="SUP_DEMadm_cap",
units=u.m**2/u.person,
about="The average urban nature supply/demand"
@ -342,7 +342,7 @@ class TestMetadataFromSpec(unittest.TestCase):
)
)
),
spec_utils.DirectoryOutputSpec(
spec_utils.DirectoryOutput(
id='intermediate',
contents=spec_utils.Contents(
spec_utils.build_output_spec('taskgraph_cache', spec_utils.TASKGRAPH_DIR)

View File

@ -69,11 +69,11 @@ class UsageLoggingTests(unittest.TestCase):
model_id='', model_title='', userguide=None,
aliases=None, ui_spec=spec_utils.UISpec(order=[], hidden={}),
inputs=spec_utils.ModelInputs(
spec_utils.SingleBandRasterInputSpec(id='raster', band=spec_utils.InputSpec()),
spec_utils.VectorInputSpec(id='vector', geometries={}, fields={}),
spec_utils.StringInputSpec(id='not_a_gis_input'),
spec_utils.SingleBandRasterInputSpec(id='blank_raster_path', band=spec_utils.InputSpec()),
spec_utils.VectorInputSpec(id='blank_vector_path', geometries={}, fields={})
spec_utils.SingleBandRasterInput(id='raster', band=spec_utils.Input()),
spec_utils.VectorInput(id='vector', geometries={}, fields={}),
spec_utils.StringInput(id='not_a_gis_input'),
spec_utils.SingleBandRasterInput(id='blank_raster_path', band=spec_utils.Input()),
spec_utils.VectorInput(id='blank_vector_path', geometries={}, fields={})
),
outputs={},
args_with_spatial_overlap=None)

File diff suppressed because it is too large Load Diff