Esempio n. 1
0
def test_reinvoke_namespace_merge():
    class ReinvokableWithExtra(Namespace):
        _name = None
        extra = Refinable()

        @reinvokable
        def __init__(self, **kwargs):
            super().__init__(**kwargs)

    assert reinvoke(
        ReinvokableWithExtra(
            extra__foo=17
        ),
        Namespace(
            extra__bar=42
        )
    ).extra == dict(bar=42, foo=17)

    # Try again with pre-Namespaced kwargs
    assert reinvoke(
        ReinvokableWithExtra(
            **Namespace(extra__foo=17)
        ),
        Namespace(
            extra__bar=42
        )
    ).extra == dict(bar=42, foo=17)
Esempio n. 2
0
def test_set_and_remember_for_reinvoke():
    x = MyReinvokable(foo=17)
    assert x._iommi_saved_params == dict(foo=17)
    assert x.kwargs.foo == 17

    set_and_remember_for_reinvoke(x, foo=42)
    assert x.foo == 42
    x = reinvoke(x, dict(bar=42))
    assert x.kwargs == dict(foo=42, bar=42)
Esempio n. 3
0
def test_reinvokable_recurse_retain_original():
    x = MyReinvokable(a=1,
                      foo=MyReinvokable(b=2, bar=MyReinvokable(c=3, baz=17)))
    x = reinvoke(x, Namespace(foo__bar__baz=42))

    assert isinstance(x.kwargs.foo, MyReinvokable)
    assert x.kwargs.a == 1
    assert x.kwargs.foo.kwargs.b == 2
    assert x.kwargs.foo.kwargs.bar.kwargs.c == 3
    assert x.kwargs.foo.kwargs.bar.kwargs.baz == 42
Esempio n. 4
0
    def on_bind(self) -> None:
        bind_members(self, name='filters')

        request = self.get_request()
        self.query_advanced_value = request_data(request).get(
            self.get_advanced_query_param(), '') if request else ''

        # TODO: should it be possible to have freetext as a callable? this code just treats callables as truthy
        if any(f.freetext for f in values(declared_members(self)['filters'])):
            set_and_remember_for_reinvoke(declared_members(
                self.form).fields[FREETEXT_SEARCH_NAME],
                                          include=True)

        declared_fields = declared_members(self.form)['fields']
        for name, filter in items(self.filters):
            is_valid, message = filter.is_valid_filter(name=name,
                                                       filter=filter)
            assert is_valid, message
            if name in declared_fields:
                field = setdefaults_path(
                    Namespace(),
                    _name=name,
                    attr=name if filter.attr is MISSING else filter.attr,
                    model_field=filter.model_field,
                    help__include=False,
                )
                declared_fields[name] = reinvoke(declared_fields[name], field)
        set_declared_member(self.form, 'fields', declared_fields)

        # Remove fields from the form that correspond to non-included filters
        declared_filters = declared_members(self)['filters']
        for name, field in items(declared_fields):
            if name == FREETEXT_SEARCH_NAME:
                continue
            # We need to check if it's in declared_filters first, otherwise we remove any injected fields
            if name in declared_filters and name not in self.filters:
                set_and_remember_for_reinvoke(field, include=False)

        bind_members(self, name='endpoints')

        self.form = self.form.bind(parent=self)
        self._bound_members.form = self.form

        self.advanced = self._bound_members.advanced = self.advanced.bind(
            parent=self)

        self.form_container = self.form_container.bind(parent=self)

        self.filter_name_by_query_name = {
            x.query_name: name
            for name, x in items(self.filters)
        }
Esempio n. 5
0
def test_reinvoke_change_shortcut():
    class ReinvokableWithShortcut(MyReinvokable):
        @classmethod
        @class_shortcut
        def shortcut(cls, call_target=None, **kwargs):
            kwargs['shortcut_was_here'] = True
            return call_target(**kwargs)

    assert reinvoke(
        ReinvokableWithShortcut(),
        dict(
            call_target__attribute='shortcut',
            foo='bar',
        )
    ).kwargs == dict(foo='bar', shortcut_was_here=True)
Esempio n. 6
0
def collect_members(
    container,
    *,
    name: str,
    items_dict: Dict = None,
    items: Dict[str, Any] = None,
    cls: Type,
    unknown_types_fall_through=False,
):
    """
    This function is used to collect and merge data from the constructor
    argument, the declared members, and other config into one data structure.
    `bind_members` is then used at bind time to recursively bind the nested
    parts.

    Example:

    .. code:: python

        class ArtistTable(Table):
            instrument = Column()  # <- declared member

        MyTable(
            columns__name=Column(),  # <- constructor argument
            columns__instrument__after='name',  # <- inserted config for a declared member
        )

    In this example the resulting table will have two columns `instrument` and
    `name`, with `instrument` after name even though it was declared before.
    """
    forbidden_names = FORBIDDEN_NAMES & (set(keys(items_dict or {})) | set(keys(items or {})))
    if forbidden_names:
        raise ForbiddenNamesException(
            f'The names {", ".join(sorted(forbidden_names))} are reserved by iommi, please pick other names'
        )

    assert name != 'items'
    unbound_items = Struct()
    _unapplied_config = {}

    if items_dict is not None:
        for key, x in items_of(items_dict):
            x._name = key
            unbound_items[key] = x

    if items is not None:
        for key, item in items_of(items):
            if isinstance(item, Traversable):
                # noinspection PyProtectedMember
                assert not item._is_bound
                item._name = key
                unbound_items[key] = item
            elif isinstance(item, dict):
                if key in unbound_items:
                    _unapplied_config[key] = item
                else:
                    item = setdefaults_path(
                        Namespace(),
                        item,
                        call_target__cls=cls,
                        _name=key,
                    )
                    unbound_items[key] = item()
            else:
                assert (
                    unknown_types_fall_through or item is None
                ), f'I got {type(item)} when creating a {cls.__name__}.{key}, but I was expecting Traversable or dict'
                unbound_items[key] = item

    for k, v in items_of(Namespace(_unapplied_config)):
        unbound_items[k] = reinvoke(unbound_items[k], v)
        # noinspection PyProtectedMember
        assert unbound_items[k]._name is not None

    to_delete = {k for k, v in items_of(unbound_items) if v is None}

    for k in to_delete:
        del unbound_items[k]

    sort_after(unbound_items)

    set_declared_member(container, name, unbound_items)
    setattr(container, name, NotBoundYet(container, name))
Esempio n. 7
0
def test_reinvokable_recurse():
    x = MyReinvokable(foo=MyReinvokable(bar=17))
    x = reinvoke(x, Namespace(foo__bar=42))

    assert isinstance(x.kwargs.foo, MyReinvokable)
    assert x.kwargs.foo.kwargs == dict(bar=42)
Esempio n. 8
0
def test_reinvokable():
    x = MyReinvokable(foo=17)
    x = reinvoke(x, dict(bar=42))
    assert x.kwargs == dict(foo=17, bar=42)