Giter Club home page Giter Club logo

Comments (5)

tlambert03 avatar tlambert03 commented on July 23, 2024

thanks @davidbrochart
can you slightly reword or recode that last bit where "it doesn't work anymore", perhaps in the form of an assertion statement? I think there's something here, but there's a lot going on in this example and I'm not entirely sure I'm following. Here's a test I wrote to confirm that processors can indeed themselves have injection requirements, and it currently passes on main ... but I suspect I've missed the crux of the issue here.

perhaps you could modify this test a bit to make it fail according to your expectations?

def test_processors_with_injections() -> None:
    """Test that we can use processors with injections."""

    class ThingToProcess:
        ...

    class InjectedDep:
        ...

    dep = InjectedDep()
    t2p = ThingToProcess()
    mock = Mock()

    # this function processes a ThingToProcess, but also requires
    # an InjectedDep to be injected before it will work
    @ino.register_processor
    @ino.inject
    def processor_that_has_injections(p0: ThingToProcess, p1: InjectedDep) -> None:
        mock(p0, p1)

    # "inject processors" of this function... 
    # meaning: when `return_a_thing ` is called, the t2p return value should be processed
    #  (as a side effect of calling the function)
    @ino.inject_processors
    def return_a_thing() -> ThingToProcess:
        return t2p

    # at the moment, our `processor_that_has_injections` function still doesn't have a
    # p1 InjectedDep, so `return_a_thing`'s return value won't be processed successfully
    with pytest.warns(UserWarning, match="Processor .* failed to process result"):
        return_a_thing()

    # but if we register a something that provides an InjectedDep...
    @ino.register_provider
    def provide_other_thing() -> InjectedDep:
        return dep

    # then the processor should work as expected ...
    return_a_thing()
    mock.assert_called_once_with(t2p, dep)

from in-n-out.

davidbrochart avatar davidbrochart commented on July 23, 2024

Sorry, I could probably simplify the example again, but here is a test that fails (the two commented blocks work fine):

import in_n_out as ino

def test_processors_with_injections() -> None:

    class Dummy:
        pass

    class Thing:
        def __init__(self):
            self.list = []

    def dummy_provider() -> Dummy:
        return Dummy()

    @ino.inject
    @ino.inject_processors
    def thing_provider(dummy: Dummy) -> Thing:
        return Thing()

    ino.register_provider(dummy_provider)
    ino.register_provider(thing_provider)

    # def add_item(thing: Thing):
    #     thing.list.append("item")

    @ino.inject
    def add_item(dummy: Dummy, thing: Thing):
        thing.list.append("item")

    # def add_item(thing: Thing):
    #     @ino.inject
    #     def inner(dummy: Dummy):
    #         thing.list.append("item")
    #     inner()

    ino.register_processor(add_item)
    ino.register_processor(add_item)
    ino.register_processor(add_item)

    @ino.inject
    def func(thing: Thing):
        return thing.list

    assert func() == ["item"] * 3

I think it's the normal behavior, because with:

@ino.inject
    def add_item(dummy: Dummy, thing: Thing):
        ...

One cannot say that thing is the thing to process.

from in-n-out.

tlambert03 avatar tlambert03 commented on July 23, 2024

ahhh, I see! sorry, I missed that. So, to restate the problem slightly, you want to specify that add_item is a processor of the second argument in its signature (the Thing not the Dummy). In that case, you can use the type_hint argument for register_processor. By default, processors with multiple arguments are assumed to process the first argument in their signature, but you can override that inference with:

ino.register_processor(add_item, type_hint=Thing)

(... this is documented, but it's a bit hard to find at the moment when you use the global ino.register_processor command)

type_hint : object
A type or type hint that `processor` can handle.

however! ... doing that in your then reveals a RecursionError in your test. So let me look into that a bit more

from in-n-out.

tlambert03 avatar tlambert03 commented on July 23, 2024

OK, looks like I just didn't prepare for processor functions that process anything other than their first argument:

for processor in self.iter_processors(type_hint): # type: ignore
try:
processor(result)
except Exception as e: # pragma: no cover
if raise_exception:

I think I could fix this by additionally storing the name of the function parameter that the processor processes ('thing' in your case), and then calling the processor with processor(**{param_name: result})

from in-n-out.

tlambert03 avatar tlambert03 commented on July 23, 2024

in summary, this boiled down to 2 things:

  1. while processors may override the associated type that they process (using the type_hint argument when registering), they must process their first argument. A "feature" was implemented in #52, but opted against at this time
  2. there was a latent recursion error when a provider has its output processed. that is was fixed in #51

from in-n-out.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.