Skip to main content

nameko-injector

injector based dependency injection mechanism for nameko services. Project is similar to flask-injector.

Problem

Nameko provides a dependency injection mechanism, built-in in the framework. It works in many cases with the limitations:

  1. All the dependencies are injected regardless of whether they are used in the entry-point. For instance, all the dependencies will be injected for /health HTTP entry point.

  2. Dependencies cannot depend on each other.

  3. The scope is an implementation detail. Frequency of the dependency creation depends on the DependencyProvider implementation.

  4. Subjectively, implementing a new DependencyProvider is not the easiest the task for the developers.

Solution

The library provides an alternative dependency injection mechanism to the one that is built-in in nameko. Several types of request scope can be used out of the box without special injector module declarations.

  • from nameko.containers.ServiceContainer

  • from nameko.containers.WorkerContext

  • werkzeug.wrappers.Request, in case of HTTP requests

The library provides 2 scopes:

  • nameko_injector.core.request_scope where each request has own instance of the injected type.

  • nameko_injected.core.resource_request_scope it’s like request_scope but also close method is called on each injected value after the request is processed to free the resources on DependencyProvider.worker_teardown call.

An example of the test that declares service class and configuration provider:

import json
import typing as t

import injector
import pytest
from nameko.containers import ServiceContainer
from nameko.web.handlers import http
from nameko_injector.core import NamekoInjector


class ServiceConfig:
    value: t.Mapping


@injector.provider
def provide_service_config(container: ServiceContainer) -> ServiceConfig:
    return container.config


def configure(binder):
    binder.bind(
        ServiceConfig,
        to=provide_service_config,
        scope=injector.singleton,
    )


INJECTOR = NamekoInjector(configure)


@INJECTOR.decorate_service
class Service:

    name = "service-name"

    @http("GET", "/config")
    def view_config(self, request, config: ServiceConfig):
        # 'config' is injected as singleton in each request that specifies it's type in
        # the view function's signature.
        return json.dumps(config)

Testing with library (pytest)

The library provides a plugin for pytest with some basic fixtures. To enable the plugin, add the following line in your conftest.py module.

pytest_plugins = [
    "nameko_injector.testing.pytest_fixtures",
]

Graph of fixtures generated from the test

pytest --fixture-graph tests/test_http.py::test_http_request_injected
assets/fixtures_graph.png

There are several fixtures that help during the testing. All of the fixtures have function pytest scope.

  • service_class fixture that MUST be redefined and return a service class under the test.

  • web_service fixture starts a real HTTP server to make real HTTP requests to the service. It can be used together with nameko’s fixture web_session that injects HTTP client that knows a correct port. See tests/test_injected.py as an example.

  • injector_in_test fixture gives access to the injector.Injector instance that will resolve the dependencies in the instance of service_class. The fixture uses a child injector from the one that decorates the service that provides isolation between the test cases with the same class under the test. By default, it uses worker_context fixture.

  • container_overridden_dependencies - web_service uses this mapping of nameko dependencies that need to be overridden with the instance values.

  • worker_ctx fixture is used to get injector_in_test value but it’s a mock and might be redefined in your tests.

How to redefine dependency?

Let’s assume that service depends on an HTTP client for some 3rd-party service. In our test, we would like to use a mocked version of it. In that case, we need to redefine injector_in_test fixture.

@pytest.fixture
def injector_in_test(injector_in_test, mocked_http_client):
    injector_in_test.binder.bind(ThirdPartyServiceHttpClient, to=mocked_http_client)
    # injector_in_test.binder.install(MockedClientModule())
    return injector_in_test

Sophisticated cases

In more sophisticated cases when we redefine how the server is started with runner_factories main task is to ensure that the container (service instance basically) has a valid injector. See nameko_injector/testing/pytest_fixtures.py:web_service code as an example. Main line there is replace_dependencies(container, **container_overridden_dependencies).

Development

tox

Release files for nameko-injector 1.1.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for nameko-injector 1.1.2
File Size Uploaded
nameko-injector-1.1.2.tar.gz 12.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for nameko-injector 1.1.2
File Interpreter ABI Platform
nameko_injector-1.1.2-py3-none-any.whl Python 3 none any Details

Total release size: 27.7 kB

Release files / nameko-injector-1.1.2.tar.gz

Download URL nameko-injector-1.1.2.tar.gz
Size 12.6 kB
Tags Source
SHA-256 checksum
How to use checksums
3aca6aef8e7f1c26eb340954ecb302ae6159d1999281f7fa1e5f2bd4db91d0af
BLAKE2b-256 checksum
How to use checksums
d946aee290a60e36d30ea8580373797048870e6684fada0c5494435fb6aa4a4a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via Python-urllib/3.6

Release files / nameko_injector-1.1.2-py3-none-any.whl

Download URL nameko_injector-1.1.2-py3-none-any.whl
Size 15.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c415c9b1ffe17fb3320d61fc31adb9e763b9878bd31789e58a97883186e8608b
BLAKE2b-256 checksum
How to use checksums
41aef6f40b4a118c1a6c4edd4bea427f59e5b4974f02d501bd722481bf5315b5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via Python-urllib/3.6

Release history Release notifications | RSS feed

This release

1.1.2 This release

2 release files

1.1.1

2 release files

1.1.0

2 release files

1.0.1

2 release files

1.0.0

2 release files

0.1.2

1 release file

0.1.1

1 release file

0.1.0

1 release file

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page