def test_serialise_and_deserialise_map_recipe(self): recipes_fixtures = [ fixtures.recipe_with_positive_iso3_code, fixtures.recipe_result_one_dataset_per_layer_windows, fixtures.recipe_without_positive_iso3_code ] with mock.patch( 'mapactionpy_controller.map_recipe.path.exists') as mock_path: mock_path.return_value = True for fixture_str in recipes_fixtures: test_recipe = MapRecipe(fixture_str, self.lyr_props) self.assertEqual( test_recipe, jsonpickle.decode(jsonpickle.encode(test_recipe))) self.assertEqual( test_recipe, MapRecipe( jsonpickle.encode(test_recipe, unpicklable=False), self.lyr_props)) self.assertNotEqual( test_recipe, MapRecipe(fixtures.recipe_with_negative_iso3_code, self.lyr_props))
def test_apply_frame_crs_and_extent(self): """ Because the test can't assume what starting extent the mxd is, the test applies to different extents as checks that the mxd changes. """ recipe = MapRecipe(fixtures.fixture_recipe_minimal, self.layer_props) recipe_frame = recipe.get_frame(recipe.principal_map_frame) my_mxd = arcpy.mapping.MapDocument(self.my_mxd_fpath) arc_frame = arcpy.mapping.ListDataFrames( my_mxd, recipe.principal_map_frame).pop() mc = MapChef(my_mxd, self.cmf, self.event) # Approximations of Lebanon in WGS1984 and Web Mercator # Case 1 - approx Lebanon in WGS1984 # Case 2 - Lebanon in Web Mercator # Case 3 - Very tall and narrow, the height will dominate the extent # Case 4 - Very flat and wide, the width will dominate the extent sample_extents = [('epsg:4326', 35, 33, 36, 34), ('epsg:3857', 3907702.338605, 3902606.144123, 4076844.286459, 4122112.913080), ('epsg:4326', 1, -70, 2, 70), ('epsg:4326', -170, -2, 170, -1)] for extent_def in sample_extents: crs, x_min, y_min, x_max, y_max = extent_def recipe_frame.crs = crs recipe_frame.extent = (x_min, y_min, x_max, y_max) mc.apply_frame_crs_and_extent(arc_frame, recipe_frame) # Either the height will approx match but the width probably won't # OR the width with approx match but the height probably won't target_height = y_max - y_min target_width = x_max - x_min actual_height = arc_frame.extent.YMax - arc_frame.extent.YMin actual_width = arc_frame.extent.XMax - arc_frame.extent.XMin print( 'target_height, target_width, actual_height, actual_width = ') print(target_height, target_width, actual_height, actual_width) # Aim for with 1% tolerance for one or the two dimensions tolerance = 0.01 passable_height = ((target_height * (1 + tolerance)) > actual_height and (target_height * (1 - tolerance)) < actual_height) passable_width = ((target_width * (1 + tolerance)) > actual_width and (target_width * (1 - tolerance)) < actual_width) print('passable_height = {}'.format(passable_height)) print('passable_width = {}'.format(passable_width)) self.assertTrue(any((passable_height, passable_width)))
def test_map_recipe_with_artbitary_principal_frame_name(self): # Test cases where the principal map frame is not called "Main map" # This should load without error MapRecipe(fixtures.recipe_with_non_standard_principal_map_frame_name, self.lyr_props) # This should raise a ValueError with self.assertRaises(ValueError): MapRecipe(fixtures.recipe_with_invalid_principal_map_frame_name, self.lyr_props)
def test_get_atlas(self): recipe_def = json.loads(fixtures.recipe_with_positive_iso3_code) test_recipe = MapRecipe(recipe_def, self.lyr_props) self.assertTrue(test_recipe.contains_frame('Main map')) self.assertFalse(test_recipe.contains_frame('not-existant')) lyr = test_recipe.get_frame('Main map') self.assertIsInstance(lyr, RecipeFrame) self.assertRaises(ValueError, test_recipe.get_frame, 'not-existant')
def test_check_layer(self): recipe = MapRecipe(fixtures.recipe_with_layer_details_embedded, self.lyr_props) lyr = recipe.all_layers().pop() # This will pass silently if the lyr is of the right type self.assertIsNone(data_search._check_layer(lyr)) # This case should raise a ValueError with self.assertRaises(ValueError): data_search._check_layer('string-to-represent-a-layer')
def test_atlas_get_layer(self): recipe_def = json.loads(fixtures.recipe_with_positive_iso3_code) test_recipe = MapRecipe(recipe_def, self.lyr_props) atlas = test_recipe.get_frame('Main map') self.assertTrue(atlas.contains_layer('mainmap_stle_stl_pt_s0_allmaps')) self.assertFalse(atlas.contains_layer('not-existant')) lyr = atlas.get_layer('mainmap_stle_stl_pt_s0_allmaps') self.assertIsInstance(lyr, RecipeLayer) self.assertRaises(ValueError, atlas.get_layer, 'not-existant')
def test_calc_data_source_checksum(self): test_recipe = MapRecipe(fixtures.recipe_with_layer_name_only, self.lyr_props) test_lyr = test_recipe.all_layers().pop() # Use a simple test shapefile test_lyr.data_source_path = os.path.join( self.parent_dir, 'tests', 'testfiles', 'test_shp_files', 'lbn_admn_ad0_py_s1_pp_cdr.shp') actual_has_of_shp_file = test_lyr._calc_data_source_checksum() expected_hash_of_shp_file = '1acb212b47c8ccb3006ae9b4c5f1cfc0' self.assertEqual(actual_has_of_shp_file, expected_hash_of_shp_file)
def test_calc_layer_file_checksum(self): test_recipe = MapRecipe(fixtures.recipe_with_layer_name_only, self.lyr_props) test_lyr = test_recipe.all_layers().pop() # This is an empty .lyr file test_lyr.layer_file_path = os.path.join( self.parent_dir, 'tests', 'testfiles', 'test_layer_rendering', 'four_files_exact_match', 'locationmap_stle_stl_pt_s0_locationmaps.lyr') test_lyr._calc_layer_file_checksum() hash_of_empty_str = 'd41d8cd98f00b204e9800998ecf8427e' self.assertEqual(test_lyr.layer_file_checksum, hash_of_empty_str)
def test_map_recipe_backward_compat(self): # This is required in order to get hold of a recipe object. This is because the method being # tested is a member of the class. recipe_obj = MapRecipe(fixtures.recipe_with_layer_name_only, self.lyr_props) test_cases = [(fixtures.recipe_schema_v2_0_with_layer_name_only, 0.2), (fixtures.recipe_with_layer_name_only, 0.3)] for recipe_str, expected_result in test_cases: recipe_def = json.loads(recipe_str) self.assertEqual( recipe_obj._check_schemas_with_backward_compat(recipe_def), expected_result)
def test_equality_of_map_recipes(self): recipe_def = json.loads(fixtures.recipe_with_positive_iso3_code) test_recipe1 = MapRecipe(recipe_def, self.lyr_props) test_recipe2 = MapRecipe(recipe_def, self.lyr_props) self.assertEqual(test_recipe1, test_recipe2) test_recipe1.summary = "something different" self.assertNotEqual(test_recipe1, test_recipe2) test_recipe3 = MapRecipe(recipe_def, self.lyr_props) self.assertEqual(test_recipe2, test_recipe3) # Remove an arbitary layer from each Map Frame for m_frames in test_recipe3.map_frames: m_frames.layers.pop() self.assertNotEqual(test_recipe2, test_recipe3)
def test_get_aspect_ratios_of_templates(self, mock_ListDataFrames, mock_MapDocument): mock_MapDocument.return_value = None df_lists = [[self.df1], [self.df2], [self.df3], [self.df4], [self.df5], [self.df6]] mock_ListDataFrames.side_effect = df_lists tmpl_paths = repeat('/the/path', len(df_lists)) tmpl_paths = ['/the/path{}'.format(n) for n in range(1, 7)] test_lp = LayerProperties(self.cmf, '.lyr') test_recipe = MapRecipe(fixtures.fixture_recipe_minimal, test_lp) expected_result = [ ('/the/path1', float(self.df1.elementWidth) / self.df1.elementHeight), ('/the/path2', float(self.df2.elementWidth) / self.df2.elementHeight), ('/the/path3', float(self.df3.elementWidth) / self.df3.elementHeight), ('/the/path4', float(self.df4.elementWidth) / self.df4.elementHeight), ('/the/path5', float(self.df5.elementWidth) / self.df5.elementHeight), ('/the/path6', float(self.df6.elementWidth) / self.df6.elementHeight) ] actual_result = self.arcmap_runner.get_aspect_ratios_of_templates( tmpl_paths, test_recipe) self.assertEqual(actual_result, expected_result)
def test_map_chef_cook(self): my_mxd = arcpy.mapping.MapDocument(self.my_mxd_fpath) mc = MapChef(my_mxd, self.cmf, self.event) test_recipe = MapRecipe( fixtures.fixture_recipe_processed_by_controller, self.layer_props) mc.cook(test_recipe) self.assertTrue(True)
def _parse_json_file(self): """ Reads product "recipes" from Map Cookbook json file """ with open(self.cookbook_json_file) as json_file: jsonContents = json.load(json_file) for recipe in jsonContents['recipes']: rec = MapRecipe(recipe, self.layer_props, self.hum_event) self.products[recipe['product']] = rec
def test_substitute_fields_in_recipe_strings(self): recipe_updater = data_search.get_recipe_event_updater(self.event) # An example with an iso code within a positive regex lookup # (eg '^{e.affected_country_iso3}_stle.....') reference_recipe = MapRecipe( fixtures.recipe_with_positive_iso3_code, self.lyr_props) pos_recipe = MapRecipe( fixtures.recipe_without_positive_iso3_code, self.lyr_props) updated_pos_recipe = recipe_updater(state=pos_recipe) self.assertEqual(updated_pos_recipe, reference_recipe) # An example with an iso code within a negitive regex lookup # (eg '^(?!({e.affected_country_iso3}))_admn.....') reference_recipe = MapRecipe( fixtures.recipe_with_negative_iso3_code, self.lyr_props) neg_recipe = MapRecipe( fixtures.recipe_without_negative_iso3_code, self.lyr_props) recipe_updater = data_search.get_recipe_event_updater(self.event) updated_neg_recipe = recipe_updater(state=neg_recipe) self.assertEqual(updated_neg_recipe, reference_recipe) # Reverse of the first example to test a case where nothing needs updating. In this case the same json # definition is used for both recipes. There are not string replacement fields within the json definition. reference_recipe = MapRecipe( fixtures.recipe_with_positive_iso3_code, self.lyr_props) pos_recipe = MapRecipe( fixtures.recipe_with_positive_iso3_code, self.lyr_props) updated_pos_recipe = recipe_updater(state=pos_recipe) self.assertEqual(updated_pos_recipe, reference_recipe)
def test_verify_layer_file_path(self): """ Test the case that a recipe is re-stored with the layer_file_paths already populated, and whether or not that path is valid. """ fail_msg = 'The expected layer file' with self.assertRaises(ValueError) as arcm: MapRecipe(fixtures.recipe_with_invalid_layer_file_path, self.lyr_props) if six.PY2: self.assertRegexpMatches(str(arcm.exception), fail_msg) else: self.assertRegex(str(arcm.exception), fail_msg)
def test_check_lyr_is_in_recipe(self): """ Check that an error is raised if any `step.funcs` attempt to act on a layer object that isn't part of the relevant recipe object. """ # Two recipes without a common layer recipe_A = MapRecipe(fixtures.recipe_with_layer_name_only, self.lyr_props) recipe_B = MapRecipe(fixtures.recipe_with_positive_iso3_code, self.lyr_props) test_lyr = recipe_A.all_layers().pop() # This should pass without error test_lyr._check_lyr_is_in_recipe(recipe_A) # This should fail because test_lyr is not from recipe_B fail_msg = 'which is not part of the recipe' with self.assertRaises(ValueError) as arcm: test_lyr._check_lyr_is_in_recipe(recipe_B) if six.PY2: self.assertRegexpMatches(str(arcm.exception), fail_msg) else: self.assertRegex(str(arcm.exception), fail_msg)
def test_calc_extent(self): test_recipe = MapRecipe(fixtures.recipe_with_layer_name_only, self.lyr_props) test_lyr = test_recipe.all_layers().pop() # Use a simple test shapefile test_lyr.data_source_path = os.path.join( self.parent_dir, 'tests', 'testfiles', 'test_shp_files', 'lbn_admn_ad0_py_s1_pp_cdr.shp') # Get the extents shapefile and update the test_lyr object test_lyr.calc_extent(state=test_recipe) expected_extent = [35.10348736558511, 33.054996785738204, 36.62291533501688, 34.69206915371] # expected_crs = ( # 'GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",' # 'SPHEROID["WGS_1984",6378137.0,298.257223563]],' # 'PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]]') # expected_crs = {'init': 'epsg:4326'} expected_crs = 'epsg:4326' for actual, expected in zip(test_lyr.extent, expected_extent): self.assertEqual(actual, expected) self.assertEqual(test_lyr.crs, expected_crs)
def test_load_recipe_with_layer_props_inc(self): # Test that a MapRecipe read form json with only a layername, combined with the # relevant LayerProperties is equal to a MapRecipe with all of the layerdetails embeded. # layerpros with cmf = CrashMoveFolder( os.path.join(self.parent_dir, 'example', 'cmf_description_relative_paths_test.json')) cmf.layer_properties = os.path.join( self.parent_dir, 'tests', 'testfiles', 'cookbooks', 'fixture_layer_properties_for_atlas.json') test_lp = LayerProperties(cmf, ".lyr", verify_on_creation=False) # recipe with layer name only recipe1 = MapRecipe(fixtures.recipe_with_layer_name_only, test_lp) # combined recipe with layer props recipe2 = MapRecipe(fixtures.recipe_with_layer_details_embedded, test_lp) self.assertEqual(recipe1, recipe2) # 2) with non-matching layer props schema recipe3 = MapRecipe(fixtures.recipe_with_positive_iso3_code, test_lp) self.assertNotEqual(recipe1, recipe3)
def setUp(self): self.parent_dir = os.path.dirname( os.path.dirname(os.path.realpath(__file__))) self.cmf_descriptor_path = os.path.join( self.parent_dir, 'example', 'cmf_description_flat_test.json') self.cmf = CrashMoveFolder(self.cmf_descriptor_path, verify_on_creation=False) self.event_descriptor_path = os.path.join(self.parent_dir, 'example', 'event_description.json') self.event = Event(self.event_descriptor_path) # self.cmf = CrashMoveFolder(self.cmf_descriptor_path) self.lyr_props = LayerProperties(self.cmf, '', verify_on_creation=False) self.recipe_descriptor_path = os.path.join( self.parent_dir, 'example', 'example_single_map_recipe.json') with open(self.recipe_descriptor_path) as json_file: self.recipe_def = json.load(json_file) self.recipe = MapRecipe(self.recipe_def, self.lyr_props)
def test_filter_lyr_for_use_in_frame_extent(self): # Have included the digit at the start of the string, so that can be sorted easily. cmf = CrashMoveFolder( os.path.join(self.parent_dir, 'example', 'cmf_description_relative_paths_test.json')) cmf.layer_properties = os.path.join( self.parent_dir, 'tests', 'testfiles', 'cookbooks', 'fixture_layer_properties_for_atlas.json') test_lp = LayerProperties(cmf, ".lyr", verify_on_creation=False) # recipe with layer name only with open( os.path.join( self.parent_dir, 'tests', 'testfiles', 'fixture_cookbook_1map_5layers_1frame.json')) as rf: cookbook_def = json.load(rf) # get the first (only) recipe in the cookbook recipe_def = cookbook_def['recipes'].pop() generic_lyr_def = json.loads('''{ "name": "the_name", "reg_exp": "^wrl_admn_ad0_py_(.*?)_(.*?)_([phm][phm])(.+)shp$", "schema_definition": "admin1_reference.yml", "definition_query": "", "display": true, "add_to_legend": true, "label_classes": [] }''') # Case 1 # test white list test_white_list1 = [('1a', True), ('1b', False), ('1c', None), ('1d', True), ('1e', False)] expected_white_result1 = ['1a', '1d'] test_white_list2 = [('2a', True), ('2b', None), ('2c', None), ('2d', True), ('2e', None)] expected_white_result2 = ['2a', '2d'] # Case 2 # Black List test_black_list = [('3a', None), ('3b', False), ('3c', None), ('3d', None), ('3e', False)] expected_black_result = ['3a', '3c', '3d'] # Case 3 # Default test_default_list = [('4a', None), ('4b', None), ('4c', None), ('4d', None), ('4e', None)] expected_default_result = ['4a', '4b', '4c', '4d', '4e'] all_test_params = [(test_white_list1, expected_white_result1), (test_white_list2, expected_white_result2), (test_black_list, expected_black_result), (test_default_list, expected_default_result)] for test_list, expected_result in all_test_params: test_recipe = MapRecipe(recipe_def, test_lp) # Build up a mock list of layer to test replacement_lyrs = [] for test_lyr_details in test_list: new_lyr = RecipeLayer(generic_lyr_def, test_lp, verify_on_creation=False) new_lyr.name = test_lyr_details[0] new_lyr.use_for_frame_extent = test_lyr_details[1] # vaugely near Lebanon new_lyr.extent = (35, 33, 36, 34) new_lyr.crs = 'epsg:4326' replacement_lyrs.append(new_lyr) test_frame = test_recipe.map_frames.pop() test_frame.layers = replacement_lyrs result_lyrs = test_frame._filter_lyr_for_use_in_frame_extent() actual_result = [lyr.name for lyr in result_lyrs] self.assertEqual(actual_result, expected_result)
def test_get_schema_checker(self): test_recipe = MapRecipe(fixtures.recipe_with_layer_name_only, self.lyr_props) test_lyr = test_recipe.all_layers().pop() # Use a simple test shapefile test_lyr.data_source_path = os.path.join( self.parent_dir, 'tests', 'testfiles', 'test_shp_files', 'lbn_admn_ad0_py_s1_pp_cdr.shp') passing_schema = yaml.safe_load(r""" required: - admin0Name - admin0Na_1 - admin0Pcod - admin0RefN - admin0AltN properties: geometry_type: items: enum: - MultiPolygon - Polygon additionalItems: false additionalItems: true """) incorrect_geom_schema = yaml.safe_load(r""" required: - admin0Name - admin0Na_1 - admin0Pcod - admin0RefN - admin0AltN properties: geometry_type: items: enum: - Point additionalItems: false additionalItems: true """) incorrect_columns_schema = yaml.safe_load(r""" required: - county_name, - parish_name properties: geometry_type: items: enum: - MultiPolygon - Polygon additionalItems: false additionalItems: true """) incorrect_columns_and_geom_schema = yaml.safe_load(r""" required: - county_name, - parish_name properties: geometry_type: items: enum: - Point additionalItems: false additionalItems: true """) # Case where data matches schema for test_schema in [passing_schema]: test_lyr.data_schema = test_schema result = test_lyr.check_data_against_schema(state=test_recipe) self.assertTrue(result) # Cases where data doesn't match schema for test_schema in [incorrect_geom_schema, incorrect_columns_schema, incorrect_columns_and_geom_schema]: test_lyr.data_schema = test_schema with self.assertRaises(ValueError) as arcm: test_lyr.check_data_against_schema(state=test_recipe) ve = arcm.exception self.assertIsInstance(ve.args[0], recipe_layer.FixSchemaErrorTask) # test a logger is call for case where a raster layer is tested. This unittest # is only available for py3.4+, though the production code is required for py2.7 if six.PY3: test_lyr.data_source_path = os.path.join( self.parent_dir, 'tests', 'testfiles', 'test_shp_files', 'lbn_evel_dem_ras_s1_pp_cdr.tif') test_lyr.data_schema = passing_schema with self.assertLogs(level='INFO') as cm: result = test_lyr.check_data_against_schema(state=test_recipe) print('cm.output = {}'.format(cm.output)) self.assertRegexpMatches( cm.output.pop(), 'Unable to check schema on for data sources which aren.t shapefiles' )
def test_layer_data_schema(self): null_schema = True passing_schema = yaml.safe_load(r""" required: - name_en properties: geometry_type: items: enum: - MultiPolygon - Polygon additionalItems: false crs: items: enum: - EPSG:2090 additionalItems: false """) # Note the missing `enum` blocks failing_schema = yaml.safe_load(r""" required: - name_en properties: geometry_type: items: - MultiPolygon - Polygon additionalItems: false crs: items: - EPSG:2090 additionalItems: false """) cmf = CrashMoveFolder( os.path.join(self.parent_dir, 'example', 'cmf_description_relative_paths_test.json')) cmf.layer_properties = os.path.join( self.parent_dir, 'tests', 'testfiles', 'cookbooks', 'fixture_layer_properties_for_atlas.json' ) # Two cases where data schema is valid yaml for test_schema in [null_schema, passing_schema]: with mock.patch('mapactionpy_controller.data_schemas.yaml.safe_load') as mock_safe_load: mock_safe_load.return_value = test_schema test_lp = LayerProperties(cmf, ".lyr", verify_on_creation=False) MapRecipe(fixtures.recipe_with_positive_iso3_code, test_lp) self.assertTrue(True, 'validated jsonschema') # case where data schema file itself malformed somehow with mock.patch('mapactionpy_controller.data_schemas.yaml.safe_load') as mock_safe_load: mock_safe_load.return_value = failing_schema self.assertRaises( jsonschema.exceptions.SchemaError, MapRecipe, fixtures.recipe_with_positive_iso3_code, test_lp )
def test_search_for_shapefiles(self): # ds = data_search.DataSearch(self.event) with mock.patch('mapactionpy_controller.data_search.glob.glob') as mock_glob: # We use two different mock values becuase we are matching absolute paths as strings # The underlying production code does not differencate between platforms. if platform.system() == 'Windows': mock_single_file_glob = fixtures.glob_single_stle_file_search_windows mock_multiple_file_glob = fixtures.glob_multiple_stle_file_search_windows mock_no_file_glob = fixtures.glob_no_stle_file_search_windows ref_recipe_str = fixtures.recipe_result_one_dataset_per_layer_windows else: mock_single_file_glob = fixtures.glob_single_stle_file_search_linux mock_multiple_file_glob = fixtures.glob_multiple_stle_file_search_linux mock_no_file_glob = fixtures.glob_no_stle_file_search_linux ref_recipe_str = fixtures.recipe_result_one_dataset_per_layer_linux reference_recipe = MapRecipe(ref_recipe_str, self.lyr_props) # Case A # where there is exactly one dataset per query test_recipe = MapRecipe(fixtures.recipe_test_for_search_for_shapefiles, self.lyr_props) mock_glob.return_value = mock_single_file_glob all_gis_files = [(f_path, os.path.basename(f_path)) for f_path in data_search.get_all_gisfiles(self.cmf)] self.assertNotEqual(test_recipe, reference_recipe) # get the first layer from the test_recipe test_lyr = test_recipe.all_layers().pop() data_finder = test_lyr.get_data_finder(self.cmf, all_gis_files) updated_test_recipe = data_finder(state=test_recipe) self.assertEqual(updated_test_recipe, test_recipe) self.assertTrue(updated_test_recipe == test_recipe) self.assertEqual(updated_test_recipe, reference_recipe) # Case B # where there is multiple matching datasets test_recipe = MapRecipe(fixtures.recipe_test_for_search_for_shapefiles, self.lyr_props) mock_glob.return_value = mock_multiple_file_glob all_gis_files = [(f_path, os.path.basename(f_path)) for f_path in data_search.get_all_gisfiles(self.cmf)] self.assertNotEqual(test_recipe, reference_recipe) # get the first layer from the test_recipe test_lyr = test_recipe.all_layers().pop() data_finder = test_lyr.get_data_finder(self.cmf, all_gis_files) with self.assertRaises(ValueError) as arcm: updated_test_recipe = data_finder(state=test_recipe) ve = arcm.exception print('ve.args[0] is instance of: {}'.format(type(ve.args[0]))) self.assertIsInstance(ve.args[0], recipe_layer.FixMultipleMatchingFilesTask) # Case C # where there are no matching datasets test_recipe = MapRecipe(fixtures.recipe_test_for_search_for_shapefiles, self.lyr_props) mock_glob.return_value = mock_no_file_glob all_gis_files = [(f_path, os.path.basename(f_path)) for f_path in data_search.get_all_gisfiles(self.cmf)] self.assertNotEqual(test_recipe, reference_recipe) # get the first layer from the test_recipe test_lyr = test_recipe.all_layers().pop() data_finder = test_lyr.get_data_finder(self.cmf, all_gis_files) with self.assertRaises(ValueError) as arcm: updated_test_recipe = data_finder(state=test_recipe) ve = arcm.exception print('ve.args[0] is instance of: {}'.format(type(ve.args[0]))) self.assertIsInstance(ve.args[0], recipe_layer.FixMissingGISDataTask) # Case D # Case insensitive search. Like Case A, but we force the regex itself into upper and lower case. test_recipe = MapRecipe(fixtures.recipe_test_for_search_for_shapefiles, self.lyr_props) mock_glob.return_value = mock_single_file_glob all_gis_files = [(f_path, os.path.basename(f_path)) for f_path in data_search.get_all_gisfiles(self.cmf)] self.assertNotEqual(test_recipe, reference_recipe) # get the first layer from the test_recipe test_lyr = test_recipe.all_layers().pop() for new_reg_exp in [test_lyr.reg_exp.upper(), test_lyr.reg_exp.lower()]: # save the old Reg Exp in order to use to compare recipes later old_reg_exp = test_lyr.reg_exp test_lyr.reg_exp = new_reg_exp data_finder = test_lyr.get_data_finder(self.cmf, all_gis_files) updated_test_recipe = data_finder(state=test_recipe) # Now replace the origional reg_exp test_lyr.reg_exp = old_reg_exp self.assertEqual(updated_test_recipe, test_recipe) self.assertTrue(updated_test_recipe == test_recipe) self.assertEqual(updated_test_recipe, reference_recipe) # Case E # Check whether or not it is enforced that a regex is matches the beginning of the string or at any # point in the string. Simular to Case A test_recipe = MapRecipe(fixtures.recipe_test_for_search_for_shapefiles, self.lyr_props) mock_glob.return_value = mock_single_file_glob all_gis_files = [(f_path, os.path.basename(f_path)) for f_path in data_search.get_all_gisfiles(self.cmf)] self.assertNotEqual(test_recipe, reference_recipe) # get the first layer from the test_recipe test_lyr = test_recipe.all_layers().pop() # save the old Reg Exp in order to use to compare recipes later old_reg_exp = test_lyr.reg_exp # force an regex that doesn't have an anchor at the begining of the string, nor does it match the # beginning of the filename test_lyr.reg_exp = 'stle_ste_pt_(.*?)_(.*?)_([phm][phm])(.*?)' data_finder = test_lyr.get_data_finder(self.cmf, all_gis_files) updated_test_recipe = data_finder(state=test_recipe) # Now replace the origional reg_exp test_lyr.reg_exp = old_reg_exp self.assertEqual(updated_test_recipe, test_recipe) self.assertTrue(updated_test_recipe == test_recipe) self.assertEqual(updated_test_recipe, reference_recipe) # Case F # Check case where filesystem has case sensitive filenames, meaning that we could match on two # seperate files whose names only different by case. # Very simular to Case B test_recipe = MapRecipe(fixtures.recipe_test_for_search_for_shapefiles, self.lyr_props) mock_glob.return_value = fixtures.glob_multiple_stle_file_search_case_difference_linux all_gis_files = [(f_path, os.path.basename(f_path)) for f_path in data_search.get_all_gisfiles(self.cmf)] self.assertNotEqual(test_recipe, reference_recipe) # get the first layer from the test_recipe test_lyr = test_recipe.all_layers().pop() data_finder = test_lyr.get_data_finder(self.cmf, all_gis_files) with self.assertRaises(ValueError) as arcm: updated_test_recipe = data_finder(state=test_recipe) ve = arcm.exception self.assertIsInstance(ve.args[0], recipe_layer.FixMultipleMatchingFilesTask)
def test_get_map_frame_extents(self): cmf = CrashMoveFolder( os.path.join(self.parent_dir, 'example', 'cmf_description_relative_paths_test.json')) cmf.layer_properties = os.path.join( self.parent_dir, 'tests', 'testfiles', 'cookbooks', 'fixture_layer_properties_for_atlas.json') test_lp = LayerProperties(cmf, ".lyr", verify_on_creation=False) # recipe with layer name only with open( os.path.join( self.parent_dir, 'tests', 'testfiles', 'fixture_cookbook_1map_5layers_1frame.json')) as rf: cookbook_def = json.load(rf) # get the first (only) recipe in the cookbook recipe_def = cookbook_def['recipes'].pop() generic_lyr_def = json.loads('''{ "name": "the_name", "reg_exp": "^wrl_admn_ad0_py_(.*?)_(.*?)_([phm][phm])(.+)shp$", "schema_definition": "admin1_reference.yml", "definition_query": "", "display": true, "add_to_legend": true, "label_classes": [] }''') # Case 1 # One or more layers does not have it's extent defined case1_list = [('case1_lyrA', (35, 33, 36, 34), 'epsg:4326'), ('case1_lyrB', None, None)] case1_result = (35, 33, 36, 34) # Case 2 # Simple union with two lyrs of same crs case2_list = [('case2_lyrA', (33, 51, 36, 58), 'epsg:4326'), ('case2_lyrB', (15, 52, 35, 55), 'epsg:4326')] case2_result = (15, 51, 36, 58) # Case 3 # Union with two lyrs of with different crs # 'epsg:4326'== WGS1984, 'epsg:3785' == Web Mercator case3_list = [('case3_lyrA', (33, 51, 36, 58), 'epsg:4326'), ('case3_lyrB', (1669792.36, 6800125.45, 3896182.18, 7361866.11), 'epsg:3785')] case3_result = (15, 51, 36, 58) # Case 4 # One layer which stradles 180 degree meridian all_test_params = [(case1_list, case1_result), (case2_list, case2_result), (case3_list, case3_result)] for test_list, expected_result in all_test_params: test_recipe = MapRecipe(recipe_def, test_lp) # Build up a mock list of layer to test replacement_lyrs = [] for name, extent, crs in test_list: new_lyr = RecipeLayer(generic_lyr_def, test_lp, verify_on_creation=False) new_lyr.name = name new_lyr.use_for_frame_extent = bool(extent) # vaugely near Lebanon new_lyr.extent = extent new_lyr.crs = crs replacement_lyrs.append(new_lyr) # print('test_get_map_frame_extents') # print('expected_result = {}'.format(expected_result)) test_frame = test_recipe.map_frames.pop() test_frame.crs = 'epsg:4326' test_frame.layers = replacement_lyrs test_frame.calc_extent(state=test_recipe) actual_result = test_frame.extent # print('actual_result = {}'.format(actual_result)) for actual, expected in zip(actual_result, expected_result): self.assertAlmostEqual(actual, expected)
def main(args): args = parser.parse_args() event = Event(args.eventDescriptionFile) runner = ArcProRunner(event) recipe_without_positive_iso3_code = ('''{ "mapnumber": "MA001", "category": "Reference", "product": "DJI Overview Map", "summary": "Overview of DJI with topography displayed", "export": true, "template": "reference", "map_frames": [ { "name": "Main map", "layers": [ { "name": "mainmap-stle-stl-pt-s0-allmaps", "reg_exp": "^[a-z][a-z][a-z]_stle_stl_pt_(.*?)_(.*?)_([phm][phm])(.*?).shp$", "schema_definition": "stle_ste_pt.yml", "definition_query": "fclass IN ('national_capital', 'city', 'capital', 'town')", "display": true, "add_to_legend": true, "label_classes": [ { "class_name": "National Capital", "expression": "[name]", "sql_query": "('fclass' = 'national_capital')", "show_class_labels": true }, { "class_name": "Admin 1 Capital", "expression": "[name]", "sql_query": "('fclass' = 'town')", "show_class_labels": true } ] }, { "name": "mainmap-carto-fea-py-s0-allmaps", "reg_exp": "^[a-z][a-z][a-z]_carto_fea_py_(.*?)_(.*?)_([phm][phm])(.*?).shp$", "schema_definition": "null-schema.yml", "definition_query": "", "display": true, "add_to_legend": false, "label_classes": [] }, { "name": "mainmap-elev-cst-ln-s0-allmaps", "reg_exp": "^[a-z][a-z][a-z]_elev_cst_ln_(.*?)_(.*?)_([phm][phm])(.*?).shp$", "schema_definition": "null-schema.yml", "definition_query": "", "display": true, "add_to_legend": false, "label_classes": [] }, { "name": "mainmap-admn-ad0-ln-s0-reference", "reg_exp": "^[a-z][a-z][a-z]_admn_ad0_ln_(.*?)_(.*?)_([phm][phm])(.*?).shp$", "schema_definition": "null-schema.yml", "definition_query": "", "display": true, "add_to_legend": false, "label_classes": [] }, { "name": "mainmap-admn-ad1-ln-s0-reference", "reg_exp": "^[a-z][a-z][a-z]_admn_ad1_ln_(.*?)_(.*?)_([phm][phm])(.*?).shp$", "schema_definition": "admin1_reference.yml", "definition_query": "", "display": true, "add_to_legend": true, "label_classes": [] }, { "name": "mainmap-phys-riv-ln-s0-reference", "reg_exp": "^[a-z][a-z][a-z]_phys_riv_ln_(.*?)_(.*?)_([phm][phm])(.*?).shp$", "schema_definition": "null-schema.yml", "definition_query": "", "display": true, "add_to_legend": true, "label_classes": [] }, { "name": "mainmap-admn-ad1-py-s0-reference", "reg_exp": "^[a-z][a-z][a-z]_admn_ad1_py_(.*?)_(.*?)_([phm][phm])(.*?).shp$", "schema_definition": "admin1_reference.yml", "definition_query": "", "display": true, "add_to_legend": true, "label_classes": [] }, { "name": "mainmap-admn-ad0-ln-s0-surroundingcountries", "reg_exp": "^[a-z][a-z][a-z]_admn_ad0_ln_(.*?)_(.*?)_([phm][phm])(.*?).shp$", "schema_definition": "null-schema.yml", "definition_query": "", "display": true, "add_to_legend": true, "label_classes": [] } ] } ] }''') layerProperties = LayerProperties(event.cmf_descriptor_path, '.lyr', verify_on_creation=False) recipe = MapRecipe(recipe_without_positive_iso3_code, layerProperties) recipe = runner.get_templates(state=recipe) recipe = runner.create_ouput_map_project(state=recipe) recipe = runner.build_project_files(state=recipe) themes = set() themes.add("Health") propertiesDict = {} propertiesDict['themes'] = themes propertiesDict['accessnotes'] = "My super access note" recipe = runner.export_maps(state=recipe, properties=propertiesDict)
def test_get_templates(self): # Case 1 # Pre-existing valid `map_project_path` value expect_result = MapRecipe( fixtures.recipe_test_for_search_for_shapefiles, self.lyr_props) test_recipe = MapRecipe(fixtures.recipe_test_for_search_for_shapefiles, self.lyr_props) expect_result.map_project_path = '/path/that/exists.mxd' test_recipe.map_project_path = '/path/that/exists.mxd' with mock.patch('mapactionpy_controller.plugin_base.os.path.exists' ) as mock_path_exists: mock_path_exists.return_value = True actual_result = self.dummy_runner.get_templates(state=test_recipe) self.assertEqual(actual_result, expect_result) # Case 2 # Non-None `map_project_path` value which points of non-existing file test_recipe = MapRecipe(fixtures.recipe_test_for_search_for_shapefiles, self.lyr_props) test_recipe.map_project_path = '/path/that/does/not/exists.mxd' with mock.patch('mapactionpy_controller.plugin_base.os.path.exists' ) as mock_path_exists: mock_path_exists.return_value = False with self.assertRaises(ValueError): self.dummy_runner.get_templates(state=test_recipe) # Case 3 & 4 # mf.extent exists and has a valid value # mf.entent is None test_extents = [('one', (1, 1, 5, 5)), ('two', (1, 1, 9, 5)), ('one', None)] for expected_result, extent in test_extents: print(expected_result, extent) test_recipe = MapRecipe( fixtures.recipe_test_for_search_for_shapefiles, self.lyr_props) test_recipe.map_frames[0].extent = extent # mf.extent = extent actual_recipe = self.dummy_runner.get_templates(state=test_recipe) self.assertEquals(expected_result, actual_recipe.template_path)