def test_timeout(): from terracotta.expressions import evaluate_expression with pytest.raises(RuntimeError) as raised_exc: evaluate_expression('+'.join(['v1'] * 100), {'v1': np.ones((256, 256))}, timeout=0) assert 'timeout' in str(raised_exc.value)
def test_invalid_expression(case): from terracotta.expressions import evaluate_expression expr, exc_msg = case with pytest.raises(ValueError) as raised_exc: evaluate_expression(expr, OPERANDS) assert exc_msg in str(raised_exc.value)
def test_invalid_compop(monkeypatch): from terracotta.expressions import evaluate_expression, ExpressionParser expr = 'v0 < v1' exc_msg = 'comparison operator' with monkeypatch.context() as m: m.setattr(ExpressionParser, 'NODE_TO_COMPOP', {}) with pytest.raises(ValueError) as raised_exc: evaluate_expression(expr, OPERANDS) assert exc_msg in str(raised_exc.value)
def test_out_dtype(): from terracotta.expressions import evaluate_expression operands = dict(v1=np.ones(10, dtype='int64'), v2=np.zeros(10, dtype='int32')) res = evaluate_expression('v1 + v2', operands) assert isinstance(res, np.ma.MaskedArray) assert res.dtype == np.dtype('int64')
def test_valid_expression(case): from terracotta.expressions import evaluate_expression # make sure we have enough recursion depth for long expression sys.setrecursionlimit(10_000) expr, result = case np.testing.assert_array_equal(evaluate_expression(expr, OPERANDS), result)
def test_mask_invalid(): from terracotta.expressions import evaluate_expression res = evaluate_expression('where(v1 + v2 < 10, nan, 0)', OPERANDS) mask = (OPERANDS['v1'] + OPERANDS['v2'] < 10) | OPERANDS['v1'].mask | OPERANDS['v2'].mask assert isinstance(res, np.ma.MaskedArray) assert np.all(res == 0) assert np.array_equal(res.mask, mask)
def test_valid_expression(case): from terracotta.expressions import evaluate_expression expr, result = case np.testing.assert_array_equal(evaluate_expression(expr, OPERANDS), result)
def compute(expression: str, some_keys: Sequence[str], operand_keys: Mapping[str, str], stretch_range: Tuple[Number, Number], tile_xyz: Tuple[int, int, int] = None, *, colormap: str = None, tile_size: Tuple[int, int] = None) -> BinaryIO: """Return singleband image computed from one or more images as PNG Expects a Python expression that returns a NumPy array. Operands in the expression are replaced by the images with keys as defined by some_keys (all but the last key) and operand_keys (last key). Contrary to singleband and rgb handlers, stretch_range must be given. Example: >>> operands = { ... 'v1': 'B08', ... 'v2': 'B04' ... } >>> compute('v1 * v2', ['S2', '20171101'], operands, [0, 1000]) <binary image containing product of bands 4 and 8> """ from terracotta.expressions import evaluate_expression if not stretch_range[1] > stretch_range[0]: raise exceptions.InvalidArgumentsError( 'Upper stretch bounds must be larger than lower bounds') settings = get_settings() if tile_size is None: tile_size_ = settings.DEFAULT_TILE_SIZE else: tile_size_ = tile_size driver = get_driver(settings.DRIVER_PATH, provider=settings.DRIVER_PROVIDER) with driver.connect(): key_names = driver.key_names if len(some_keys) != len(key_names) - 1: raise exceptions.InvalidArgumentsError( 'must specify all keys except last one') def get_band_future(band_key: str) -> Future: band_keys = (*some_keys, band_key) return xyz.get_tile_data(driver, band_keys, tile_xyz=tile_xyz, tile_size=tile_size_, asynchronous=True) futures = { var: get_band_future(key) for var, key in operand_keys.items() } operand_data = { var: future.result() for var, future in futures.items() } try: out = evaluate_expression(expression, operand_data) except ValueError as exc: # make sure error message gets propagated raise exceptions.InvalidArgumentsError( f'error while executing expression: {exc!s}') out = image.to_uint8(out, *stretch_range) return image.array_to_png(out, colormap=colormap)