kalekundert / byoc

MIT License
0 stars 0 forks source link

Allow function/method calls to be mixed with keys #12

Closed kalekundert closed 3 years ago

kalekundert commented 3 years ago

I'm thinking of something like this:

class Foo:
    bar = appcli.param(
            Key(ConfigA),
            Call(lambda: ...),
            Key(ConfigB),
    )

The Key objects would get their values by querying the corresponding configs, while the Call objects would get their values by calling the given function. There could be several of these classes, e.g. to return scalar values, to call methods (e.g. functions with the self argument), etc. These classes actually correspond with the default parameters that I was thinking about expanding in #10.

It's worth noting that you could probably achieve the same end result using custom configs, but I think this is still a paradigm worth supporting. I want to think of parameters as being able to read values from arbitrary sources in arbitrary order, and this makes it much easier to fit calculated values into that ordering.

The other nice thing about this approach is that the functions/methods can raise AttributeError to be skipped, which default values can't do.

kalekundert commented 3 years ago

More syntax examples:


class MyApp:

    bar = appcli.param(
            Key(ConfigA),
            Method(lambda self: self._helper()),
            Key(ConfigB),
            Func(list),
            Value(None),
    )

    def _helper(self):
        pass

I like that Method, Func, and Value are nouns in the same sense as Key, if you know what I mean. These three classes also clearly communicate how the value will be determined, without doing anything magical or overloaded.

kalekundert commented 3 years ago

Note that the Method/Func/Value objects could replace the default and default_factory arguments to param(). They provide all of the equivalent functionality and more. But the default arguments are useful syntactic sugar, so I'm not going to get rid of them.