Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proposal for one more user-friendly crudify layer #21

Closed
thorwhalen opened this issue Aug 4, 2022 · 0 comments
Closed

Proposal for one more user-friendly crudify layer #21

thorwhalen opened this issue Aug 4, 2022 · 0 comments
Labels
enhancement New feature or request

Comments

@thorwhalen
Copy link
Member

thorwhalen commented Aug 4, 2022

prepare_for_crude_dispatch is still a low level function not intended to be used directly, except by "experts".

We need to give a few easy-to-use (yet safe) tools for higher-level users to use crude.
Here's one proposal.

from dataclasses import make_dataclass
from i2 import Sig
from front.crude import prepare_for_crude_dispatch

_Crudifier = make_dataclass('_Crudifier', [(p.name, p.kind, p.default) for p in Sig(prepare_for_crude_dispatch).params[1:]])

class Crudifier(_Crudifier):
    def __call__(self, func):
        # is there a safer way than vars to get the init fields (keys and values)?
        return prepare_for_crude_dispatch(func, **vars(self))

Here are a few examples of how to use it.

def foo(x, y):
    return x + y

def bar(a, x):
    return a * x

crudify = Crudifier(param_to_mall_map={'x': 'x_store'}, mall={'x_store': {'stored_two': 2}})

crudified_foo = crudify(foo)
assert str(Sig(crudified_foo)) == '(x: str, y)'
assert crudified_foo('stored_two', 3) == 5

crudify = Crudifier('x y', mall={'x': {'stored_two': 2}, 'y': {'three': 3}})
f = crudify(foo)
assert str(Sig(f)) == '(x: str, y: str)'
assert f('stored_two', 'three') == 5

This allows you to do things like partialize, to fix the mall, and only have to specify the param_to_mall_map when you want to crudify

from functools import partial

mall = {'x': {'stored_two': 2}, 'y': {'three': 3}, 'fall_back_store': {'zebra': 11}}
Crudify = partial(Crudifier, mall=mall, verbose=False)

f = Crudify('x')(foo)
assert f('stored_two', 3) == 5

f = Crudify('x y')(foo)
assert f('stored_two', 'three') == 5

b = Crudify({'a': 'fall_back_store'})(bar)
assert b('zebra', 3) == 33

This callable object, or something like it, can then be used in a recursive transformer such a
the front rendering process to indicate that a function should be crudified, and how.
For example:

from typing import Iterable
from i2 import Pipe

def _ensure_iterable(v):
    if not isinstance(v, Iterable):
        v = [v]
    return v

def prepare(configs):
    for func, specs in configs.items():
        if (processes := specs.get('preprocesses', None)) is not None:
            preprocess = Pipe(*_ensure_iterable(processes))
            _func = preprocess(func)
        else:
            _func = func
        specs = dict(specs, func=_func)
        print(func, specs)
        yield func, specs

Example use:

configs = {
    # of course, this is not our actual configs, but used here for simplicity.
    foo: {
        'preprocesses': Crudify('x y'),
        'whatevs': 42
    },
    bar: {
        'blahblah': 24
    }
}

prepared_configs = dict(prepare(configs))

processed_foo = prepared_configs[foo]['func']
assert processed_foo('stored_two', 'three') == 5
@thorwhalen thorwhalen added the enhancement New feature or request label Aug 4, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

1 participant