def test_compressed_file_based_raster_creation(self): rstfile = tempfile.NamedTemporaryFile(suffix='.tif') # Make a compressed copy of an existing raster. compressed = self.rs.warp({ 'papsz_options': { 'compress': 'packbits' }, 'name': rstfile.name }) # Check physically if compression worked. self.assertLess(os.path.getsize(compressed.name), os.path.getsize(self.rs.name)) # Create file-based raster with options from scratch. compressed = GDALRaster({ 'datatype': 1, 'driver': 'tif', 'name': rstfile.name, 'width': 40, 'height': 40, 'srid': 3086, 'origin': (500000, 400000), 'scale': (100, -100), 'skew': (0, 0), 'bands': [{ 'data': range(40 ^ 2), 'nodata_value': 255, }], 'papsz_options': { 'compress': 'packbits', 'pixeltype': 'signedbyte', 'blockxsize': 23, 'blockysize': 23, } }) # Check if options used on creation are stored in metadata. # Reopening the raster ensures that all metadata has been written # to the file. compressed = GDALRaster(compressed.name) self.assertEqual( compressed.metadata['IMAGE_STRUCTURE']['COMPRESSION'], 'PACKBITS', ) self.assertEqual( compressed.bands[0].metadata['IMAGE_STRUCTURE']['PIXELTYPE'], 'SIGNEDBYTE') if GDAL_VERSION >= (2, 1): self.assertIn('Block=40x23', compressed.info)
def test_geotransform_and_friends(self): # Assert correct values for file based raster self.assertEqual( self.rs.geotransform, [511700.4680706557, 100.0, 0.0, 435103.3771231986, 0.0, -100.0]) self.assertEqual(self.rs.origin, [511700.4680706557, 435103.3771231986]) self.assertEqual(self.rs.origin.x, 511700.4680706557) self.assertEqual(self.rs.origin.y, 435103.3771231986) self.assertEqual(self.rs.scale, [100.0, -100.0]) self.assertEqual(self.rs.scale.x, 100.0) self.assertEqual(self.rs.scale.y, -100.0) self.assertEqual(self.rs.skew, [0, 0]) self.assertEqual(self.rs.skew.x, 0) self.assertEqual(self.rs.skew.y, 0) # Create in-memory rasters and change gtvalues rsmem = GDALRaster(JSON_RASTER) # geotransform accepts both floats and ints rsmem.geotransform = [0.0, 1.0, 2.0, 3.0, 4.0, 5.0] self.assertEqual(rsmem.geotransform, [0.0, 1.0, 2.0, 3.0, 4.0, 5.0]) rsmem.geotransform = range(6) self.assertEqual(rsmem.geotransform, [float(x) for x in range(6)]) self.assertEqual(rsmem.origin, [0, 3]) self.assertEqual(rsmem.origin.x, 0) self.assertEqual(rsmem.origin.y, 3) self.assertEqual(rsmem.scale, [1, 5]) self.assertEqual(rsmem.scale.x, 1) self.assertEqual(rsmem.scale.y, 5) self.assertEqual(rsmem.skew, [2, 4]) self.assertEqual(rsmem.skew.x, 2) self.assertEqual(rsmem.skew.y, 4) self.assertEqual(rsmem.width, 5) self.assertEqual(rsmem.height, 5)
def test_offset_size_and_shape_on_raster_creation(self): rast = GDALRaster({ 'datatype': 1, 'width': 4, 'height': 4, 'srid': 4326, 'bands': [{ 'data': (1, ), 'offset': (1, 1), 'size': (2, 2), 'shape': (1, 1), 'nodata_value': 2, }], }) # Get array from raster. result = rast.bands[0].data() if numpy: result = result.flatten().tolist() # Band data is equal to nodata value except on input block of ones. self.assertEqual(result, [2, 2, 2, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2, 2, 2, 2])
def test_raster_warp_nodata_zone(self): # Create in memory raster. source = GDALRaster({ 'datatype': 1, 'driver': 'MEM', 'width': 4, 'height': 4, 'srid': 3086, 'origin': (500000, 400000), 'scale': (100, -100), 'skew': (0, 0), 'bands': [{ 'data': range(16), 'nodata_value': 23, }], }) # Warp raster onto a location that does not cover any pixels of the original. result = source.warp({'origin': (200000, 200000)}).bands[0].data() if numpy: result = result.flatten().tolist() # The result is an empty raster filled with the correct nodata value. self.assertEqual(result, [23] * 16)
def setUp(self): rast = GDALRaster({ "srid": 4326, "origin": [0, 0], "scale": [-1, 1], "skew": [0, 0], "width": 5, "height": 5, "nr_of_bands": 2, "bands": [{ "data": range(25) }, { "data": range(25, 50) }], }) model_instance = RasterModel.objects.create( rast=rast, rastprojected=rast, geom="POINT (-95.37040 29.70486)", ) RasterRelatedModel.objects.create(rastermodel=model_instance)
def test_band_data_replication(self): band = GDALRaster({ 'srid': 4326, 'width': 3, 'height': 3, 'bands': [{ 'data': range(10, 19), 'nodata_value': 0 }], }).bands[0] # Variations for input (data, shape, expected result). combos = ( ([1], (1, 1), [1] * 9), (range(3), (1, 3), [0, 0, 0, 1, 1, 1, 2, 2, 2]), (range(3), (3, 1), [0, 1, 2, 0, 1, 2, 0, 1, 2]), ) for combo in combos: band.data(combo[0], shape=combo[1]) if numpy: numpy.testing.assert_equal(band.data(), numpy.array(combo[2]).reshape(3, 3)) else: self.assertEqual(band.data(), list(combo[2]))
def test_raster_warp(self): # Create in memory raster source = GDALRaster({ 'datatype': 1, 'driver': 'MEM', 'name': 'sourceraster', 'width': 4, 'height': 4, 'nr_of_bands': 1, 'srid': 3086, 'origin': (500000, 400000), 'scale': (100, -100), 'skew': (0, 0), 'bands': [{ 'data': range(16), 'nodata_value': 255, }], }) # Test altering the scale, width, and height of a raster data = { 'scale': [200, -200], 'width': 2, 'height': 2, } target = source.warp(data) self.assertEqual(target.width, data['width']) self.assertEqual(target.height, data['height']) self.assertEqual(target.scale, data['scale']) self.assertEqual(target.bands[0].datatype(), source.bands[0].datatype()) self.assertEqual(target.name, 'sourceraster_copy.MEM') result = target.bands[0].data() if numpy: result = result.flatten().tolist() self.assertEqual(result, [5, 7, 13, 15]) # Test altering the name and datatype (to float) data = { 'name': '/path/to/targetraster.tif', 'datatype': 6, } target = source.warp(data) self.assertEqual(target.bands[0].datatype(), 6) self.assertEqual(target.name, '/path/to/targetraster.tif') self.assertEqual(target.driver.name, 'MEM') result = target.bands[0].data() if numpy: result = result.flatten().tolist() self.assertEqual(result, [ 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0 ])
def test_read_mode_error(self): # Open raster in read mode rs = GDALRaster(self.rs_path, write=False) band = rs.bands[0] # Setting attributes in write mode raises exception in the _flush method with self.assertRaises(GDALException): setattr(band, 'nodata_value', 10)
def test_rs_srid(self): rast = GDALRaster({ 'width': 16, 'height': 16, 'srid': 4326, }) self.assertEqual(rast.srid, 4326) rast.srid = 3086 self.assertEqual(rast.srid, 3086)
def test_band_statistics_empty_band(self): rsmem = GDALRaster({ 'srid': 4326, 'width': 1, 'height': 1, 'bands': [{ 'data': [0], 'nodata_value': 0 }], }) self.assertEqual(rsmem.bands[0].statistics(), (None, None, None, None))
def test_vsi_buffer_property(self): # Create a vsi-based raster from scratch. rast = GDALRaster({ 'name': '/vsimem/raster.tif', 'driver': 'tif', 'width': 4, 'height': 4, 'srid': 4326, 'bands': [{ 'data': range(16), }], }) # Do a round trip from raster to buffer to raster. result = GDALRaster(rast.vsi_buffer).bands[0].data() if numpy: result = result.flatten().tolist() # Band data is equal to nodata value except on input block of ones. self.assertEqual(result, list(range(16))) # The vsi buffer is None for rasters that are not vsi based. self.assertIsNone(self.rs.vsi_buffer)
def test_geotransform_bad_inputs(self): rsmem = GDALRaster(JSON_RASTER) error_geotransforms = [ [1, 2], [1, 2, 3, 4, 5, 'foo'], [1, 2, 3, 4, 5, 6, 'foo'], ] msg = 'Geotransform must consist of 6 numeric values.' for geotransform in error_geotransforms: with self.subTest(i=geotransform), self.assertRaisesMessage( ValueError, msg): rsmem.geotransform = geotransform
def test_vsi_raster_creation(self): # Open a raster as a file object. with open(self.rs_path, 'rb') as dat: # Instantiate a raster from the file binary buffer. vsimem = GDALRaster(dat.read()) # The data of the in-memory file is equal to the source file. result = vsimem.bands[0].data() target = self.rs.bands[0].data() if numpy: result = result.flatten().tolist() target = target.flatten().tolist() self.assertEqual(result, target)
def test_lookup_with_raster_bbox(self): rast = GDALRaster(json.loads(JSON_RASTER)) # Shift raster upwards rast.origin.y = 2 # The raster in the model is not strictly below qs = RasterModel.objects.filter(rast__strictly_below=rast) self.assertEqual(qs.count(), 0) # Shift raster further upwards rast.origin.y = 6 # The raster in the model is strictly below qs = RasterModel.objects.filter(rast__strictly_below=rast) self.assertEqual(qs.count(), 1)
def test_file_based_raster_creation(self): # Prepare tempfile rstfile = tempfile.NamedTemporaryFile(suffix='.tif') # Create file-based raster from scratch GDALRaster({ 'datatype': self.rs.bands[0].datatype(), 'driver': 'tif', 'name': rstfile.name, 'width': 163, 'height': 174, 'nr_of_bands': 1, 'srid': self.rs.srs.wkt, 'origin': (self.rs.origin.x, self.rs.origin.y), 'scale': (self.rs.scale.x, self.rs.scale.y), 'skew': (self.rs.skew.x, self.rs.skew.y), 'bands': [{ 'data': self.rs.bands[0].data(), 'nodata_value': self.rs.bands[0].nodata_value, }], }) # Reload newly created raster from file restored_raster = GDALRaster(rstfile.name) self.assertEqual(restored_raster.srs.wkt, self.rs.srs.wkt) self.assertEqual(restored_raster.geotransform, self.rs.geotransform) if numpy: numpy.testing.assert_equal(restored_raster.bands[0].data(), self.rs.bands[0].data()) else: self.assertEqual(restored_raster.bands[0].data(), self.rs.bands[0].data())
def test_vsi_raster_deletion(self): path = '/vsimem/raster.tif' # Create a vsi-based raster from scratch. vsimem = GDALRaster({ 'name': path, 'driver': 'tif', 'width': 4, 'height': 4, 'srid': 4326, 'bands': [{ 'data': range(16), }], }) # The virtual file exists. rst = GDALRaster(path) self.assertEqual(rst.width, 4) # Delete GDALRaster. del vsimem del rst # The virtual file has been removed. msg = 'Could not open the datasource at "/vsimem/raster.tif"' with self.assertRaisesMessage(GDALException, msg): GDALRaster(path)
def test_lookup_with_polygonized_raster(self): rast = GDALRaster(json.loads(JSON_RASTER)) # Move raster to overlap with the model point on the left side rast.origin.x = -95.37040 + 1 rast.origin.y = 29.70486 # Raster overlaps with point in model qs = RasterModel.objects.filter(geom__intersects=rast) self.assertEqual(qs.count(), 1) # Change left side of raster to be nodata values rast.bands[0].data(data=[0, 0, 0, 1, 1], shape=(5, 1)) rast.bands[0].nodata_value = 0 qs = RasterModel.objects.filter(geom__intersects=rast) # Raster does not overlap anymore after polygonization # where the nodata zone is not included. self.assertEqual(qs.count(), 0)
def test_set_nodata_value_on_raster_creation(self): # Create raster filled with nodata values. rast = GDALRaster({ 'datatype': 1, 'width': 2, 'height': 2, 'srid': 4326, 'bands': [{ 'nodata_value': 23 }], }) # Get array from raster. result = rast.bands[0].data() if numpy: result = result.flatten().tolist() # All band data is equal to nodata value. self.assertEqual(result, [23] * 4)
def test_band_delete_nodata(self): rsmem = GDALRaster({ 'srid': 4326, 'width': 1, 'height': 1, 'bands': [{ 'data': [0], 'nodata_value': 1 }], }) if GDAL_VERSION < (2, 1): msg = 'GDAL >= 2.1 required to delete nodata values.' with self.assertRaisesMessage(ValueError, msg): rsmem.bands[0].nodata_value = None else: rsmem.bands[0].nodata_value = None self.assertIsNone(rsmem.bands[0].nodata_value)
def test_raster_metadata_property(self): data = self.rs.metadata self.assertEqual(data['DEFAULT'], {'AREA_OR_POINT': 'Area'}) self.assertEqual(data['IMAGE_STRUCTURE'], {'INTERLEAVE': 'BAND'}) # Create file-based raster from scratch source = GDALRaster({ 'datatype': 1, 'width': 2, 'height': 2, 'srid': 4326, 'bands': [{ 'data': range(4), 'nodata_value': 99 }], }) # Set metadata on raster and on a band. metadata = { 'DEFAULT': { 'OWNER': 'Django', 'VERSION': '1.0', 'AREA_OR_POINT': 'Point' }, } source.metadata = metadata source.bands[0].metadata = metadata self.assertEqual(source.metadata['DEFAULT'], metadata['DEFAULT']) self.assertEqual(source.bands[0].metadata['DEFAULT'], metadata['DEFAULT']) # Update metadata on raster. metadata = { 'DEFAULT': { 'VERSION': '2.0' }, } source.metadata = metadata self.assertEqual(source.metadata['DEFAULT']['VERSION'], '2.0') # Remove metadata on raster. metadata = { 'DEFAULT': { 'OWNER': None }, } source.metadata = metadata self.assertNotIn('OWNER', source.metadata['DEFAULT'])
def test_db_function_errors(self): """ Errors are raised when using DB functions with raster content. """ point = GEOSGeometry( "SRID=3086;POINT (-697024.9213808845 683729.1705516104)") rast = GDALRaster(json.loads(JSON_RASTER)) msg = "Distance function requires a geometric argument in position 2." with self.assertRaisesMessage(TypeError, msg): RasterModel.objects.annotate( distance_from_point=Distance("geom", rast)) with self.assertRaisesMessage(TypeError, msg): RasterModel.objects.annotate( distance_from_point=Distance("rastprojected", rast)) msg = "Distance function requires a GeometryField in position 1, got RasterField." with self.assertRaisesMessage(TypeError, msg): RasterModel.objects.annotate( distance_from_point=Distance("rastprojected", point)).count()
def test_set_nodata_none_on_raster_creation(self): if GDAL_VERSION < (2, 1): self.skipTest("GDAL >= 2.1 is required for this test.") # Create raster without data and without nodata value. rast = GDALRaster({ 'datatype': 1, 'width': 2, 'height': 2, 'srid': 4326, 'bands': [{ 'nodata_value': None }], }) # Get array from raster. result = rast.bands[0].data() if numpy: result = result.flatten().tolist() # Band data is equal to zero becaues no nodata value has been specified. self.assertEqual(result, [0] * 4)
def test_band_statistics_automatic_refresh(self): rsmem = GDALRaster({ 'srid': 4326, 'width': 2, 'height': 2, 'bands': [{ 'data': [0] * 4, 'nodata_value': 99 }], }) band = rsmem.bands[0] # Populate statistics cache self.assertEqual(band.statistics(), (0, 0, 0, 0)) # Change data band.data([1, 1, 0, 0]) # Statistics are properly updated self.assertEqual(band.statistics(), (0.0, 1.0, 0.5, 0.5)) # Change nodata_value band.nodata_value = 0 # Statistics are properly updated self.assertEqual(band.statistics(), (1.0, 1.0, 1.0, 0.0))
def test_memory_based_raster_creation(self): # Create uint8 raster with full pixel data range (0-255) rast = GDALRaster({ 'datatype': 1, 'width': 16, 'height': 16, 'srid': 4326, 'bands': [{ 'data': range(256), 'nodata_value': 255, }], }) # Get array from raster result = rast.bands[0].data() if numpy: result = result.flatten().tolist() # Assert data is same as original input self.assertEqual(result, list(range(256)))
def setUp(self): self.rs_path = os.path.join(os.path.dirname(__file__), '../data/rasters/raster.tif') rs = GDALRaster(self.rs_path) self.band = rs.bands[0]
def test_lookup_input_band_not_allowed(self): rast = GDALRaster(json.loads(JSON_RASTER)) qs = RasterModel.objects.filter(rast__bbcontains=(rast, 1)) msg = 'Band indices are not allowed for this operator, it works on bbox only.' with self.assertRaisesMessage(ValueError, msg): qs.count()
def test_lookup_input_tuple_too_long(self): rast = GDALRaster(json.loads(JSON_RASTER)) msg = 'Tuple too long for lookup bbcontains.' with self.assertRaisesMessage(ValueError, msg): RasterModel.objects.filter(rast__bbcontains=(rast, 1, 2))
def test_band_data_setters(self): # Create in-memory raster and get band rsmem = GDALRaster({ 'datatype': 1, 'driver': 'MEM', 'name': 'mem_rst', 'width': 10, 'height': 10, 'nr_of_bands': 1, 'srid': 4326, }) bandmem = rsmem.bands[0] # Set nodata value bandmem.nodata_value = 99 self.assertEqual(bandmem.nodata_value, 99) # Set data for entire dataset bandmem.data(range(100)) if numpy: numpy.testing.assert_equal(bandmem.data(), numpy.arange(100).reshape(10, 10)) else: self.assertEqual(bandmem.data(), list(range(100))) # Prepare data for setting values in subsequent tests block = list(range(100, 104)) packed_block = struct.pack('<' + 'B B B B', *block) # Set data from list bandmem.data(block, (1, 1), (2, 2)) result = bandmem.data(offset=(1, 1), size=(2, 2)) if numpy: numpy.testing.assert_equal(result, numpy.array(block).reshape(2, 2)) else: self.assertEqual(result, block) # Set data from packed block bandmem.data(packed_block, (1, 1), (2, 2)) result = bandmem.data(offset=(1, 1), size=(2, 2)) if numpy: numpy.testing.assert_equal(result, numpy.array(block).reshape(2, 2)) else: self.assertEqual(result, block) # Set data from bytes bandmem.data(bytes(packed_block), (1, 1), (2, 2)) result = bandmem.data(offset=(1, 1), size=(2, 2)) if numpy: numpy.testing.assert_equal(result, numpy.array(block).reshape(2, 2)) else: self.assertEqual(result, block) # Set data from bytearray bandmem.data(bytearray(packed_block), (1, 1), (2, 2)) result = bandmem.data(offset=(1, 1), size=(2, 2)) if numpy: numpy.testing.assert_equal(result, numpy.array(block).reshape(2, 2)) else: self.assertEqual(result, block) # Set data from memoryview bandmem.data(memoryview(packed_block), (1, 1), (2, 2)) result = bandmem.data(offset=(1, 1), size=(2, 2)) if numpy: numpy.testing.assert_equal(result, numpy.array(block).reshape(2, 2)) else: self.assertEqual(result, block) # Set data from numpy array if numpy: bandmem.data( numpy.array(block, dtype='int8').reshape(2, 2), (1, 1), (2, 2)) numpy.testing.assert_equal( bandmem.data(offset=(1, 1), size=(2, 2)), numpy.array(block).reshape(2, 2)) # Test json input data rsmemjson = GDALRaster(JSON_RASTER) bandmemjson = rsmemjson.bands[0] if numpy: numpy.testing.assert_equal(bandmemjson.data(), numpy.array(range(25)).reshape(5, 5)) else: self.assertEqual(bandmemjson.data(), list(range(25)))
def test_dwithin_gis_lookup_ouptut_with_rasters(self): """ Check the logical functionality of the dwithin lookup for different input parameters. """ # Create test raster and geom. rast = GDALRaster(json.loads(JSON_RASTER)) stx_pnt = GEOSGeometry( 'POINT (-95.370401017314293 29.704867409475465)', 4326) stx_pnt.transform(3086) # Filter raster with different lookup raster formats. qs = RasterModel.objects.filter(rastprojected__dwithin=(rast, D(km=1))) self.assertEqual(qs.count(), 1) qs = RasterModel.objects.filter( rastprojected__dwithin=(json.loads(JSON_RASTER), D(km=1))) self.assertEqual(qs.count(), 1) qs = RasterModel.objects.filter(rastprojected__dwithin=(JSON_RASTER, D(km=1))) self.assertEqual(qs.count(), 1) # Filter in an unprojected coordinate system. qs = RasterModel.objects.filter(rast__dwithin=(rast, 40)) self.assertEqual(qs.count(), 1) # Filter with band index transform. qs = RasterModel.objects.filter(rast__1__dwithin=(rast, 1, 40)) self.assertEqual(qs.count(), 1) qs = RasterModel.objects.filter(rast__1__dwithin=(rast, 40)) self.assertEqual(qs.count(), 1) qs = RasterModel.objects.filter(rast__dwithin=(rast, 1, 40)) self.assertEqual(qs.count(), 1) # Filter raster by geom. qs = RasterModel.objects.filter(rast__dwithin=(stx_pnt, 500)) self.assertEqual(qs.count(), 1) qs = RasterModel.objects.filter(rastprojected__dwithin=(stx_pnt, D(km=10000))) self.assertEqual(qs.count(), 1) qs = RasterModel.objects.filter(rast__dwithin=(stx_pnt, 5)) self.assertEqual(qs.count(), 0) qs = RasterModel.objects.filter(rastprojected__dwithin=(stx_pnt, D(km=100))) self.assertEqual(qs.count(), 0) # Filter geom by raster. qs = RasterModel.objects.filter(geom__dwithin=(rast, 500)) self.assertEqual(qs.count(), 1) # Filter through related model. qs = RasterRelatedModel.objects.filter( rastermodel__rast__dwithin=(rast, 40)) self.assertEqual(qs.count(), 1) # Filter through related model with band index transform qs = RasterRelatedModel.objects.filter( rastermodel__rast__1__dwithin=(rast, 40)) self.assertEqual(qs.count(), 1) # Filter through conditional statements. qs = RasterModel.objects.filter( Q(rast__dwithin=(rast, 40)) & Q(rastprojected__dwithin=(stx_pnt, D(km=10000)))) self.assertEqual(qs.count(), 1) # Filter through different lookup. qs = RasterModel.objects.filter(rastprojected__bbcontains=rast) self.assertEqual(qs.count(), 1)
def test_all_gis_lookups_with_rasters(self): """ Evaluate all possible lookups for all input combinations (i.e. raster-raster, raster-geom, geom-raster) and for projected and unprojected coordinate systems. This test just checks that the lookup can be called, but doesn't check if the result makes logical sense. """ from djmodels.contrib.gis.db.backends.postgis.operations import PostGISOperations # Create test raster and geom. rast = GDALRaster(json.loads(JSON_RASTER)) stx_pnt = GEOSGeometry( 'POINT (-95.370401017314293 29.704867409475465)', 4326) stx_pnt.transform(3086) lookups = [(name, lookup) for name, lookup in BaseSpatialField.get_lookups().items() if issubclass(lookup, GISLookup)] self.assertNotEqual(lookups, [], 'No lookups found') # Loop through all the GIS lookups. for name, lookup in lookups: # Construct lookup filter strings. combo_keys = [ field + name for field in [ 'rast__', 'rast__', 'rastprojected__0__', 'rast__', 'rastprojected__', 'geom__', 'rast__', ] ] if issubclass(lookup, DistanceLookupBase): # Set lookup values for distance lookups. combo_values = [ (rast, 50, 'spheroid'), (rast, 0, 50, 'spheroid'), (rast, 0, D(km=1)), (stx_pnt, 0, 500), (stx_pnt, D(km=1000)), (rast, 500), (json.loads(JSON_RASTER), 500), ] elif name == 'relate': # Set lookup values for the relate lookup. combo_values = [ (rast, 'T*T***FF*'), (rast, 0, 'T*T***FF*'), (rast, 0, 'T*T***FF*'), (stx_pnt, 0, 'T*T***FF*'), (stx_pnt, 'T*T***FF*'), (rast, 'T*T***FF*'), (json.loads(JSON_RASTER), 'T*T***FF*'), ] elif name == 'isvalid': # The isvalid lookup doesn't make sense for rasters. continue elif PostGISOperations.gis_operators[name].func: # Set lookup values for all function based operators. combo_values = [ rast, (rast, 0), (rast, 0), (stx_pnt, 0), stx_pnt, rast, json.loads(JSON_RASTER) ] else: # Override band lookup for these, as it's not supported. combo_keys[2] = 'rastprojected__' + name # Set lookup values for all other operators. combo_values = [ rast, None, rast, stx_pnt, stx_pnt, rast, json.loads(JSON_RASTER) ] # Create query filter combinations. self.assertEqual( len(combo_keys), len(combo_values), 'Number of lookup names and values should be the same', ) combos = [x for x in zip(combo_keys, combo_values) if x[1]] self.assertEqual( [(n, x) for n, x in enumerate(combos) if x in combos[:n]], [], 'There are repeated test lookups', ) combos = [{k: v} for k, v in combos] for combo in combos: # Apply this query filter. qs = RasterModel.objects.filter(**combo) # Evaluate normal filter qs. self.assertIn(qs.count(), [0, 1]) # Evaluate on conditional Q expressions. qs = RasterModel.objects.filter(Q(**combos[0]) & Q(**combos[1])) self.assertIn(qs.count(), [0, 1])