Finistere/antidote

Qualifiers and by_default

Closed this issue · 5 comments

by_default lets you register an implementation to be used when no other implementation is found. But it doesn't work as expected with qualified_by.

@interface
class View(Protocol):
    name: str


@implements(View).by_default
@dataclass
class DefaultView:
    name: str = "Default View"


@implements(View).when(qualified_by=V1)
@dataclass
class CustomView:
    name: str = "Custom View"


if __name__ == "__main__":
    print(world.get[View].single(qualified_by=V1))
    print(world.get[View].single())

If I leave off .by_default it fails at lookup when discovering multiple implementations.

When I include by_default, the second print just finds CustomView again.

I have a worry that you've explained this to me in email and I forgot. 😇

Ok, I have to admit, it wasn't obvious to me either at first. :)

When doing the second part, world.get[View].single(), no constraints are used at all. So any implementation is valid, CustomView included.

What you were expecting though was an implementation without qualifiers. This can be done with a predicate constraint:

class NotQualified:
    def evaluate(self, predicate: Optional[QualifiedBy]) -> bool:
        return predicate is None

print(world.get[View].single(NotQualified()))

Also, In the V2, I intend to replace evaluate with __call__. I think it was a mistake to use a custom name. It makes using function as constraints just easier.

For the stuff I'm writing on holiday, predicates was next. So you give me a good "segue" to introduce it!

While I won't change the current behavior with qualifiers, I've added a QualifiedBy.nothing constraint:

from dataclasses import dataclass
from typing import Protocol

from antidote import implements, instanceOf, interface, QualifiedBy, world


@interface
class View(Protocol):
    name: str


@implements.protocol[View]().as_default
@dataclass
class DefaultView:
    name: str = "Default View"


@implements.protocol[View]().when(qualified_by='v1')
@dataclass
class CustomView:
    name: str = "Custom View"


if __name__ == "__main__":
    print(world[instanceOf[View]().single(qualified_by='v1')])
    print(world[instanceOf[View]().single(QualifiedBy.nothing)])

Ah, thanks, I think that covers the case (from our coding session) that my cursor is currently sitting on.

I'll close this.