fix a few bugs introduced in merge and update tests for #1373
This commit is contained in:
parent
a805df880d
commit
0e0c7b1bae
|
@ -1521,9 +1521,8 @@ def _validate_same_id_lengths(table_path):
|
|||
table_path (string): path to a csv table that has at least
|
||||
the field 'id'
|
||||
|
||||
Raises:
|
||||
ValueError if any of the fields in 'id' and 'type' don't match between
|
||||
tables.
|
||||
Return:
|
||||
string message if IDs are too long
|
||||
|
||||
"""
|
||||
predictor_df = utils.read_csv_to_dataframe(
|
||||
|
@ -1552,12 +1551,8 @@ def _validate_same_ids_and_types(
|
|||
at least the fields 'id' and 'type'
|
||||
|
||||
Returns:
|
||||
None
|
||||
|
||||
Raises:
|
||||
ValueError if any of the fields in 'id' and 'type' don't match between
|
||||
tables.
|
||||
|
||||
string message if any of the fields in 'id' and 'type' don't match
|
||||
between tables.
|
||||
"""
|
||||
predictor_df = utils.read_csv_to_dataframe(
|
||||
predictor_table_path, MODEL_SPEC['args']['predictor_table_path'])
|
||||
|
@ -1571,8 +1566,8 @@ def _validate_same_ids_and_types(
|
|||
scenario_predictor_pairs = set([
|
||||
(p_id, row['type']) for p_id, row in scenario_predictor_df.iterrows()])
|
||||
if predictor_pairs != scenario_predictor_pairs:
|
||||
return (f'table pairs unequal. predictor: {predictor_table_pairs} '
|
||||
f'scenario: {scenario_predictor_table_pairs}')
|
||||
return (f'table pairs unequal. predictor: {predictor_pairs} '
|
||||
f'scenario: {scenario_predictor_pairs}')
|
||||
|
||||
|
||||
def _validate_same_projection(base_vector_path, table_path):
|
||||
|
@ -1584,12 +1579,8 @@ def _validate_same_projection(base_vector_path, table_path):
|
|||
the field 'path'
|
||||
|
||||
Returns:
|
||||
None
|
||||
|
||||
Raises:
|
||||
ValueError if the projections in each of the GIS types in the table
|
||||
string message if the projections in each of the GIS types in the table
|
||||
are not identical to the projection in base_vector_path
|
||||
|
||||
"""
|
||||
# This will load the table as a list of paths which we can iterate through
|
||||
# without bothering the rest of the table structure
|
||||
|
@ -1620,16 +1611,12 @@ def _validate_same_projection(base_vector_path, table_path):
|
|||
else:
|
||||
vector = gdal.OpenEx(path, gdal.OF_VECTOR)
|
||||
if vector is None:
|
||||
raise ValueError(f"{path} did not load")
|
||||
return f"{path} did not load"
|
||||
layer = vector.GetLayer()
|
||||
ref = osr.SpatialReference(layer.GetSpatialRef().ExportToWkt())
|
||||
layer = None
|
||||
vector = None
|
||||
if not base_ref.IsSame(ref):
|
||||
LOGGER.warning(
|
||||
f"{path} might have a different projection than the base AOI\n"
|
||||
f"base:{base_ref.ExportToPrettyWkt()}\n"
|
||||
f"current:{ref.ExportToPrettyWkt()}")
|
||||
invalid_projections = True
|
||||
if invalid_projections:
|
||||
return ("One or more of the projections in the table did not match "
|
||||
|
@ -1644,11 +1631,8 @@ def _validate_predictor_types(table_path):
|
|||
the field 'type'
|
||||
|
||||
Returns:
|
||||
None
|
||||
|
||||
Raises:
|
||||
ValueError if any value in the ``type`` column does not match a valid
|
||||
type, ignoring leading/trailing whitespace.
|
||||
string message if any value in the ``type`` column does not match a
|
||||
valid type, ignoring leading/trailing whitespace.
|
||||
"""
|
||||
df = utils.read_csv_to_dataframe(
|
||||
table_path, MODEL_SPEC['args']['predictor_table_path'])
|
||||
|
@ -1707,8 +1691,9 @@ def validate(args, limit_to=None):
|
|||
sufficient_valid_keys = (validation.get_sufficient_keys(args) -
|
||||
validation.get_invalid_keys(validation_messages))
|
||||
|
||||
validation_tuples = []
|
||||
if 'predictor_table_path' in sufficient_valid_keys:
|
||||
validation_tuples = [
|
||||
validation_tuples += [
|
||||
(_validate_same_id_lengths, ['predictor_table_path']),
|
||||
(_validate_same_projection, ['aoi_path', 'predictor_table_path']),
|
||||
(_validate_predictor_types, ['predictor_table_path'])]
|
||||
|
@ -1727,8 +1712,8 @@ def validate(args, limit_to=None):
|
|||
|
||||
if 'start_year' in sufficient_valid_keys and 'end_year' in sufficient_valid_keys:
|
||||
if int(args['end_year']) < int(args['start_year']):
|
||||
validation_messages.append(
|
||||
validation_messages.append((
|
||||
['start_year', 'end_year'],
|
||||
"Start year must be less than or equal to end year.")
|
||||
"Start year must be less than or equal to end year."))
|
||||
|
||||
return validation_messages
|
||||
|
|
|
@ -791,7 +791,7 @@ def _calculate_valuation(visibility_path, viewpoint, weight,
|
|||
weight * visibility[valid_pixels]))
|
||||
return valuation
|
||||
|
||||
elif valuation_method == 'exponential':
|
||||
else: # exponential
|
||||
|
||||
def _valuation(distance, visibility):
|
||||
valid_pixels = (visibility == 1)
|
||||
|
|
|
@ -2758,22 +2758,26 @@ def validate(args, limit_to=None):
|
|||
Returns:
|
||||
A list of tuples where tuple[0] is an iterable of keys that the error
|
||||
message applies to and tuple[1] is the str validation warning.
|
||||
|
||||
"""
|
||||
validation_warnings = validation.validate(args, MODEL_SPEC['args'],
|
||||
MODEL_SPEC['args_with_spatial_overlap'])
|
||||
|
||||
invalid_keys = validation.get_invalid_keys(validation_warnings)
|
||||
if ('wind_schedule' not in invalid_keys and
|
||||
'global_wind_parameters_path' not in invalid_keys):
|
||||
sufficient_keys = validation.get_sufficient_keys(args)
|
||||
valid_sufficient_keys = sufficient_keys - invalid_keys
|
||||
|
||||
if ('wind_schedule' in valid_sufficient_keys and
|
||||
'global_wind_parameters_path' in valid_sufficient_keys):
|
||||
year_count = len(
|
||||
utils.read_csv_to_dataframe(args['wind_schedule'])['year'])
|
||||
utils.read_csv_to_dataframe(
|
||||
args['wind_schedule'], MODEL_SPEC['args']['wind_schedule']))
|
||||
time = int(_read_csv_wind_parameters(
|
||||
args['global_wind_parameters_path'], valuation_global_params
|
||||
args['global_wind_parameters_path'], ['time_period']
|
||||
)['time_period'])
|
||||
if year_count != time + 1:
|
||||
validation_warnings.append((
|
||||
['wind_schedule']
|
||||
['wind_schedule'],
|
||||
"The 'time' argument in the Global Wind Energy Parameters "
|
||||
"file must equal the number of years provided in the price"
|
||||
" table.")
|
||||
"file must equal the number of years provided in the price "
|
||||
"table."))
|
||||
return validation_warnings
|
||||
|
|
|
@ -203,34 +203,6 @@ class ForestCarbonEdgeTests(unittest.TestCase):
|
|||
actual_message = str(cm.exception)
|
||||
self.assertTrue(expected_message in actual_message, actual_message)
|
||||
|
||||
def test_missing_aoi(self):
|
||||
"""Forest carbon edge: ensure missing AOI causes exception."""
|
||||
from natcap.invest import forest_carbon_edge_effect
|
||||
args = {
|
||||
'biomass_to_carbon_conversion_factor': '0.47',
|
||||
'biophysical_table_path': os.path.join(
|
||||
REGRESSION_DATA, 'input',
|
||||
'no_forest_edge_carbon_lu_table_bad_pool_value.csv'),
|
||||
'compute_forest_edge_effects': False,
|
||||
'lulc_raster_path': os.path.join(
|
||||
REGRESSION_DATA, 'input', 'small_lulc.tif'),
|
||||
'n_nearest_model_points': 1,
|
||||
'pools_to_calculate': 'all',
|
||||
'results_suffix': 'small_no_edge_effect',
|
||||
'tropical_forest_edge_carbon_model_vector_path': os.path.join(
|
||||
REGRESSION_DATA, 'input', 'core_data',
|
||||
'forest_carbon_edge_regression_model_parameters.shp'),
|
||||
'workspace_dir': self.workspace_dir,
|
||||
'n_workers': -1
|
||||
}
|
||||
args['aoi_vector_path'] = os.path.join(
|
||||
'path', 'to', 'nonexistant', 'aoi.shp')
|
||||
with self.assertRaises(ValueError) as cm:
|
||||
forest_carbon_edge_effect.execute(args)
|
||||
expected_message = 'Unable to open aoi at:'
|
||||
actual_message = str(cm.exception)
|
||||
self.assertTrue(expected_message in actual_message, actual_message)
|
||||
|
||||
def test_carbon_nodata_lulc(self):
|
||||
"""Forest Carbon Edge: ensure nodata lulc raster cause exception."""
|
||||
from natcap.invest import forest_carbon_edge_effect
|
||||
|
|
|
@ -1476,10 +1476,3 @@ class HRAModelTests(unittest.TestCase):
|
|||
str(cm.exception))
|
||||
self.assertIn("Missing from criteria table: transportation",
|
||||
str(cm.exception))
|
||||
|
||||
args['risk_eq'] = 'some other risk eq'
|
||||
with self.assertRaises(ValueError) as cm:
|
||||
hra.execute(args)
|
||||
|
||||
self.assertIn("must be either 'Multiplicative' or 'Euclidean'",
|
||||
str(cm.exception))
|
||||
|
|
|
@ -102,7 +102,7 @@ class NDRTests(unittest.TestCase):
|
|||
normalized_array, expected_array, rtol=0, atol=1e-6)
|
||||
|
||||
def test_missing_headers(self):
|
||||
"""NDR biphysical headers missing should raise a ValueError."""
|
||||
"""NDR biphysical headers missing should return validation message."""
|
||||
from natcap.invest.ndr import ndr
|
||||
|
||||
# use predefined directory so test can clean up files during teardown
|
||||
|
@ -110,8 +110,8 @@ class NDRTests(unittest.TestCase):
|
|||
# make args explicit that this is a base run of SWY
|
||||
args['biophysical_table_path'] = os.path.join(
|
||||
REGRESSION_DATA, 'input', 'biophysical_table_missing_headers.csv')
|
||||
with self.assertRaises(ValueError):
|
||||
ndr.execute(args)
|
||||
validation_messages = ndr.validate(args)
|
||||
self.assertEqual(len(validation_messages), 1)
|
||||
|
||||
def test_crit_len_0(self):
|
||||
"""NDR test case where crit len is 0 in biophysical table."""
|
||||
|
@ -182,7 +182,7 @@ class NDRTests(unittest.TestCase):
|
|||
in actual_message)
|
||||
|
||||
def test_no_nutrient_selected(self):
|
||||
"""NDR no nutrient selected should raise a ValueError."""
|
||||
"""NDR no nutrient selected should return a validation message."""
|
||||
from natcap.invest.ndr import ndr
|
||||
|
||||
# use predefined directory so test can clean up files during teardown
|
||||
|
@ -190,8 +190,8 @@ class NDRTests(unittest.TestCase):
|
|||
# make args explicit that this is a base run of SWY
|
||||
args['calc_n'] = False
|
||||
args['calc_p'] = False
|
||||
with self.assertRaises(ValueError):
|
||||
ndr.execute(args)
|
||||
validation_messages = ndr.validate(args)
|
||||
self.assertEqual(len(validation_messages), 1)
|
||||
|
||||
def test_base_regression(self):
|
||||
"""NDR base regression test on sample data.
|
||||
|
|
|
@ -697,9 +697,8 @@ class RecreationRegressionTests(unittest.TestCase):
|
|||
table_path = os.path.join(
|
||||
SAMPLE_DATA, 'predictors_data_missing.csv')
|
||||
|
||||
with self.assertRaises(ValueError):
|
||||
recmodel_client._validate_same_projection(
|
||||
response_vector_path, table_path)
|
||||
self.assertIsNotNone(recmodel_client._validate_same_projection(
|
||||
response_vector_path, table_path))
|
||||
|
||||
def test_data_different_projection(self):
|
||||
"""Recreation raise exception if data in different projection."""
|
||||
|
@ -709,9 +708,8 @@ class RecreationRegressionTests(unittest.TestCase):
|
|||
table_path = os.path.join(
|
||||
SAMPLE_DATA, 'predictors_wrong_projection.csv')
|
||||
|
||||
with self.assertRaises(ValueError):
|
||||
recmodel_client._validate_same_projection(
|
||||
response_vector_path, table_path)
|
||||
self.assertIsNotNone(recmodel_client._validate_same_projection(
|
||||
response_vector_path, table_path))
|
||||
|
||||
def test_different_tables(self):
|
||||
"""Recreation exception if scenario ids different than predictor."""
|
||||
|
@ -721,10 +719,9 @@ class RecreationRegressionTests(unittest.TestCase):
|
|||
SAMPLE_DATA, 'predictors_data_missing.csv')
|
||||
scenario_table_path = os.path.join(
|
||||
SAMPLE_DATA, 'predictors_wrong_projection.csv')
|
||||
|
||||
with self.assertRaises(ValueError):
|
||||
self.assertIsNotNone(
|
||||
recmodel_client._validate_same_ids_and_types(
|
||||
base_table_path, scenario_table_path)
|
||||
base_table_path, scenario_table_path))
|
||||
|
||||
def test_delay_op(self):
|
||||
"""Recreation coverage of delay op function."""
|
||||
|
@ -833,7 +830,6 @@ class RecreationRegressionTests(unittest.TestCase):
|
|||
|
||||
with open(predictor_target_path, 'r') as file:
|
||||
data = json.load(file)
|
||||
print(data)
|
||||
actual_value = list(data.values())[0]
|
||||
expected_value = 1
|
||||
self.assertEqual(actual_value, expected_value)
|
||||
|
@ -984,9 +980,8 @@ class RecreationRegressionTests(unittest.TestCase):
|
|||
'results_suffix': '',
|
||||
'workspace_dir': self.workspace_dir,
|
||||
}
|
||||
|
||||
with self.assertRaises(ValueError):
|
||||
recmodel_client.execute(args)
|
||||
msgs = recmodel_client.validate(args)
|
||||
self.assertIn('more than 10 characters long', msgs[0][1])
|
||||
|
||||
def test_existing_output_shapefiles(self):
|
||||
"""Recreation grid test when output files need to be overwritten."""
|
||||
|
@ -1125,9 +1120,9 @@ class RecreationRegressionTests(unittest.TestCase):
|
|||
SAMPLE_DATA, 'predictors_scenario.csv'),
|
||||
'workspace_dir': self.workspace_dir,
|
||||
}
|
||||
|
||||
with self.assertRaises(ValueError):
|
||||
recmodel_client.execute(args)
|
||||
msgs = recmodel_client.validate(args)
|
||||
self.assertEqual(
|
||||
'Start year must be less than or equal to end year.', msgs[0][1])
|
||||
|
||||
def test_bad_grid_type(self):
|
||||
"""Recreation ensure that bad grid type raises ValueError."""
|
||||
|
@ -1341,11 +1336,8 @@ class RecreationValidationTests(unittest.TestCase):
|
|||
'predictor_table_path': bad_table_path,
|
||||
'workspace_dir': self.workspace_dir,
|
||||
}
|
||||
|
||||
with self.assertRaises(ValueError) as cm:
|
||||
recmodel_client.execute(args)
|
||||
self.assertTrue('The table contains invalid type value(s)' in
|
||||
str(cm.exception))
|
||||
msgs = recmodel_client.validate(args)
|
||||
self.assertIn('The table contains invalid type value(s)', msgs[0][1])
|
||||
|
||||
|
||||
def _assert_regression_results_eq(
|
||||
|
|
|
@ -59,23 +59,6 @@ class RouteDEMTests(unittest.TestCase):
|
|||
dem_raster.SetGeoTransform(dem_geotransform)
|
||||
dem_raster = None
|
||||
|
||||
def test_routedem_invalid_algorithm(self):
|
||||
"""RouteDEM: fail when the algorithm isn't recognized."""
|
||||
from natcap.invest import routedem
|
||||
args = {
|
||||
'workspace_dir': self.workspace_dir,
|
||||
'algorithm': 'invalid',
|
||||
'dem_path': os.path.join(self.workspace_dir, 'dem.tif'),
|
||||
'results_suffix': 'foo',
|
||||
'calculate_flow_direction': True,
|
||||
}
|
||||
|
||||
RouteDEMTests._make_dem(args['dem_path'])
|
||||
with self.assertRaises(RuntimeError) as cm:
|
||||
routedem.execute(args)
|
||||
|
||||
self.assertTrue('Invalid algorithm specified' in str(cm.exception))
|
||||
|
||||
def test_routedem_no_options_default_band(self):
|
||||
"""RouteDEM: default to band 1 when not specified."""
|
||||
from natcap.invest import routedem
|
||||
|
|
|
@ -225,38 +225,6 @@ class ScenicQualityTests(unittest.TestCase):
|
|||
quality_matrix,
|
||||
rtol=0, atol=1e-6)
|
||||
|
||||
def test_invalid_valuation_function(self):
|
||||
"""SQ: model raises exception with invalid valuation function."""
|
||||
from natcap.invest.scenic_quality import scenic_quality
|
||||
|
||||
dem_path = os.path.join(self.workspace_dir, 'dem.tif')
|
||||
ScenicQualityTests.create_dem(dem_path)
|
||||
|
||||
viewpoints_path = os.path.join(self.workspace_dir,
|
||||
'viewpoints.geojson')
|
||||
ScenicQualityTests.create_viewpoints(viewpoints_path)
|
||||
|
||||
aoi_path = os.path.join(self.workspace_dir, 'aoi.geojson')
|
||||
ScenicQualityTests.create_aoi(aoi_path)
|
||||
|
||||
args = {
|
||||
'workspace_dir': os.path.join(self.workspace_dir, 'workspace'),
|
||||
'results_suffix': 'foo',
|
||||
'aoi_path': aoi_path,
|
||||
'structure_path': viewpoints_path,
|
||||
'dem_path': dem_path,
|
||||
'refraction': 0.13,
|
||||
'do_valuation': True,
|
||||
'valuation_function': 'INVALID FUNCTION',
|
||||
'a_coef': 1,
|
||||
'b_coef': 0,
|
||||
'max_valuation_radius': 10.0,
|
||||
'n_workers': -1,
|
||||
}
|
||||
|
||||
with self.assertRaises(ValueError):
|
||||
scenic_quality.execute(args)
|
||||
|
||||
def test_error_invalid_viewpoints(self):
|
||||
"""SQ: error when no valid viewpoints.
|
||||
|
||||
|
|
|
@ -297,13 +297,6 @@ class UFRMTests(unittest.TestCase):
|
|||
self.assertEqual(len(aoi_damage_dict), 1)
|
||||
numpy.testing.assert_allclose(aoi_damage_dict[0], 5645.787282992962)
|
||||
|
||||
def test_ufrm_invalid_validation(self):
|
||||
"""UFRM: assert validation error on bad args."""
|
||||
from natcap.invest import urban_flood_risk_mitigation
|
||||
|
||||
with self.assertRaises(ValueError):
|
||||
urban_flood_risk_mitigation.execute({})
|
||||
|
||||
def test_validate(self):
|
||||
"""UFRM: test validate function."""
|
||||
from natcap.invest import urban_flood_risk_mitigation
|
||||
|
|
|
@ -807,22 +807,6 @@ class UNATests(unittest.TestCase):
|
|||
[polygon_1, polygon_2, polygon_3], vector_path, wkt, 'GeoJSON')
|
||||
self.assertTrue(urban_nature_access._geometries_overlap(vector_path))
|
||||
|
||||
def test_invalid_search_radius_mode(self):
|
||||
"""UNA: Assert an exception when invalid radius mode provided."""
|
||||
from natcap.invest import urban_nature_access
|
||||
|
||||
args = _build_model_args(self.workspace_dir)
|
||||
args['search_radius_mode'] = 'some invalid mode'
|
||||
|
||||
with self.assertRaises(ValueError) as cm:
|
||||
urban_nature_access.execute(args)
|
||||
|
||||
self.assertIn('Invalid search radius mode provided', str(cm.exception))
|
||||
for mode_suffix in ('UNIFORM', 'URBAN_NATURE', 'POP_GROUP'):
|
||||
valid_mode_string = getattr(urban_nature_access,
|
||||
f'RADIUS_OPT_{mode_suffix}')
|
||||
self.assertIn(valid_mode_string, str(cm.exception))
|
||||
|
||||
def test_square_pixels(self):
|
||||
"""UNA: Assert we can make square pixels as expected."""
|
||||
from natcap.invest import urban_nature_access
|
||||
|
|
|
@ -723,7 +723,7 @@ class WindEnergyRegressionTests(unittest.TestCase):
|
|||
os.path.join(REGRESSION_DATA, 'priceval', vector_path))
|
||||
|
||||
def test_field_error_missing_bio_param(self):
|
||||
"""WindEnergy: test that ValueError raised when missing bio param."""
|
||||
"""WindEnergy: test that validation catches missing bio param."""
|
||||
from natcap.invest import wind_energy
|
||||
|
||||
# for testing raised exceptions, running on a set of data that was
|
||||
|
@ -749,7 +749,7 @@ class WindEnergyRegressionTests(unittest.TestCase):
|
|||
}
|
||||
|
||||
# creating a stand in turbine parameter csv file that is missing
|
||||
# the 'cut_out_wspd' entry. This should raise the exception
|
||||
# the 'cut_out_wspd' entry.
|
||||
tmp, file_path = tempfile.mkstemp(
|
||||
suffix='.csv', dir=args['workspace_dir'])
|
||||
os.close(tmp)
|
||||
|
@ -760,10 +760,11 @@ class WindEnergyRegressionTests(unittest.TestCase):
|
|||
_create_vertical_csv(data, file_path)
|
||||
args['turbine_parameters_path'] = file_path
|
||||
|
||||
self.assertRaises(ValueError, wind_energy.execute, args)
|
||||
validation_messages = wind_energy.validate(args)
|
||||
self.assertEqual(len(validation_messages), 1)
|
||||
|
||||
def test_time_period_exception(self):
|
||||
"""WindEnergy: raise ValueError if 'time' and 'wind_sched' differ."""
|
||||
"""WindEnergy: validation message if 'time' and 'wind_sched' differ."""
|
||||
from natcap.invest import wind_energy
|
||||
|
||||
# for testing raised exceptions, running on a set of data that was
|
||||
|
@ -815,8 +816,8 @@ class WindEnergyRegressionTests(unittest.TestCase):
|
|||
}
|
||||
_create_vertical_csv(data, file_path)
|
||||
args['global_wind_parameters_path'] = file_path
|
||||
|
||||
self.assertRaises(ValueError, wind_energy.execute, args)
|
||||
validation_messages = wind_energy.validate(args)
|
||||
self.assertEqual(len(validation_messages), 1)
|
||||
|
||||
def test_clip_vector_value_error(self):
|
||||
"""WindEnergy: Test AOI doesn't intersect Wind Data points."""
|
||||
|
|
Loading…
Reference in New Issue