rename ARGS_SPEC to MODEL_SPEC everywhere
This commit is contained in:
parent
521f18a352
commit
bffbb342f6
|
@ -228,9 +228,9 @@ invest_model_modules = {}
|
|||
for _, name, _ in pkgutil.walk_packages(path=[INVEST_LIB_DIR],
|
||||
prefix='natcap.'):
|
||||
module = importlib.import_module(name)
|
||||
# any module with an ARGS_SPEC is an invest model
|
||||
if hasattr(module, 'ARGS_SPEC'):
|
||||
model_title = module.ARGS_SPEC['model_name']
|
||||
# any module with a MODEL_SPEC is an invest model
|
||||
if hasattr(module, 'MODEL_SPEC'):
|
||||
model_title = module.MODEL_SPEC['model_name']
|
||||
invest_model_modules[model_title] = name
|
||||
|
||||
# Write sphinx autodoc function for each entrypoint
|
||||
|
|
|
@ -306,7 +306,7 @@ Using the parameter study example, this might look like:
|
|||
Internationalization
|
||||
====================
|
||||
|
||||
If you use the InVEST python API to access model names, ``ARGS_SPEC``s, or validation messages, you can translate those strings using ``gettext``:
|
||||
If you use the InVEST python API to access model names, ``MODEL_SPEC``s, or validation messages, you can translate those strings using ``gettext``:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
|
|
|
@ -1380,4 +1380,4 @@ def validate(args, limit_to=None):
|
|||
|
||||
"""
|
||||
return validation.validate(
|
||||
args, ARGS_SPEC['args'], ARGS_SPEC['args_with_spatial_overlap'])
|
||||
args, MODEL_SPEC['args'], MODEL_SPEC['args_with_spatial_overlap'])
|
||||
|
|
|
@ -756,4 +756,4 @@ def validate(args, limit_to=None):
|
|||
be an empty list if validation succeeds.
|
||||
"""
|
||||
return validation.validate(
|
||||
args, ARGS_SPEC['args'], ARGS_SPEC['args_with_spatial_overlap'])
|
||||
args, MODEL_SPEC['args'], MODEL_SPEC['args_with_spatial_overlap'])
|
||||
|
|
|
@ -125,7 +125,7 @@ def export_to_python(target_filepath, model, args_dict=None):
|
|||
if args_dict is None:
|
||||
model_module = importlib.import_module(
|
||||
name=model_metadata.MODEL_METADATA[model].pyname)
|
||||
spec = model_module.ARGS_SPEC
|
||||
spec = model_module.MODEL_SPEC
|
||||
cast_args = {key: '' for key in spec['args'].keys()}
|
||||
else:
|
||||
cast_args = dict((str(key), value) for (key, value)
|
||||
|
@ -436,7 +436,7 @@ def main(user_args=None):
|
|||
target_model = model_metadata.MODEL_METADATA[args.model].pyname
|
||||
model_module = importlib.reload(
|
||||
importlib.import_module(name=target_model))
|
||||
spec = model_module.ARGS_SPEC
|
||||
spec = model_module.MODEL_SPEC
|
||||
|
||||
if args.json:
|
||||
message = json.dumps(spec)
|
||||
|
|
|
@ -567,7 +567,7 @@ def execute(args):
|
|||
Required if ``args['do_economic_analysis']``.
|
||||
args['biophysical_table_path'] (string): The path to the biophysical
|
||||
table on disk. This table has many required columns. See
|
||||
``ARGS_SPEC`` for the required columns.
|
||||
``MODEL_SPEC`` for the required columns.
|
||||
args['landcover_transitions_table'] (string): The path to the landcover
|
||||
transitions table, indicating the behavior of carbon when the
|
||||
landscape undergoes a transition.
|
||||
|
@ -2282,7 +2282,7 @@ def validate(args, limit_to=None):
|
|||
message applies to and tuple[1] is the string validation warning.
|
||||
"""
|
||||
validation_warnings = validation.validate(
|
||||
args, ARGS_SPEC['args'])
|
||||
args, MODEL_SPEC['args'])
|
||||
|
||||
sufficient_keys = validation.get_sufficient_keys(args)
|
||||
invalid_keys = validation.get_invalid_keys(validation_warnings)
|
||||
|
|
|
@ -368,7 +368,7 @@ def _create_biophysical_table(landcover_table, target_biophysical_table_path):
|
|||
``None``
|
||||
"""
|
||||
target_column_names = [
|
||||
colname.lower() for colname in coastal_blue_carbon.ARGS_SPEC['args'][
|
||||
colname.lower() for colname in coastal_blue_carbon.MODEL_SPEC['args'][
|
||||
'biophysical_table_path']['columns']]
|
||||
|
||||
with open(target_biophysical_table_path, 'w') as bio_table:
|
||||
|
@ -400,4 +400,4 @@ def validate(args, limit_to=None):
|
|||
A list of tuples where tuple[0] is an iterable of keys that the error
|
||||
message applies to and tuple[1] is the string validation warning.
|
||||
"""
|
||||
return validation.validate(args, ARGS_SPEC['args'])
|
||||
return validation.validate(args, MODEL_SPEC['args'])
|
||||
|
|
|
@ -3355,7 +3355,7 @@ def validate(args, limit_to=None):
|
|||
|
||||
"""
|
||||
validation_warnings = validation.validate(
|
||||
args, ARGS_SPEC['args'], ARGS_SPEC['args_with_spatial_overlap'])
|
||||
args, MODEL_SPEC['args'], MODEL_SPEC['args_with_spatial_overlap'])
|
||||
|
||||
invalid_keys = validation.get_invalid_keys(validation_warnings)
|
||||
sufficient_keys = validation.get_sufficient_keys(args)
|
||||
|
|
|
@ -988,4 +988,4 @@ def validate(args, limit_to=None):
|
|||
be an empty list if validation succeeds.
|
||||
"""
|
||||
return validation.validate(
|
||||
args, ARGS_SPEC['args'], ARGS_SPEC['args_with_spatial_overlap'])
|
||||
args, MODEL_SPEC['args'], MODEL_SPEC['args_with_spatial_overlap'])
|
||||
|
|
|
@ -1035,4 +1035,4 @@ def validate(args, limit_to=None):
|
|||
|
||||
"""
|
||||
return validation.validate(
|
||||
args, ARGS_SPEC['args'], ARGS_SPEC['args_with_spatial_overlap'])
|
||||
args, MODEL_SPEC['args'], MODEL_SPEC['args_with_spatial_overlap'])
|
||||
|
|
|
@ -212,7 +212,7 @@ def build_datastack_archive(args, model_name, datastack_path):
|
|||
# For tracking existing files so we don't copy files in twice
|
||||
files_found = {}
|
||||
LOGGER.debug(f'Keys: {sorted(args.keys())}')
|
||||
args_spec = module.ARGS_SPEC['args']
|
||||
args_spec = module.MODEL_SPEC['args']
|
||||
|
||||
spatial_types = {'raster', 'vector'}
|
||||
file_based_types = spatial_types.union({'csv', 'file', 'directory'})
|
||||
|
@ -220,7 +220,7 @@ def build_datastack_archive(args, model_name, datastack_path):
|
|||
for key in args:
|
||||
# Allow the model to override specific arguments in datastack archive
|
||||
# prep. This is useful for tables (like HRA) that are too complicated
|
||||
# to describe in the ARGS_SPEC format, but use a common specification
|
||||
# to describe in the MODEL_SPEC format, but use a common specification
|
||||
# for the other args keys.
|
||||
override_funcname = f'_override_datastack_archive_{key}'
|
||||
if hasattr(module, override_funcname):
|
||||
|
@ -249,7 +249,7 @@ def build_datastack_archive(args, model_name, datastack_path):
|
|||
# Possible that a user might pass an args key that doesn't belong to
|
||||
# this model. Skip if so.
|
||||
if key not in args_spec:
|
||||
LOGGER.info(f'Skipping arg {key}; not in model ARGS_SPEC')
|
||||
LOGGER.info(f'Skipping arg {key}; not in model MODEL_SPEC')
|
||||
|
||||
input_type = args_spec[key]['type']
|
||||
if input_type in file_based_types:
|
||||
|
@ -275,7 +275,7 @@ def build_datastack_archive(args, model_name, datastack_path):
|
|||
if input_type == 'csv':
|
||||
# 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 ARGS_SPEC.
|
||||
# require that 'columns' exists in the MODEL_SPEC.
|
||||
spatial_columns = []
|
||||
if 'columns' in args_spec[key]:
|
||||
for col_name, col_definition in (
|
||||
|
@ -402,7 +402,7 @@ def build_datastack_archive(args, model_name, datastack_path):
|
|||
# Note that no models currently use this to the best of my
|
||||
# knowledge, so better to raise a NotImplementedError
|
||||
raise NotImplementedError(
|
||||
'The "other" ARGS_SPEC input type is not supported')
|
||||
'The "other" MODEL_SPEC input type is not supported')
|
||||
else:
|
||||
LOGGER.debug(
|
||||
f"Type {input_type} is not filesystem-based; "
|
||||
|
|
|
@ -820,4 +820,4 @@ def validate(args, limit_to=None):
|
|||
|
||||
"""
|
||||
return validation.validate(
|
||||
args, ARGS_SPEC['args'], ARGS_SPEC['args_with_spatial_overlap'])
|
||||
args, MODEL_SPEC['args'], MODEL_SPEC['args_with_spatial_overlap'])
|
||||
|
|
|
@ -1035,7 +1035,7 @@ def validate(args, limit_to=None):
|
|||
|
||||
"""
|
||||
validation_warnings = validation.validate(
|
||||
args, ARGS_SPEC['args'], ARGS_SPEC['args_with_spatial_overlap'])
|
||||
args, MODEL_SPEC['args'], MODEL_SPEC['args_with_spatial_overlap'])
|
||||
|
||||
invalid_keys = set([])
|
||||
for affected_keys, error_msg in validation_warnings:
|
||||
|
|
|
@ -1226,4 +1226,4 @@ def validate(args, limit_to=None):
|
|||
|
||||
"""
|
||||
return validation.validate(
|
||||
args, ARGS_SPEC['args'], ARGS_SPEC['args_with_spatial_overlap'])
|
||||
args, MODEL_SPEC['args'], MODEL_SPEC['args_with_spatial_overlap'])
|
||||
|
|
|
@ -1114,7 +1114,7 @@ def validate(args, limit_to=None):
|
|||
be an empty list if validation succeeds.
|
||||
"""
|
||||
validation_warnings = validation.validate(
|
||||
args, ARGS_SPEC['args'], ARGS_SPEC['args_with_spatial_overlap'])
|
||||
args, MODEL_SPEC['args'], MODEL_SPEC['args_with_spatial_overlap'])
|
||||
|
||||
invalid_keys = validation.get_invalid_keys(validation_warnings)
|
||||
|
||||
|
|
|
@ -65,7 +65,7 @@ Then follow the "Process to update translations" instructions above, starting fr
|
|||
## Which messages are translated?
|
||||
|
||||
* Model titles
|
||||
* `ARGS_SPEC` `name` and `about` text
|
||||
* `MODEL_SPEC` `name` and `about` text
|
||||
* Validation messages
|
||||
* Strings that appear in the UI, such as button labels and tooltip text
|
||||
|
||||
|
|
|
@ -1023,7 +1023,7 @@ def validate(args, limit_to=None):
|
|||
|
||||
"""
|
||||
validation_warnings = validation.validate(
|
||||
args, ARGS_SPEC['args'], ARGS_SPEC['args_with_spatial_overlap'])
|
||||
args, MODEL_SPEC['args'], MODEL_SPEC['args_with_spatial_overlap'])
|
||||
|
||||
invalid_keys = validation.get_invalid_keys(validation_warnings)
|
||||
|
||||
|
|
|
@ -1601,4 +1601,4 @@ def validate(args, limit_to=None):
|
|||
# Deliberately not validating the interrelationship of the columns between
|
||||
# the biophysical table and the guilds table as the model itself already
|
||||
# does extensive checking for this.
|
||||
return validation.validate(args, ARGS_SPEC['args'])
|
||||
return validation.validate(args, MODEL_SPEC['args'])
|
||||
|
|
|
@ -1667,4 +1667,4 @@ def validate(args, limit_to=None):
|
|||
be an empty list if validation succeeds.
|
||||
|
||||
"""
|
||||
return validation.validate(args, ARGS_SPEC['args'])
|
||||
return validation.validate(args, MODEL_SPEC['args'])
|
||||
|
|
|
@ -366,7 +366,7 @@ def validate(args, limit_to=None):
|
|||
the error message in the second part of the tuple. This should
|
||||
be an empty list if validation succeeds.
|
||||
"""
|
||||
validation_warnings = validation.validate(args, ARGS_SPEC['args'])
|
||||
validation_warnings = validation.validate(args, MODEL_SPEC['args'])
|
||||
|
||||
invalid_keys = validation.get_invalid_keys(validation_warnings)
|
||||
sufficient_keys = validation.get_sufficient_keys(args)
|
||||
|
|
|
@ -904,7 +904,7 @@ def validate(args, limit_to=None):
|
|||
be an empty list if validation succeeds.
|
||||
|
||||
"""
|
||||
validation_warnings = validation.validate(args, ARGS_SPEC['args'])
|
||||
validation_warnings = validation.validate(args, MODEL_SPEC['args'])
|
||||
invalid_keys = validation.get_invalid_keys(validation_warnings)
|
||||
|
||||
if ('convert_nearest_to_edge' not in invalid_keys and
|
||||
|
|
|
@ -258,7 +258,7 @@ def execute(args):
|
|||
'b': float(args['b_coef']),
|
||||
}
|
||||
if (args['valuation_function'] not in
|
||||
ARGS_SPEC['args']['valuation_function']['options']):
|
||||
MODEL_SPEC['args']['valuation_function']['options']):
|
||||
raise ValueError('Valuation function type %s not recognized' %
|
||||
args['valuation_function'])
|
||||
max_valuation_radius = float(args['max_valuation_radius'])
|
||||
|
@ -1092,4 +1092,4 @@ def validate(args, limit_to=None):
|
|||
|
||||
"""
|
||||
return validation.validate(
|
||||
args, ARGS_SPEC['args'], ARGS_SPEC['args_with_spatial_overlap'])
|
||||
args, MODEL_SPEC['args'], MODEL_SPEC['args_with_spatial_overlap'])
|
||||
|
|
|
@ -1600,7 +1600,7 @@ def validate(args, limit_to=None):
|
|||
|
||||
"""
|
||||
validation_warnings = validation.validate(
|
||||
args, ARGS_SPEC['args'], ARGS_SPEC['args_with_spatial_overlap'])
|
||||
args, MODEL_SPEC['args'], MODEL_SPEC['args_with_spatial_overlap'])
|
||||
|
||||
invalid_keys = validation.get_invalid_keys(validation_warnings)
|
||||
sufficient_keys = validation.get_sufficient_keys(args)
|
||||
|
|
|
@ -1357,5 +1357,5 @@ def validate(args, limit_to=None):
|
|||
the error message in the second part of the tuple. This should
|
||||
be an empty list if validation succeeds.
|
||||
"""
|
||||
return validation.validate(args, ARGS_SPEC['args'],
|
||||
ARGS_SPEC['args_with_spatial_overlap'])
|
||||
return validation.validate(args, MODEL_SPEC['args'],
|
||||
MODEL_SPEC['args_with_spatial_overlap'])
|
||||
|
|
|
@ -209,10 +209,10 @@ def format_unit(unit):
|
|||
|
||||
|
||||
def serialize_args_spec(spec):
|
||||
"""Serialize an ARGS_SPEC dict to a JSON string.
|
||||
"""Serialize an MODEL_SPEC dict to a JSON string.
|
||||
|
||||
Args:
|
||||
spec (dict): An invest model's ARGS_SPEC.
|
||||
spec (dict): An invest model's MODEL_SPEC.
|
||||
|
||||
Raises:
|
||||
TypeError if any object type within the spec is not handled by
|
||||
|
@ -506,11 +506,11 @@ def describe_arg_from_name(module_name, *arg_keys):
|
|||
<arg_keys[0]>-<arg_keys[1]>...-<arg_keys[n]>
|
||||
where underscores in arg keys are replaced with hyphens.
|
||||
"""
|
||||
# import the specified module (that should have an ARGS_SPEC attribute)
|
||||
# import the specified module (that should have an MODEL_SPEC attribute)
|
||||
module = importlib.import_module(module_name)
|
||||
# start with the spec for all args
|
||||
# narrow down to the nested spec indicated by the sequence of arg keys
|
||||
spec = module.ARGS_SPEC['args']
|
||||
spec = module.MODEL_SPEC['args']
|
||||
for i, key in enumerate(arg_keys):
|
||||
# convert raster band numbers to ints
|
||||
if arg_keys[i - 1] == 'bands':
|
||||
|
@ -521,7 +521,7 @@ def describe_arg_from_name(module_name, *arg_keys):
|
|||
keys_so_far = '.'.join(arg_keys[:i + 1])
|
||||
raise ValueError(
|
||||
f"Could not find the key '{keys_so_far}' in the "
|
||||
f"{module_name} model's ARGS_SPEC")
|
||||
f"{module_name} model's MODEL_SPEC")
|
||||
|
||||
# format spec into an RST formatted description string
|
||||
if 'name' in spec:
|
||||
|
|
|
@ -1198,5 +1198,5 @@ def validate(args, limit_to=None):
|
|||
the error message in the second part of the tuple. This should
|
||||
be an empty list if validation succeeds.
|
||||
"""
|
||||
return validation.validate(args, ARGS_SPEC['args'],
|
||||
ARGS_SPEC['args_with_spatial_overlap'])
|
||||
return validation.validate(args, MODEL_SPEC['args'],
|
||||
MODEL_SPEC['args_with_spatial_overlap'])
|
||||
|
|
|
@ -56,7 +56,7 @@ def get_invest_models():
|
|||
|
||||
@app.route(f'/{PREFIX}/getspec', methods=['POST'])
|
||||
def get_invest_getspec():
|
||||
"""Gets the ARGS_SPEC dict from an InVEST model.
|
||||
"""Gets the MODEL_SPEC dict from an InVEST model.
|
||||
|
||||
Body (JSON string): "carbon"
|
||||
Accepts a `language` query parameter which should be an ISO 639-1 language
|
||||
|
@ -71,7 +71,7 @@ def get_invest_getspec():
|
|||
target_module = MODEL_METADATA[target_model].pyname
|
||||
model_module = importlib.reload(
|
||||
importlib.import_module(name=target_module))
|
||||
return spec_utils.serialize_args_spec(model_module.ARGS_SPEC)
|
||||
return spec_utils.serialize_args_spec(model_module.MODEL_SPEC)
|
||||
|
||||
|
||||
@app.route(f'/{PREFIX}/validate', methods=['POST'])
|
||||
|
|
|
@ -1059,7 +1059,7 @@ def calculate_energy_savings(
|
|||
|
||||
# Find the index of the 'type' column in a case-insensitive way.
|
||||
# We can assume that the field exists because we're checking for it in
|
||||
# validation as defined in ARGS_SPEC.
|
||||
# validation as defined in MODEL_SPEC.
|
||||
fieldnames = [field.GetName().lower()
|
||||
for field in target_building_layer.schema]
|
||||
type_field_index = fieldnames.index('type')
|
||||
|
@ -1511,7 +1511,7 @@ def validate(args, limit_to=None):
|
|||
|
||||
"""
|
||||
validation_warnings = validation.validate(
|
||||
args, ARGS_SPEC['args'], ARGS_SPEC['args_with_spatial_overlap'])
|
||||
args, MODEL_SPEC['args'], MODEL_SPEC['args_with_spatial_overlap'])
|
||||
|
||||
invalid_keys = validation.get_invalid_keys(validation_warnings)
|
||||
if ('biophysical_table_path' not in invalid_keys and
|
||||
|
@ -1523,7 +1523,7 @@ def validate(args, limit_to=None):
|
|||
# If args['cc_method'] isn't one of these two allowed values
|
||||
# ('intensity' or 'factors'), it'll be caught by
|
||||
# validation.validate due to the allowed values stated in
|
||||
# ARGS_SPEC.
|
||||
# MODEL_SPEC.
|
||||
extra_biophysical_keys = ['building_intensity']
|
||||
|
||||
error_msg = validation.check_csv(
|
||||
|
|
|
@ -908,5 +908,5 @@ def validate(args, limit_to=None):
|
|||
be an empty list if validation succeeds.
|
||||
|
||||
"""
|
||||
return validation.validate(args, ARGS_SPEC['args'],
|
||||
ARGS_SPEC['args_with_spatial_overlap'])
|
||||
return validation.validate(args, MODEL_SPEC['args'],
|
||||
MODEL_SPEC['args_with_spatial_overlap'])
|
||||
|
|
|
@ -70,7 +70,7 @@ def _calculate_args_bounding_box(args, args_spec):
|
|||
|
||||
Args:
|
||||
args (dict): a string key and any value pair dictionary.
|
||||
args_spec (dict): the model ARGS_SPEC describing args
|
||||
args_spec (dict): the model MODEL_SPEC describing args
|
||||
|
||||
Returns:
|
||||
bb_intersection, bb_union tuple that's either the lat/lng bounding
|
||||
|
@ -216,7 +216,7 @@ def _log_model(pyname, model_args, invest_interface, session_id=None):
|
|||
md5.update(json.dumps(data).encode('utf-8'))
|
||||
return md5.hexdigest()
|
||||
|
||||
args_spec = importlib.import_module(pyname).ARGS_SPEC
|
||||
args_spec = importlib.import_module(pyname).MODEL_SPEC
|
||||
|
||||
try:
|
||||
bounding_box_intersection, bounding_box_union = (
|
||||
|
|
|
@ -904,12 +904,12 @@ def validate(args, spec, spatial_overlap_opts=None):
|
|||
invalid_keys = set()
|
||||
sufficient_keys = set(args.keys()).difference(insufficient_keys)
|
||||
for key in sufficient_keys.difference(excluded_keys):
|
||||
# Extra args that don't exist in the ARGS_SPEC are okay
|
||||
# Extra args that don't exist in the MODEL_SPEC are okay
|
||||
# we don't need to try to validate them
|
||||
try:
|
||||
parameter_spec = spec[key]
|
||||
except KeyError:
|
||||
LOGGER.debug(f'Provided key {key} does not exist in ARGS_SPEC')
|
||||
LOGGER.debug(f'Provided key {key} does not exist in MODEL_SPEC')
|
||||
continue
|
||||
|
||||
type_validation_func = _VALIDATION_FUNCS[parameter_spec['type']]
|
||||
|
@ -1013,24 +1013,24 @@ def invest_validator(validate_func):
|
|||
# import one another. This causes a problem in test_validation.py,
|
||||
# which gets imported into itself here and fails.
|
||||
# Since this decorator might not be needed in the future,
|
||||
# just ignore failed imports; assume they have no ARGS_SPEC.
|
||||
# just ignore failed imports; assume they have no MODEL_SPEC.
|
||||
try:
|
||||
model_module = importlib.import_module(validate_func.__module__)
|
||||
except Exception:
|
||||
LOGGER.warning('Unable to import module %s: assuming no ARGS_SPEC.',
|
||||
LOGGER.warning('Unable to import module %s: assuming no MODEL_SPEC.',
|
||||
validate_func.__module__)
|
||||
model_module = None
|
||||
|
||||
# If the module has an ARGS_SPEC defined, validate against that.
|
||||
if hasattr(model_module, 'ARGS_SPEC'):
|
||||
# If the module has an MODEL_SPEC defined, validate against that.
|
||||
if hasattr(model_module, 'MODEL_SPEC'):
|
||||
LOGGER.debug('Using ARG_SPEC for validation')
|
||||
args_spec = getattr(model_module, 'ARGS_SPEC')['args']
|
||||
args_spec = getattr(model_module, 'MODEL_SPEC')['args']
|
||||
|
||||
if limit_to is None:
|
||||
LOGGER.info('Starting whole-model validation with ARGS_SPEC')
|
||||
LOGGER.info('Starting whole-model validation with MODEL_SPEC')
|
||||
warnings_ = validate_func(args)
|
||||
else:
|
||||
LOGGER.info('Starting single-input validation with ARGS_SPEC')
|
||||
LOGGER.info('Starting single-input validation with MODEL_SPEC')
|
||||
args_key_spec = args_spec[limit_to]
|
||||
|
||||
args_value = args[limit_to]
|
||||
|
@ -1061,7 +1061,7 @@ def invest_validator(validate_func):
|
|||
else:
|
||||
warnings_ = [([limit_to], error_msg)]
|
||||
else: # args_spec is not defined for this function.
|
||||
LOGGER.warning('ARGS_SPEC not defined for this model')
|
||||
LOGGER.warning('MODEL_SPEC not defined for this model')
|
||||
warnings_ = validate_func(args, limit_to)
|
||||
|
||||
LOGGER.debug('Validation warnings: %s',
|
||||
|
|
|
@ -2340,4 +2340,4 @@ def validate(args, limit_to=None):
|
|||
validation warning.
|
||||
|
||||
"""
|
||||
return validation.validate(args, ARGS_SPEC['args'])
|
||||
return validation.validate(args, MODEL_SPEC['args'])
|
||||
|
|
|
@ -2703,5 +2703,5 @@ def validate(args, limit_to=None):
|
|||
message applies to and tuple[1] is the str validation warning.
|
||||
|
||||
"""
|
||||
return validation.validate(args, ARGS_SPEC['args'],
|
||||
ARGS_SPEC['args_with_spatial_overlap'])
|
||||
return validation.validate(args, MODEL_SPEC['args'],
|
||||
MODEL_SPEC['args_with_spatial_overlap'])
|
||||
|
|
|
@ -269,7 +269,7 @@ class CarbonTests(unittest.TestCase):
|
|||
|
||||
|
||||
class CarbonValidationTests(unittest.TestCase):
|
||||
"""Tests for the Carbon Model ARGS_SPEC and validation."""
|
||||
"""Tests for the Carbon Model MODEL_SPEC and validation."""
|
||||
|
||||
def setUp(self):
|
||||
"""Create a temporary workspace."""
|
||||
|
|
|
@ -401,7 +401,7 @@ class CLIUnitTests(unittest.TestCase):
|
|||
|
||||
target_model = model_metadata.MODEL_METADATA[target_model].pyname
|
||||
model_module = importlib.import_module(name=target_model)
|
||||
spec = model_module.ARGS_SPEC
|
||||
spec = model_module.MODEL_SPEC
|
||||
expected_args = {key: '' for key in spec['args'].keys()}
|
||||
|
||||
module_name = str(uuid.uuid4()) + 'testscript'
|
||||
|
|
|
@ -1583,7 +1583,7 @@ def assert_pickled_arrays_almost_equal(
|
|||
|
||||
|
||||
class CoastalVulnerabilityValidationTests(unittest.TestCase):
|
||||
"""Tests for the CV Model ARGS_SPEC and validation."""
|
||||
"""Tests for the CV Model MODEL_SPEC and validation."""
|
||||
|
||||
def setUp(self):
|
||||
"""Create a temporary workspace."""
|
||||
|
|
|
@ -400,7 +400,7 @@ class CropProductionTests(unittest.TestCase):
|
|||
|
||||
|
||||
class CropValidationTests(unittest.TestCase):
|
||||
"""Tests for the Crop Productions' ARGS_SPEC and validation."""
|
||||
"""Tests for the Crop Productions' MODEL_SPEC and validation."""
|
||||
|
||||
def setUp(self):
|
||||
"""Create a temporary workspace."""
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
ARGS_SPEC = {
|
||||
MODEL_SPEC = {
|
||||
'args': {
|
||||
'blank': {'type': 'freestyle_string'},
|
||||
'a': {'type': 'integer'},
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
ARGS_SPEC = {
|
||||
MODEL_SPEC = {
|
||||
'args': {
|
||||
'foo': {'type': 'file'},
|
||||
'bar': {'type': 'file'},
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
ARGS_SPEC = {
|
||||
MODEL_SPEC = {
|
||||
'args': {
|
||||
'some_file': {'type': 'file'},
|
||||
'data_dir': {'type': 'directory'},
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
ARGS_SPEC = {
|
||||
MODEL_SPEC = {
|
||||
'args': {
|
||||
'raster': {'type': 'raster'},
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
ARGS_SPEC = {
|
||||
MODEL_SPEC = {
|
||||
'args': {
|
||||
'a': {'type': 'integer'},
|
||||
'b': {'type': 'freestyle_string'},
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
ARGS_SPEC = {
|
||||
MODEL_SPEC = {
|
||||
'args': {
|
||||
'foo': {'type': 'freestyle_string'},
|
||||
'bar': {'type': 'freestyle_string'},
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
ARGS_SPEC = {
|
||||
MODEL_SPEC = {
|
||||
'args': {
|
||||
'vector': {'type': 'vector'},
|
||||
}
|
||||
|
|
|
@ -349,7 +349,7 @@ class ForestCarbonEdgeTests(unittest.TestCase):
|
|||
|
||||
|
||||
class ForestCarbonEdgeValidationTests(unittest.TestCase):
|
||||
"""Tests for the Forest Carbon Model ARGS_SPEC and validation."""
|
||||
"""Tests for the Forest Carbon Model MODEL_SPEC and validation."""
|
||||
|
||||
def setUp(self):
|
||||
"""Create a temporary workspace."""
|
||||
|
|
|
@ -395,7 +395,7 @@ class GLOBIOTests(unittest.TestCase):
|
|||
|
||||
|
||||
class GlobioValidationTests(unittest.TestCase):
|
||||
"""Tests for the GLOBIO Model ARGS_SPEC and validation."""
|
||||
"""Tests for the GLOBIO Model MODEL_SPEC and validation."""
|
||||
|
||||
def setUp(self):
|
||||
"""Create a temporary workspace."""
|
||||
|
|
|
@ -77,26 +77,23 @@ class ValidateModelSpecs(unittest.TestCase):
|
|||
for key, spec in model.MODEL_SPEC['outputs'].items():
|
||||
self.validate_output(spec, f'{model_name}.outputs.{key}')
|
||||
|
||||
def validate_output(self, spec, key, parent_type=None, is_pattern=False):
|
||||
def validate_output(self, spec, key, parent_type=None):
|
||||
"""
|
||||
Recursively validate nested spec s against the arg spec standard.
|
||||
Recursively validate nested output specs against the output spec standard.
|
||||
|
||||
Args:
|
||||
spec (dict): any nested spec component of an MODEL_SPEC
|
||||
name (str): name to use in error messages to identify the spec
|
||||
parent_type (str): the type of this spec's parent arg (or None if
|
||||
spec (dict): any nested output spec component of a MODEL_SPEC
|
||||
key (str): key to identify the spec by in error messages
|
||||
parent_type (str): the type of this output's parent output (or None if
|
||||
no parent).
|
||||
is_pattern (bool): if True, the arg is validated as a pattern (such
|
||||
as for user-defined CSV headers, vector fields, or directory
|
||||
paths).
|
||||
|
||||
Returns:
|
||||
None
|
||||
|
||||
Raises:
|
||||
AssertionError if the arg violates the standard
|
||||
AssertionError if the output spec violates the standard
|
||||
"""
|
||||
with self.subTest(nested_arg_name=key):
|
||||
with self.subTest(output=key):
|
||||
# if parent_type is None: # all top-level args must have these attrs
|
||||
# for attr in ['about']:
|
||||
# self.assertIn(attr, spec)
|
||||
|
@ -113,7 +110,8 @@ class ValidateModelSpecs(unittest.TestCase):
|
|||
t = 'vector'
|
||||
elif file_extension == 'csv':
|
||||
t = 'csv'
|
||||
elif file_extension in {'json', 'txt', 'pickle', 'db', 'zip', 'dat', 'idx'}:
|
||||
elif file_extension in {'json', 'txt', 'pickle', 'db', 'zip',
|
||||
'dat', 'idx'}:
|
||||
t = 'file'
|
||||
else:
|
||||
raise Warning(
|
||||
|
@ -228,7 +226,7 @@ class ValidateModelSpecs(unittest.TestCase):
|
|||
'expected for its type')
|
||||
|
||||
|
||||
def validate(self, arg, name, parent_type=None, is_pattern=False):
|
||||
def validate(self, arg, name, parent_type=None):
|
||||
"""
|
||||
Recursively validate nested args against the arg spec standard.
|
||||
|
||||
|
@ -237,9 +235,6 @@ class ValidateModelSpecs(unittest.TestCase):
|
|||
name (str): name to use in error messages to identify the arg
|
||||
parent_type (str): the type of this arg's parent arg (or None if
|
||||
no parent).
|
||||
is_pattern (bool): if True, the arg is validated as a pattern (such
|
||||
as for user-defined CSV headers, vector fields, or directory
|
||||
paths).
|
||||
|
||||
Returns:
|
||||
None
|
|
@ -463,7 +463,7 @@ class PollinationTests(unittest.TestCase):
|
|||
|
||||
|
||||
class PollinationValidationTests(unittest.TestCase):
|
||||
"""Tests for the Pollination Model ARGS_SPEC and validation."""
|
||||
"""Tests for the Pollination Model MODEL_SPEC and validation."""
|
||||
|
||||
def setUp(self):
|
||||
"""Create list of always required arguments."""
|
||||
|
|
|
@ -1190,7 +1190,7 @@ class RecreationRegressionTests(unittest.TestCase):
|
|||
|
||||
|
||||
class RecreationValidationTests(unittest.TestCase):
|
||||
"""Tests for the Recreation Model ARGS_SPEC and validation."""
|
||||
"""Tests for the Recreation Model MODEL_SPEC and validation."""
|
||||
|
||||
def setUp(self):
|
||||
"""Create a temporary workspace."""
|
||||
|
|
|
@ -135,7 +135,7 @@ class ScenarioProximityTests(unittest.TestCase):
|
|||
|
||||
|
||||
class ScenarioGenValidationTests(unittest.TestCase):
|
||||
"""Tests for the Scenario Generator ARGS_SPEC and validation."""
|
||||
"""Tests for the Scenario Generator MODEL_SPEC and validation."""
|
||||
|
||||
def setUp(self):
|
||||
"""Initiate list of required keys."""
|
||||
|
|
|
@ -1065,7 +1065,7 @@ class SeasonalWaterYieldRegressionTests(unittest.TestCase):
|
|||
|
||||
|
||||
class SWYValidationTests(unittest.TestCase):
|
||||
"""Tests for the SWY Model ARGS_SPEC and validation."""
|
||||
"""Tests for the SWY Model MODEL_SPEC and validation."""
|
||||
|
||||
def setUp(self):
|
||||
"""Create a temporary workspace."""
|
||||
|
|
|
@ -242,6 +242,6 @@ class TestSpecUtils(unittest.TestCase):
|
|||
expected_rst = (
|
||||
'.. _carbon-pools-path-columns-lucode:\n\n' +
|
||||
'**lucode** (`integer <input_types.html#integer>`__, *required*): ' +
|
||||
carbon.ARGS_SPEC['args']['carbon_pools_path']['columns']['lucode']['about']
|
||||
carbon.MODEL_SPEC['args']['carbon_pools_path']['columns']['lucode']['about']
|
||||
)
|
||||
self.assertEqual(repr(out), repr(expected_rst))
|
||||
|
|
|
@ -136,7 +136,7 @@ class TranslationTests(unittest.TestCase):
|
|||
"""Translation: test that /validate endpoint is translated."""
|
||||
test_client = ui_server.app.test_client()
|
||||
payload = {
|
||||
'model_module': carbon.ARGS_SPEC['pyname'],
|
||||
'model_module': carbon.MODEL_SPEC['pyname'],
|
||||
'args': json.dumps({})
|
||||
}
|
||||
response = test_client.post(
|
||||
|
|
|
@ -67,7 +67,7 @@ class EndpointFunctionTests(unittest.TestCase):
|
|||
self.assertEqual(
|
||||
set(spec),
|
||||
{'model_name', 'pyname', 'userguide',
|
||||
'args_with_spatial_overlap', 'args'})
|
||||
'args_with_spatial_overlap', 'args', 'outputs'})
|
||||
|
||||
def test_get_invest_validate(self):
|
||||
"""UI server: get_invest_validate endpoint."""
|
||||
|
@ -77,7 +77,7 @@ class EndpointFunctionTests(unittest.TestCase):
|
|||
'workspace_dir': 'foo'
|
||||
}
|
||||
payload = {
|
||||
'model_module': carbon.ARGS_SPEC['pyname'],
|
||||
'model_module': carbon.MODEL_SPEC['pyname'],
|
||||
'args': json.dumps(args)
|
||||
}
|
||||
response = test_client.post(f'{ROUTE_PREFIX}/validate', json=payload)
|
||||
|
|
|
@ -1355,7 +1355,7 @@ class TestValidationFromSpec(unittest.TestCase):
|
|||
self.assertEqual(set(args.keys()), set(validation_warnings[0][0]))
|
||||
|
||||
def test_allow_extra_keys(self):
|
||||
"""Including extra keys in args that aren't in ARGS_SPEC should work"""
|
||||
"""Including extra keys in args that aren't in MODEL_SPEC should work"""
|
||||
from natcap.invest import validation
|
||||
|
||||
args = {'a': 'a', 'b': 'b'}
|
||||
|
@ -1367,7 +1367,7 @@ class TestValidationFromSpec(unittest.TestCase):
|
|||
'required': True
|
||||
}
|
||||
}
|
||||
message = 'DEBUG:natcap.invest.validation:Provided key b does not exist in ARGS_SPEC'
|
||||
message = 'DEBUG:natcap.invest.validation:Provided key b does not exist in MODEL_SPEC'
|
||||
|
||||
with self.assertLogs('natcap.invest.validation', level='DEBUG') as cm:
|
||||
validation.validate(args, spec)
|
||||
|
|
|
@ -613,7 +613,7 @@ class WaveEnergyRegressionTests(unittest.TestCase):
|
|||
|
||||
|
||||
class WaveEnergyValidateTests(unittest.TestCase):
|
||||
"""Wave Energy Validate: tests for ARGS_SPEC and validate."""
|
||||
"""Wave Energy Validate: tests for MODEL_SPEC and validate."""
|
||||
|
||||
def setUp(self):
|
||||
"""Set up list of required keys."""
|
||||
|
|
|
@ -850,7 +850,7 @@ class WindEnergyRegressionTests(unittest.TestCase):
|
|||
|
||||
|
||||
class WindEnergyValidationTests(unittest.TestCase):
|
||||
"""Tests for the Wind Energy Model ARGS_SPEC and validation."""
|
||||
"""Tests for the Wind Energy Model MODEL_SPEC and validation."""
|
||||
|
||||
def setUp(self):
|
||||
"""Setup a list of required keys."""
|
||||
|
|
|
@ -22,7 +22,7 @@ import { ipcMainChannels } from '../../../main/ipcMainChannels';
|
|||
const { ipcRenderer } = window.Workbench.electron;
|
||||
const logger = window.Workbench.getLogger('InvestTab');
|
||||
|
||||
/** Get an invest model's ARGS_SPEC when a model button is clicked.
|
||||
/** Get an invest model's spec when a model button is clicked.
|
||||
*
|
||||
* @param {string} modelName - as in a model name appearing in `invest list`
|
||||
* @returns {object} destructures to:
|
||||
|
@ -57,8 +57,8 @@ export default class InvestTab extends React.Component {
|
|||
super(props);
|
||||
this.state = {
|
||||
activeTab: 'setup',
|
||||
modelSpec: null, // ARGS_SPEC dict with all keys except ARGS_SPEC.args
|
||||
argsSpec: null, // ARGS_SPEC.args, the immutable args stuff
|
||||
modelSpec: null, // MODEL_SPEC dict with all keys except MODEL_SPEC.args
|
||||
argsSpec: null, // MODEL_SPEC.args, the immutable args stuff
|
||||
uiSpec: null,
|
||||
userTerminated: false,
|
||||
executeClicked: false,
|
||||
|
|
|
@ -32,7 +32,7 @@ const { ipcRenderer } = window.Workbench.electron;
|
|||
*
|
||||
* Values initialize with either a complete args dict, or with empty/default values.
|
||||
*
|
||||
* @param {object} argsSpec - an InVEST model's ARGS_SPEC.args
|
||||
* @param {object} argsSpec - an InVEST model's MODEL_SPEC.args
|
||||
* @param {object} uiSpec - the model's UI Spec.
|
||||
* @param {object} argsDict - key: value pairs of InVEST model arguments, or {}.
|
||||
*
|
||||
|
|
|
@ -28,7 +28,7 @@ export async function getInvestModelNames() {
|
|||
}
|
||||
|
||||
/**
|
||||
* Get the ARGS_SPEC dict from an invest model as a JSON.
|
||||
* Get the MODEL_SPEC dict from an invest model as a JSON.
|
||||
*
|
||||
* @param {string} payload - model name as given by `invest list`
|
||||
* @returns {Promise} resolves object
|
||||
|
|
|
@ -19,7 +19,7 @@ where
|
|||
Args within each nested array are visually grouped together.
|
||||
- `hidden` (optional) a 1D array of args that should not be displayed in a GUI.
|
||||
Use this for model-specific args, no need to include 'n_workers'.
|
||||
All args in ARGS_SPEC (except n_workers) must be contained in `order`+`hidden`.
|
||||
All args in MODEL_SPEC (except n_workers) must be contained in `order`+`hidden`.
|
||||
`hidden` is only used in tests, to catch args that should be in `order`,
|
||||
but are missing.
|
||||
- `modelName` as passed to `invest getspec <modelName>`
|
||||
|
@ -28,7 +28,7 @@ where
|
|||
- `f` is a function that accepts `SetupTab.state` as its one argument
|
||||
- in the `enabledFunctions` section, `f` returns a boolean where true = enabled, false = disabled
|
||||
- in the `dropdownFunctions` section, `f` returns a list of dropdown options.
|
||||
Note: Most dropdown inputs will have a static list of options defined in the ARGS_SPEC.
|
||||
Note: Most dropdown inputs will have a static list of options defined in the MODEL_SPEC.
|
||||
This is only for dynamically populating a dropdown.
|
||||
|
||||
When the SetupTab component renders, it calls `f(this.state)` to get
|
||||
|
|
|
@ -158,10 +158,10 @@ describe('validate the UI spec', () => {
|
|||
expect(spec.model_name).toBeDefined();
|
||||
expect(Object.keys(UI_SPEC)).toContain(modelName);
|
||||
expect(Object.keys(UI_SPEC[modelName])).toContain('order');
|
||||
// expect each ARGS_SPEC arg to exist in 'order' or 'hidden' property
|
||||
// expect each MODEL_SPEC arg to exist in 'order' or 'hidden' property
|
||||
const orderArray = UI_SPEC[modelName].order.flat();
|
||||
// 'hidden' is an optional property. It need not include 'n_workers',
|
||||
// but we should insert 'n_workers' here as it is present in ARGS_SPEC.
|
||||
// but we should insert 'n_workers' here as it is present in MODEL_SPEC.
|
||||
const hiddenArray = UI_SPEC[modelName].hidden || [];
|
||||
const allArgs = orderArray.concat(hiddenArray.concat('n_workers'));
|
||||
const argsSet = new Set(allArgs);
|
||||
|
@ -207,7 +207,7 @@ expect.extend({
|
|||
},
|
||||
});
|
||||
|
||||
describe('Build each model UI from ARGS_SPEC', () => {
|
||||
describe('Build each model UI from MODEL_SPEC', () => {
|
||||
const { UI_SPEC } = require('../../src/renderer/ui_config');
|
||||
|
||||
test.each(Object.keys(UI_SPEC))('%s', async (model) => {
|
||||
|
|
|
@ -18,7 +18,7 @@ jest.mock('../../src/renderer/server_requests');
|
|||
const MODULE = 'carbon';
|
||||
|
||||
const VALIDATION_MESSAGE = 'invalid because';
|
||||
const BASE_ARGS_SPEC = {
|
||||
const BASE_MODEL_SPEC = {
|
||||
args: {
|
||||
arg: {
|
||||
name: 'foo',
|
||||
|
@ -37,14 +37,14 @@ const BASE_ARGS_SPEC = {
|
|||
*/
|
||||
function baseArgsSpec(type) {
|
||||
// make a deep copy so we don't edit the original
|
||||
const spec = JSON.parse(JSON.stringify(BASE_ARGS_SPEC));
|
||||
const spec = JSON.parse(JSON.stringify(BASE_MODEL_SPEC));
|
||||
spec.args.arg.type = type;
|
||||
if (type === 'number') {
|
||||
spec.args.arg.units = 'foo unit';
|
||||
}
|
||||
return spec;
|
||||
}
|
||||
const UI_SPEC = { order: [Object.keys(BASE_ARGS_SPEC.args)] };
|
||||
const UI_SPEC = { order: [Object.keys(BASE_MODEL_SPEC.args)] };
|
||||
|
||||
/**
|
||||
* Render a SetupTab component given the necessary specs.
|
||||
|
@ -54,7 +54,7 @@ const UI_SPEC = { order: [Object.keys(BASE_ARGS_SPEC.args)] };
|
|||
* @returns {object} - containing the test utility functions returned by render
|
||||
*/
|
||||
function renderSetupFromSpec(baseSpec, uiSpec) {
|
||||
// some ARGS_SPEC boilerplate that is not under test,
|
||||
// some MODEL_SPEC boilerplate that is not under test,
|
||||
// but is required by PropType-checking
|
||||
const spec = { ...baseSpec };
|
||||
if (!spec.modelName) { spec.modelName = 'Eco Model'; }
|
||||
|
@ -82,7 +82,7 @@ function renderSetupFromSpec(baseSpec, uiSpec) {
|
|||
describe('Arguments form input types', () => {
|
||||
beforeEach(() => {
|
||||
fetchValidation.mockResolvedValue(
|
||||
[[Object.keys(BASE_ARGS_SPEC.args), VALIDATION_MESSAGE]]
|
||||
[[Object.keys(BASE_MODEL_SPEC.args), VALIDATION_MESSAGE]]
|
||||
);
|
||||
});
|
||||
|
||||
|
@ -157,7 +157,7 @@ describe('Arguments form input types', () => {
|
|||
describe('Arguments form interactions', () => {
|
||||
beforeEach(() => {
|
||||
fetchValidation.mockResolvedValue(
|
||||
[[Object.keys(BASE_ARGS_SPEC.args), VALIDATION_MESSAGE]]
|
||||
[[Object.keys(BASE_MODEL_SPEC.args), VALIDATION_MESSAGE]]
|
||||
);
|
||||
setupOpenExternalUrl();
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue