Giter Club home page Giter Club logo

Comments (8)

davidparsson avatar davidparsson commented on August 31, 2024 1

PRs are welcome, and it seems to me like a natural evolution of Injector to support this.

But regarding the API, don't you think it would be better to bind the Annotated[...] type instead of adding the named argument?

# ...

LoginUsername = Annotated[str, Name("login_username")]
LoginPassword = Annotated[str, Name("login_password")]

@dataclass
def Login:
    username: LoginUsername
    password: LoginPassword


def configure_from_env(binder):
    binder.bind(LoginUsername, to=lambda: os.environ["LOGIN_USERNAME"])
    binder.bind(LoginPassword, to=lambda: os.environ["LOGIN_PASSWORD"])

I hope the performance hit of NewType is negligible for things that run on Python, but the usability improvement of Annotated is appealing.

from injector.

ljnsn avatar ljnsn commented on August 31, 2024 1

I just opened a PR a that adds support for Annotated. Sorry @jriddy , I kind of needed this and it seemed pretty straightforward (unless I missed something). Would definitely value your input!

from injector.

hmoniz avatar hmoniz commented on August 31, 2024

I just to add one more data point. Interestingly, if I have the binding configured like this:

def configure(self, binder):
    binder.bind(Annotated[Shape, 'first'], to=Circle)
    binder.bind(Annotated[Shape, 'second'], to=Square)

and I get the objects directly from the injector, it works:

injector = Injector(Mod())
injector.get(Annotated[Shape, 'first'])
injector.get(Annotated[Shape, 'second'])

This means that the following provider method that manually constructs the A object also works:

@provider
def provide_a_from_injector(self, injector: Injector) -> A:
    return A(
        injector.get(Annotated[Shape, 'first']),
        injector.get(Annotated[Shape, 'second'])
    )

While this is a potential workaround, I feel like the overall behaviour is too inconsistent to warrant a production use of the framework.

from injector.

davidparsson avatar davidparsson commented on August 31, 2024

I haven't had the time to get into all the details of this issue, but have you tried using NewType instead of Annotated? There's an example in the tests.

from injector.

hmoniz avatar hmoniz commented on August 31, 2024

I have, but unfortunately it doesn't work in situations where I want to inject a ClassAssistedBuilder. For example, let's say I define a type FirstShape = NewType('FirstShape', Shape). Then, in class A, I inject a ClassAssistedBuilder[FirstShape]. When I call build(), I get:

injector.CallError: Call to NewType.__new__() failed: object.__new__(X): X is not a type object (NewType) (injection stack: [])

from injector.

davidparsson avatar davidparsson commented on August 31, 2024

Would the the regular AssistedBuilder work for you here? I haven't tried it myself, but it uses the existing binds so it might work better.

from injector.

jriddy avatar jriddy commented on August 31, 2024

I've been looking at this an I'm thinking about generalizing this pattern. If PRs are welcome I might give it a go to try to cook something up here.

I'm trying to evaluate an ad-hoc injection framework I can use or modify, but the limitation of needing to inject a type is kinda frustrating. It basically pushes you in the direction of using DI solely for creating more complex types that are worth constructing, whereas I often want to encourage devs to do things like express getting an environment variable as a dependency.

FastAPI has a DI implementation that is a good example of this, where it's injecting query strings and stuff from having parsed an HTTP request, but often the underlying types are simple types like str and int. It uses Annotated to declare this metadata and then extracts that to create the binding.

While the design there is a bit different, since FastAPI is an application framework instead of a general-purpose library, I think this pattern could be applied here, such as in this putative code:

from dataclasses import dataclass
from injector import inject, Injector, Name
from typing import Annotated
import os

@inject
@dataclass
def Login:
    username: Annotated[str, Name("login_username")]
    password: Annotated[str, Name("login_password")]


def configure_from_env(binder):
    binder.bind(str, named="login_username", to=lambda: os.environ["LOGIN_USERNAME"])
    binder.bind(str, named="login_password", to=lambda: os.environ["LOGIN_PASSWORD"])


injector = Injector([configure_from_env])
injector.get(Login)

If there's interest I could look into adding this

from injector.

jriddy avatar jriddy commented on August 31, 2024

I haven't had the time to get into all the details of this issue, but have you tried using NewType instead of Annotated? There's an example in the tests.

NewType works sorta, but it leads to an annoying situation where you have to convert everything to your NewType where you use them. And unlike Haskell or Rust or languages like that where this idea is really prevalent, using NewTypes in Python don't get compiled away and do incur a (small) runtime penalty.

from injector.

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.