Nested Dependency Injections

Hiya

Is it possible for a dependency to further depend on another? E.g.

class FooInjection(DependencyProvider):
    ...

class BarInjection(DependencyProvider):
    foo = FooInjection()
    ...

class Service:
    bar = BarInjection()

Thanks

Hi,

Yes, via what's called a 'shared extension' (behaves slightly differently
but same principle). see
e.g. https://github.com/nameko/nameko/blob/master/nameko/web/server.py for
an example

let us know if anything's unclear or you need more pointers

best,
david

···

On Wednesday, 15 March 2017 10:51:44 UTC, simon harrison wrote:

Hiya

Is it possible for a dependency to further depend on another? E.g.

class FooInjection(DependencyProvider):
    ...

class BarInjection(DependencyProvider):
    foo = FooInjection()
    ...

class Service:
    bar = BarInjection()

Thanks

that's worked out nicely. Thanks David.

···

On Wednesday, 15 March 2017 10:57:47 UTC, David Szotten wrote:

Hi,

Yes, via what's called a 'shared extension' (behaves slightly differently
but same principle). see e.g.
https://github.com/nameko/nameko/blob/master/nameko/web/server.py for an
example

let us know if anything's unclear or you need more pointers

best,
david

On Wednesday, 15 March 2017 10:51:44 UTC, simon harrison wrote:

Hiya

Is it possible for a dependency to further depend on another? E.g.

class FooInjection(DependencyProvider):
    ...

class BarInjection(DependencyProvider):
    foo = FooInjection()
    ...

class Service:
    bar = BarInjection()

Thanks

A follow up question.

Now that it's a SharedExtension, the worker factory does not substitute it
with a Mock when it's on the service class.

How do I handle this?

Thanks

···

On Wednesday, 15 March 2017 11:49:48 UTC, simon harrison wrote:

that's worked out nicely. Thanks David.

On Wednesday, 15 March 2017 10:57:47 UTC, David Szotten wrote:

Hi,

Yes, via what's called a 'shared extension' (behaves slightly differently
but same principle). see e.g.
https://github.com/nameko/nameko/blob/master/nameko/web/server.py for an
example

let us know if anything's unclear or you need more pointers

best,
david

On Wednesday, 15 March 2017 10:51:44 UTC, simon harrison wrote:

Hiya

Is it possible for a dependency to further depend on another? E.g.

class FooInjection(DependencyProvider):
    ...

class BarInjection(DependencyProvider):
    foo = FooInjection()
    ...

class Service:
    bar = BarInjection()

Thanks

Can I even use a Shared Extension on the service class like this?

···

On Wednesday, 15 March 2017 13:46:27 UTC, simon harrison wrote:

A follow up question.

Now that it's a SharedExtension, the worker factory does not substitute it
with a Mock when it's on the service class.

How do I handle this?

Thanks

On Wednesday, 15 March 2017 11:49:48 UTC, simon harrison wrote:

that's worked out nicely. Thanks David.

On Wednesday, 15 March 2017 10:57:47 UTC, David Szotten wrote:

Hi,

Yes, via what's called a 'shared extension' (behaves slightly
differently but same principle). see e.g.
https://github.com/nameko/nameko/blob/master/nameko/web/server.py for
an example

let us know if anything's unclear or you need more pointers

best,
david

On Wednesday, 15 March 2017 10:51:44 UTC, simon harrison wrote:

Hiya

Is it possible for a dependency to further depend on another? E.g.

class FooInjection(DependencyProvider):
    ...

class BarInjection(DependencyProvider):
    foo = FooInjection()
    ...

class Service:
    bar = BarInjection()

Thanks

that's certainly not what they're designed for. may work incidentally but
probably not

shared extensions are for other extensions to depend on, not for services

in your original example, only `FooInjection` should be a shared extension

d

···

On Wednesday, 15 March 2017 13:53:10 UTC, simon harrison wrote:

Can I even use a Shared Extension on the service class like this?

On Wednesday, 15 March 2017 13:46:27 UTC, simon harrison wrote:

A follow up question.

Now that it's a SharedExtension, the worker factory does not substitute
it with a Mock when it's on the service class.

How do I handle this?

Thanks

On Wednesday, 15 March 2017 11:49:48 UTC, simon harrison wrote:

that's worked out nicely. Thanks David.

On Wednesday, 15 March 2017 10:57:47 UTC, David Szotten wrote:

Hi,

Yes, via what's called a 'shared extension' (behaves slightly
differently but same principle). see e.g.
https://github.com/nameko/nameko/blob/master/nameko/web/server.py for
an example

let us know if anything's unclear or you need more pointers

best,
david

On Wednesday, 15 March 2017 10:51:44 UTC, simon harrison wrote:

Hiya

Is it possible for a dependency to further depend on another? E.g.

class FooInjection(DependencyProvider):
    ...

class BarInjection(DependencyProvider):
    foo = FooInjection()
    ...

class Service:
    bar = BarInjection()

Thanks

What is your usecase for this, Simon?

···

On Wednesday, March 15, 2017 at 1:59:12 PM UTC, David Szotten wrote:

that's certainly not what they're designed for. may work incidentally but
probably not

shared extensions are for other extensions to depend on, not for services

in your original example, only `FooInjection` should be a shared extension

d

On Wednesday, 15 March 2017 13:53:10 UTC, simon harrison wrote:

Can I even use a Shared Extension on the service class like this?

On Wednesday, 15 March 2017 13:46:27 UTC, simon harrison wrote:

A follow up question.

Now that it's a SharedExtension, the worker factory does not substitute
it with a Mock when it's on the service class.

How do I handle this?

Thanks

On Wednesday, 15 March 2017 11:49:48 UTC, simon harrison wrote:

that's worked out nicely. Thanks David.

On Wednesday, 15 March 2017 10:57:47 UTC, David Szotten wrote:

Hi,

Yes, via what's called a 'shared extension' (behaves slightly
differently but same principle). see e.g.
https://github.com/nameko/nameko/blob/master/nameko/web/server.py for
an example

let us know if anything's unclear or you need more pointers

best,
david

On Wednesday, 15 March 2017 10:51:44 UTC, simon harrison wrote:

Hiya

Is it possible for a dependency to further depend on another? E.g.

class FooInjection(DependencyProvider):
    ...

class BarInjection(DependencyProvider):
    foo = FooInjection()
    ...

class Service:
    bar = BarInjection()

Thanks

Hello,

here at Namecheap, we’re exploring nameko to be used as our core framework for the microservices.

And I got the exact same question as simon_harrison

An example use case might be a repository pattern.
What if we wanted to use repository pattern for example with nameko-sqlalchemy extension?

class UserService:
    user_repository = UserRepositoryInjection()

    # ...

class UserRepositoryInjection(DependencyProvider):
     def get_dependency(self):
        # how to get Database() dependency of nameko-sqlalchemy in here?
        db = Database()

        return UserRepository(db)

class UserRepository(object):
    def __init__(self, db: SQLAlchemy):
        self.db = db

    def find(self, id: int):
        return self.db.query(User).find(id)

In other words: I didn’t find a way how to properly inject SQLAlchemy dependency into the UserRepository dependency.

1 Like

Hi Titas,

To implement the Repository Pattern you would subclass Database rather than DependencyProvider:

from nameko_sqlalchemy import Database

class UserRepositoryInjection(Database):
    def get_dependency(self, worker_ctx):
        return UserRepository(super().get_dependency(worker_ctx))

class UserRepository(object):
    def __init__(self, db: SQLAlchemy):
        self.db = db

    def find(self, id: int):
        return self.db.query(User).find(id)

We used this pattern at Student.com to inject higher level abstractions into the services, rather than just the bare session. Worked great.

Do the responses to Simon’s question above make sense? Happy to elucidate or give examples for other usecases.

Hi Matt,

thank you for such a quick reply.
Your solution looks nice and clean!

Just one more thing that got in my mind regarding this strategy.
What if a service depends on 2 repositories. Doesn’t it mean that Database dependency would be constructed twice? Can it be a problem and should we care?

If a service depends on two repositories I would want them exposed separately to the service, and wouldn’t worry too much about the Database dependency being constructed twice.

If both repositories share the same underlying schema, you can probably configure Sqlalchemy to use a single shared connection pool. I’ve not actually tried this but it looks like it’s possible.

Am I the only one who thinks this bonkers?

So, instead of our service accepting dependencies it “eats” them? Are we suppose to create cookie monsters now?

What if our service has two/three/four dependencies?

The <service_name>Injection class is actually a factory. Why wouldn’t factories be able to accept instances created by other factories?

Zend Framework 2/3 for example has this pattern done correctly (in my point of view) why not use that?

class BaseRepository(object):

def __init__(self, db, model_cls=None):
    self.db = db
    self.model_cls = model_cls

def q(self, *args) -> Query:
    return self.db.query(*args)

@classmethod
def get_provider(cls):
    class _provider(DatabaseSession):
        def get_dependency(self, worker_ctx):
            model_cls = getattr(cls, "model_cls", None)
            return cls(super().get_dependency(worker_ctx), model_cls)
    return _provider

here is base repo so there no need to create separate dep provider for each repo.
in service initialized like this.
repo = SomeRepo.get_provider()(Base)