Beispiel #1
0
def _condition_schema(operator,
                      _op,
                      scalar=True,
                      aggr=False,
                      label_required=False):
    """Build a schema that expresses an (optionally labeled) boolean
    expression.

    For instance:

    condition:
      field: age
      label: 'over 80'
      gt: 80

    """

    allowed_values = SCALAR_TYPES if scalar else SCALAR_TYPES + [S.List()]
    field = "aggregated_field" if aggr else "non_aggregated_field"

    cond_schema = {
        "field": field,
        "label": S.String(required=label_required),
        operator: {
            "anyof": allowed_values
        },
    }

    _condition_schema = S.Dict(
        allow_unknown=False,
        schema=cond_schema,
        coerce_post=ConditionPost(operator, _op, scalar),
    )
    return _condition_schema
Beispiel #2
0
def _field_schema(aggr=True, required=True):
    """Make a field schema that either aggregates or doesn't. """
    if aggr:
        ag = S.String(
            required=False,
            allowed=list(aggregations.keys()),
            default=default_aggregation,
            nullable=True,
        )
    else:
        ag = S.String(
            required=False,
            allowed=[no_aggregation, None],
            default=no_aggregation,
            nullable=True,
        )

    operator = S.Dict({
        "operator": S.String(allowed=["+", "-", "/", "*"]),
        "field": S.String()
    })

    return S.Dict(
        schema={
            "value":
            S.String(),
            "aggregation":
            ag,
            "ref":
            S.String(required=False),
            "condition":
            "condition",
            "operators":
            S.List(schema=operator, required=False),
            # Performs a dividebyzero safe sql division
            "divide_by":
            S.Dict(required=False, schema="aggregated_field"),
            # Performs casting
            "as":
            S.String(
                required=False,
                allowed=list(sqlalchemy_datatypes.keys()),
                coerce=_to_lowercase,
            ),
            # Performs coalescing
            "default": {
                "anyof": SCALAR_TYPES,
                "required": False
            },
            # Should the value be used directly in sql
            "_use_raw_value":
            S.Boolean(required=False),
        },
        coerce=_coerce_string_into_field,
        coerce_post=_field_post,
        allow_unknown=False,
        required=required,
    )
Beispiel #3
0
def test_list_schema():
    schema = S.List(schema=S.Integer())
    val = [1, 2, 3]
    assert normalize_schema(schema, val) == val

    with pytest.raises(E.BadType) as ei:
        normalize_schema(schema, [1, 'two', object()])
    assert ei.value.value == 'two'
    assert ei.value.stack == (1, )
Beispiel #4
0
    "label": S.String(required=True)
})

# A full condition guaranteed to not contain an aggregation
named_condition_schema = S.Dict(schema={
    "condition": field_schema,
    "name": S.String(required=True)
})

format_schema = S.String(coerce=coerce_format, required=False)

metric_schema = S.Dict(
    schema={
        "field": field_schema,
        "format": format_schema,
        "quickselects": S.List(required=False,
                               schema=labeled_condition_schema),
    },
    allow_unknown=True,
)

dimension_schema = S.Dict(
    schema={
        "field":
        field_schema,
        "extra_fields":
        S.List(
            required=False,
            schema=S.Dict(schema={
                "field": field_schema,
                "name": S.String(required=True)
            }),
Beispiel #5
0
shelf_schema = S.Dict(choose_schema=S.when_key_is(
    "_version",
    {
        "1": shelf_schema,
        1: shelf_schema,
        "2": parsed_shelf_schema,
        2: parsed_shelf_schema,
    },
    default_choice="1",
))

# This schema is used with sureberus
recipe_schema = S.Dict(
    schema={
        "metrics":
        S.List(schema=S.String(), required=False),
        "dimensions":
        S.List(schema=S.String(), required=False),
        "filters":
        S.List(schema={"oneof": [S.String(), "condition"]}, required=False),
        "order_by":
        S.List(schema=S.String(), required=False),
    },
    registry={
        "aggregated_field":
        _field_schema(aggr=True, required=True),
        "optional_aggregated_field":
        _field_schema(aggr=True, required=False),
        "non_aggregated_field":
        _field_schema(aggr=False, required=True),
        "condition":
Beispiel #6
0
def _full_condition_schema(**kwargs):
    """Conditions can be a field with an operator, like this yaml example

    condition:
        field: foo
        gt: 22

    Or conditions can be a list of and-ed and or-ed conditions

    condition:
        or:
            - field: foo
              gt: 22
            - field: foo
              lt: 0

    :param aggr: Build the condition with aggregate fields (default is False)
    """

    label_required = kwargs.get("label_required", False)

    # Handle conditions where there's an
    operator_condition = S.Dict(
        choose_schema=S.when_key_exists({
            "gt":
            _condition_schema("gt", "__gt__", **kwargs),
            "gte":
            _condition_schema("gte", "__ge__", **kwargs),
            "ge":
            _condition_schema("ge", "__ge__", **kwargs),
            "lt":
            _condition_schema("lt", "__lt__", **kwargs),
            "lte":
            _condition_schema("lte", "__le__", **kwargs),
            "le":
            _condition_schema("le", "__le__", **kwargs),
            "eq":
            _condition_schema("eq", "__eq__", **kwargs),
            "ne":
            _condition_schema("ne", "__ne__", **kwargs),
            "like":
            _condition_schema("like", "like", **kwargs),
            "ilike":
            _condition_schema("ilike", "ilike", **kwargs),
            "in":
            _condition_schema("in", "in_", scalar=False, **kwargs),
            "notin":
            _condition_schema("notin", "notin", scalar=False, **kwargs),
            "between":
            _condition_schema("between", "between", scalar=False, **kwargs),
            "or":
            S.Dict(
                schema={
                    "or": S.List(schema="condition"),
                    "label": S.String(required=label_required),
                }),
            "and":
            S.Dict(
                schema={
                    "and": S.List(schema="condition"),
                    "label": S.String(required=label_required),
                }),
            # A reference to another condition
            "ref":
            S.Dict(schema={"ref": S.String()}),
        }),
        required=False,
        coerce=_coerce_string_into_condition_ref,
    )

    return {
        "registry": {
            "condition": operator_condition,
            "aggregated_field": _field_schema(aggr=True),
            "non_aggregated_field": _field_schema(aggr=False),
        },
        "schema_ref": "condition",
    }
Beispiel #7
0

def _replace_references(shelf):
    """Iterate over the shelf and replace and field.value: @ references
    with the field in another ingredient"""
    for ingr in shelf.values():
        _process_ingredient(ingr, shelf)
    return shelf


condition_schema = _full_condition_schema(aggr=False)

quickselect_schema = S.List(
    required=False,
    schema=S.Dict(schema={
        "condition": "condition",
        "name": S.String(required=True)
    }),
)

ingredient_schema_choices = {
    "metric":
    S.Dict(
        allow_unknown=True,
        schema={
            "field": "aggregated_field",
            "divide_by": "optional_aggregated_field",
            "format": S.String(coerce=coerce_format, required=False),
            "quickselects": quickselect_schema,
        },
    ),
Beispiel #8
0
def test_allow_unknown_in_list_schema():
    schema = S.List(allow_unknown=True,
                    schema=S.Dict(schema={'x': S.String()}))
    val = [{'x': 'y', 'extra': 0}]
    assert normalize_schema(schema, val, allow_unknown=False) == val
Beispiel #9
0
def test_list_normalize():
    schema = S.List(schema=S.Dict(schema={'x': S.String(default='')}))
    result = normalize_schema(schema, [{}])
    assert result == [{'x': ''}]
Beispiel #10
0
def test_list():
    schema = S.List()
    val = [1, 'two', object()]
    assert normalize_schema(schema, val) == val
Beispiel #11
0
def test_oneof_only_one():
    oneof = {'oneof': [{'maxlength': 3}, S.List()]}
    with pytest.raises(E.MoreThanOneMatched) as ei:
        normalize_schema(oneof, [0])