def test_from_dict(self): """classmethod to construct from serialisation """ spec = Spec.from_dict({ 'name': 'population', 'description': 'Population by age class', 'dims': ['countries', 'age'], 'coords': { 'age': [">30", "<30"], 'countries': ["England", "Wales"] }, 'dtype': 'int', 'abs_range': (0, float('inf')), 'exp_range': (10e6, 10e9), 'unit': 'people' }) assert spec.name == 'population' assert spec.description == 'Population by age class' assert spec.unit == 'people' assert spec.abs_range == (0, float('inf')) assert spec.exp_range == (10e6, 10e9) assert spec.dtype == 'int' assert spec.shape == (2, 2) assert spec.ndim == 2 assert spec.dims == ['countries', 'age'] assert spec.coords == [ Coordinates('countries', ["England", "Wales"]), Coordinates('age', [">30", "<30"]) ]
def test_construct(self, spec): """A Spec has: - coords: coordinates that label each point - list of Coordinates, one for each dim - name - dtype - absolute range: (optional) for numerical types, to raise error if exceeded - expected range: (optional) for numerical types, to raise warning if exceeded - unit - acceptable values The DataArray it describes may be sparse """ assert spec.name == 'population' assert spec.description == 'Population by age class' assert spec.unit == 'people' assert spec.abs_range == (0, float('inf')) assert spec.exp_range == (10e6, 10e9) assert spec.dtype == 'int' assert spec.shape == (2, 2) assert spec.ndim == 2 assert spec.dims == ['countries', 'age'] assert spec.coords == [ Coordinates('countries', ["England", "Wales"]), Coordinates('age', [">30", "<30"]) ]
def test_eq(self): """Equality based on equivalent dtype, dims, coords, unit """ a = Spec(name='population', coords=[Coordinates('countries', ["England", "Wales"])], dtype='int', unit='people') b = Spec(name='pop', coords=[Coordinates('countries', ["England", "Wales"])], dtype='int', unit='people') c = Spec(name='population', coords=[ Coordinates('countries', ["England", "Scotland", "Wales"]) ], dtype='int', unit='people') d = Spec(name='population', coords=[Coordinates('countries', ["England", "Wales"])], dtype='float', unit='people') e = Spec(name='population', coords=[Coordinates('countries', ["England", "Wales"])], dtype='int', unit='thousand people') assert a == b assert a != c assert a != d assert a != e
def spec(self): spec = Spec(name='population', description='Population by age class', coords=[ Coordinates('countries', ["England", "Wales"]), Coordinates('age', [">30", "<30"]) ], dtype='int', abs_range=(0, float('inf')), exp_range=(10e6, 10e9), unit='people') return spec
def test_name_dim_alias(self): """Name and dim refer to the same label """ coords = Coordinates('name', ['test']) assert coords.name == 'name' assert coords.dim == 'name' coords.name = 'name2' assert coords.name == 'name2' assert coords.dim == 'name2' coords.dim = 'name3' assert coords.name == 'name3' assert coords.dim == 'name3'
def test_empty_dtype_error(self): """A Spec must be constructed with a dtype """ with raises(ValueError) as ex: Spec(name='test', coords=[Coordinates('countries', ["England", "Wales"])]) assert "dtype must be provided" in str(ex.value)
def test_coords_from_list_error(self): """A Spec constructed with a dict must have dims """ with raises(ValueError) as ex: Spec(name='test', dtype='int', coords=[Coordinates('countries', ["England", "Wales"])], dims=['countries']) assert "dims are derived" in str(ex.value)
def test_duplicate_dims_error(self): """A Spec must not have duplicate dimension names """ with raises(ValueError) as ex: Spec(dtype='int', dims=['countries', 'countries'], coords={'countries': ["Scotland", "Northern Ireland"]}) assert "duplicate dims" in str(ex.value) with raises(ValueError) as ex: Spec(dtype='int', coords=[ Coordinates('countries', ['Scotland', 'Northern Ireland']), Coordinates('countries', ['Scotland', 'Northern Ireland']), ]) assert "duplicate dims" in str(ex.value)
def test_eq(self): """Equality based on equivalent name and elements """ a = Coordinates('name', [1, 2, 3]) b = Coordinates('name', [{'name': 1}, {'name': 2}, {'name': 3}]) c = Coordinates('another', [1, 2, 3]) d = Coordinates('name', [2, 3, 4]) e = Coordinates('name', [{ 'name': 1, 'note': 'meta' }, { 'name': 2, 'note': 'meta' }, { 'name': 3, 'note': 'meta' }]) assert a == b assert a != c assert a != d assert a != e
def test_elements_must_be_finite(self): """Only accept finite Coordinatess """ def natural_numbers(): i = 0 while True: yield i i += 1 elements = natural_numbers() with raises(ValueError) as ex: Coordinates('natural_numbers', elements) assert "must be finite" in str(ex.value)
def test_construct_with_elements(self, elements): """Create a Coordinates with name and elements (list of dicts) """ name = 'building_categories' building_sectors = Coordinates(name, elements) assert building_sectors.name == name assert building_sectors.ids == [ 'residential', 'commercial', 'industrial' ] assert building_sectors.names == [ 'residential', 'commercial', 'industrial' ] assert building_sectors.elements == elements
def test_construct_with_element_names(self): """Create a Coordinates with name and elements (list of ids) """ name = 'building_categories' element_ids = ['residential', 'commercial', 'industrial'] building_sectors = Coordinates(name, element_ids) assert building_sectors.name == name assert building_sectors.ids == element_ids assert building_sectors.names == element_ids assert building_sectors.elements == [{ 'name': 'residential' }, { 'name': 'commercial' }, { 'name': 'industrial' }]
def test_elements_must_have_name(self): """Coordinates elements must have "name" """ elements = [ { "description": "Petrol", "state": "liquid" }, { "description": "Diesel", "state": "liquid" }, { "description": "Coal", "state": "solid" }, ] with raises(KeyError) as ex: Coordinates('fossil_fuels', elements) assert "must have a name" in str(ex.value)
def test_dim_coords_method(self, spec): assert spec.dim_coords('countries') == Coordinates( 'countries', ["England", "Wales"]) with raises(KeyError) as ex: spec.dim_coords('does not exist') assert "Could not find dim 'does not exist' in Spec 'population'" in str( ex.value) with raises(TypeError) as ex: spec.dim_coords(['wrong type']) assert "Expected string as argument, instead received <class 'list'>" in str( ex.value) spec._dims = ['countries', 'age', 'no coords'] with raises(KeyError) as ex: spec.dim_coords('no coords') assert "Coords not found for dim 'no coords', in Spec 'population'" in str( ex.value)
def test_to_dict(self): actual = Spec(name='population', description='Population by age class', coords=[Coordinates('countries', ["England", "Wales"])], dtype='int', abs_range=(0, float('inf')), exp_range=(10e6, 10e9), unit='people').as_dict() expected = { 'name': 'population', 'description': 'Population by age class', 'dims': ['countries'], 'coords': { 'countries': ["England", "Wales"] }, 'dtype': 'int', 'abs_range': (0, float('inf')), 'exp_range': (10e6, 10e9), 'unit': 'people' } assert actual == expected
def test_coordinates_must_have_elements(self): """A Coordinates must have one or more elements """ with raises(ValueError) as ex: Coordinates('zero_d', []) assert "must not be empty" in str(ex.value)