Package: pinject
Pinject is a dependency injection library for python.The primary goal of Pinject is to help you assemble objects into graphs in an
easy, maintainable way.If you are already familiar with other dependency injection libraries, you may
want to read the condensed summary section at the end, so that you get an idea
of what Pinject is like and how it might differ from libraries you’re used to.There is a changelog of differences between released versions near the end of
this README.Why Pinject?If you’re wondering why to use a dependency injection library at all: if
you’re writing a lot of object-oriented code in python, then it will make your
life easier.  See, for instance:https://en.wikipedia.org/wiki/Dependency_injectionhttp://lmgtfy.com/?q=dependency+injectionIf you’re wondering why to use Pinject instead of another python dependency
injection library, a few of reasons are:Pinject is much easier to get started with.  Forget having to decorate your code with@inject_thisand@annotate_thatjust to get started.  With Pinject, you callnew_object_graph(), one line, and you’re good to go.Pinject is apythonicdependency injection library.  Python ports of other libraries, like Spring or Guice, retain the feel (and verbosity) of being designed for a statically typed language.  Pinject is designed from the ground up for python.The design choices in Pinject are informed by several dependency injection experts working at Google, based on many years of experience.  Several common confusing or misguided features are omitted altogether from Pinject.Pinject has great error messages.  They tell you exactly what you did wrong, and exactly where.  This should be a welcome change from other dependency frameworks, with their voluminous and yet inscrutable stack traces.Look at the simplest getting-started examples for Pinject and for other
similar libraries.  Pinject should be uniformly easier to use, clearer to
read, and less boilerplate that you need to add.  If you don’t find this to be
the case, email!InstallationThe easiest way to install Pinject is to get the latest released version from
PyPI:sudopipinstallpinjectIf you are interested in the developing version, you can install the next version from Test PyPI:sudopipinstall\--no-deps\--no-cache\--upgrade\--index-urlhttps://test.pypi.org/simple/\pinjectYou can also check out all the source code, including tests, designs, and
TODOs:gitclonehttps://github.com/google/pinjectBasic dependency injectionThe most important function in thepinjectmodule isnew_object_graph().  This creates anObjectGraph, which you can use to
instantiate objects using dependency injection.  If you pass no args tonew_object_graph(), it will return a reasonably configured defaultObjectGraph.>>>classOuterClass(object):...def__init__(self,inner_class):...self.inner_class=inner_class...>>>classInnerClass(object):...def__init__(self):...self.forty_two=42...>>>obj_graph=pinject.new_object_graph()>>>outer_class=obj_graph.provide(OuterClass)>>>printouter_class.inner_class.forty_two42>>>As you can see, you don’t need to tell Pinject how to construct itsObjectGraph, and you don’t need to put decorators in your code.  Pinject has
reasonable defaults that allow it to work out of the box.A Pinjectbindingis an association between anarg nameand aprovider.
In the example above, Pinject created a binding between the arg nameinner_classand an implicitly created provider for the classInnerClass.  The binding it had created was how Pinject knew that it
should pass an instance ofInnerClassas the value of theinner_classarg when instantiatingOuterClass.Implicit class bindingsPinject creates implicit bindings for classes.  The implicit bindings assume
your code follows PEP8 conventions: your classes are named inCamelCase,
and your args are named inlower_with_underscores.  Pinject transforms
class names to injectable arg names by lowercasing words and connecting them
with underscores.  It will also ignore any leading underscore on the class
name.Class nameArg nameFoofooFooBarfoo_bar_Foofoo_FooBarfoo_barIf two classes map to the same arg name, whether those classes are in the same
module or different modules, Pinject will not create an implicit binding for
that arg name (though it will not raise an error).Finding classes and providers for implicit bindingsSo far, the examples have not toldnew_object_graph()the classes for
which it should create implicit bindings.new_object_graph()by default
looks in all imported modules, but you may occasionally want to restrict the
classes for whichnew_object_graph()creates implicit bindings.  If so,new_object_graph()has two args for this purpose.Themodulesarg specifies in which (python) modules to look for classes; this defaults toALL_IMPORTED_MODULES.Theclassesarg specifies a exact list of classes; this defaults toNone.>>>classSomeClass(object):...def__init__(self,foo):...self.foo=foo...>>>classFoo(object):...pass...>>>obj_graph=pinject.new_object_graph(modules=None,classes=[SomeClass])>>># obj_graph.provide(SomeClass)  # would raise a NothingInjectableForArgError>>>obj_graph=pinject.new_object_graph(modules=None,classes=[SomeClass,Foo])>>>some_class=obj_graph.provide(SomeClass)>>>Auto-copying args to fieldsOne thing that can get tedious about dependency injection via initializers is
that you need to write__init__()methods that copy args to fields.  These__init__()methods can get repetitive, especially when you have several
initializer args.>>>classClassWithTediousInitializer(object):...def__init__(self,foo,bar,baz,quux):...self._foo=foo...self._bar=bar...self._baz=baz...self._quux=quux...>>>Pinject provides decorators that you can use to avoid repetitive initializer
bodies.@copy_args_to_internal_fieldsprepends an underscore, i.e., it copies an arg namedfooto a field named_foo.  It’s useful for normal classes.@copy_args_to_public_fieldscopies the arg named as-is, i.e., it copies an arg namedfooto a field namedfoo.  It’s useful for data objects.>>>classClassWithTediousInitializer(object):...@pinject.copy_args_to_internal_fields...def__init__(self,foo,bar,baz,quux):...pass...>>>cwti=ClassWithTediousInitializer('a-foo','a-bar','a-baz','a-quux')>>>printcwti._foo'a-foo'>>>When using these decorators, you’ll normallypassin the body of the
initializer, but you can put other statements there if you need to.  The args
will be copied to fields before the initializer body is executed.These decorators can be applied to initializers that take**kwargsbut not
initializers that take*pargs(since it would be unclear what field name
to use).Binding specsTo create any bindings more complex than the implicit class bindings described
above, you use abinding spec.  A binding spec is any python class that
inherits fromBindingSpec.  A binding spec can do three things:Itsconfigure()method can create explicit bindings to classes or instances, as well as requiring bindings without creating them.Itsdependencies()method can return depended-on binding specs.It can have provider methods, for which explicit bindings are created.Thenew_object_graph()function takes a sequence of binding spec instances
as itsbinding_specsarg.new_object_graph()takes binding spec
instances, rather than binding spec classes, so that you can manually inject
any initial dependencies into the binding specs as needed.Binding specs should generally live in files namedbinding_specs.py, where
each file is named in the plural even if there is exactly one binding spec in
it.  Ideally, a directory’s worth of functionality should be coverable with a
single binding spec.  If not, you can create multiple binding specs in the
samebinding_specs.pyfile.  If you have so many binding specs that you
need to split them into multiple files, you should name them each with a_binding_specs.pysuffix.Binding specconfigure()methodsPinject creates implicit bindings for classes, but sometimes the implicit
bindings aren’t what you want.  For instance, if you haveSomeReallyLongClassName, you may not want to name your initializer argssome_really_long_class_namebut instead use something shorter likelong_name, just for this class.For such situations, you can create explicit bindings using theconfigure()method of a binding spec.  Theconfigure()method takes a
functionbind()as an arg and calls that function to create explicit
bindings.>>>classSomeClass(object):...def__init__(self,long_name):...self.long_name=long_name...>>>classSomeReallyLongClassName(object):...def__init__(self):...self.foo='foo'...>>>classMyBindingSpec(pinject.BindingSpec):...defconfigure(self,bind):...bind('long_name',to_class=SomeReallyLongClassName)...>>>obj_graph=pinject.new_object_graph(binding_specs=[MyBindingSpec()])>>>some_class=obj_graph.provide(SomeClass)>>>printsome_class.long_name.foo'foo'>>>Thebind()function passed to a binding function binds its first arg,
which must be an arg name (as astr), to exactly one of two kinds of
things.Usingto_classbinds to a class.  When the binding is used, Pinject injects an instance of the class.Usingto_instancebinds to an instance of some object.  Every time the binding is used, Pinject uses that instance.>>>classSomeClass(object):...def__init__(self,foo):...self.foo=foo...>>>classMyBindingSpec(pinject.BindingSpec):...defconfigure(self,bind):...bind('foo',to_instance='a-foo')...>>>obj_graph=pinject.new_object_graph(binding_specs=[MyBindingSpec()])>>>some_class=obj_graph.provide(SomeClass)>>>printsome_class.foo'a-foo'>>>Theconfigure()method of a binding spec also may take a functionrequire()as an arg and use that function to require that a binding be
present without actually defining that binding.require()takes as args
the name of the arg for which to require a binding.>>>classMainBindingSpec(pinject.BindingSpec):...defconfigure(self,require):...require('foo')...>>>classRealFooBindingSpec(pinject.BindingSpec):...defconfigure(self,bind):...bind('foo',to_instance='a-real-foo')...>>>classStubFooBindingSpec(pinject.BindingSpec):...defconfigure(self,bind):...bind('foo',to_instance='a-stub-foo')...>>>classSomeClass(object):...def__init__(self,foo):...self.foo=foo...>>>obj_graph=pinject.new_object_graph(...binding_specs=[MainBindingSpec(),RealFooBindingSpec()])>>>some_class=obj_graph.provide(SomeClass)>>>printsome_class.foo'a-real-foo'>>># pinject.new_object_graph(...#    binding_specs=[MainBindingSpec()])  # would raise a MissingRequiredBindingError...>>>Being able to require a binding without defining the binding is useful when
you know the code will need some dependency satisfied, but there is more than
one implementation that satisfies that dependency, e.g., there may be a real
RPC client and a fake RPC client.  Declaring the dependency means that any
expected but missing bindings will be detected early, whennew_object_graph()is called, rather than in the middle of running your
program.You’ll notice that theconfigure()methods above have different
signatures, sometimes taking the argbindand sometimes taking the argrequire.configure()methods must take at least one arg that is
eitherbindorrequire, and they may have both args.  Pinject will
pass whichever arg or args yourconfigure()method needs.Binding spec dependenciesBinding specs can declare dependencies.  A binding spec declares its
dependencies by returning a sequence of instances of the dependent binding
specs from itsdependencies()method.>>>classClassOne(object):...def__init__(self,foo):...self.foo=foo....>>>classBindingSpecOne(pinject.BindingSpec):...defconfigure(self,bind):...bind('foo',to_instance='foo-')...>>>classClassTwo(object):...def__init__(self,class_one,bar):...self.foobar=class_one.foo+bar...>>>classBindingSpecTwo(pinject.BindingSpec):...defconfigure(self,bind):...bind('bar',to_instance='-bar')...defdependencies(self):...return[BindingSpecOne()]...>>>obj_graph=pinject.new_object_graph(binding_specs=[BindingSpecTwo()])>>>class_two=obj_graph.provide(ClassTwo)>>>printclass_two.foobar'foo--bar'>>>If classes from module A are injected as collaborators into classes from
module B, then you should consider having the binding spec for module B depend
on the binding spec for module A.  In the example above,ClassOneis
injected as a collaborator intoClassTwo, and soBindingSpecTwo(the
binding spec forClassTwo) depends onBindingSpecOne(the binding spec
forClassOne).In this way, you can build a graph of binding spec dependencies that mirrors
the graph of collaborator dependencies.Since explicit bindings cannot conflict (see the section below on binding
precedence), a binding spec should only have dependencies that there will
never be a choice about using.  If there may be a choice, then it is better to
list the binding specs separately and explicitly when callingnew_object_graph().The binding spec dependencies can be a directed acyclic graph (DAG); that is,
binding spec A can be a dependency of B and of C, and binding spec D can have
dependencies on B and C.  Even though there are multiple dependency paths from
D to A, the bindings in binding spec A will only be evaluated once.The binding spec instance of A that is a dependency of B is considered the
same as the instance that is a dependency of C if the two instances are equal
(via__eq__()).  The default implementation of__eq__()inBindingSpecsays that two binding specs are equal if they are of exactly
the same python type.  You will need to override__eq__()(as well as__hash__()) if your binding spec is parameterized, i.e., if it takes one
or more initializer args so that two instances of the binding spec may behave
differently.>>>classSomeBindingSpec(pinject.BindingSpec):...def__init__(self,the_instance):...self._the_instance=the_instance...defconfigure(self,bind):...bind('foo',to_instance=self._the_instance)...def__eq__(self,other):...return(type(self)==type(other)and...self._the_instance==other._the_instance)...def__hash__(self):...returnhash(type(self))^hash(self._the_instance)...>>>Provider methodsIf it takes more to instantiate a class than calling its initializer and
injecting initializer args, then you can write aprovider methodfor it.
Pinject can use provider methods to instantiate objects used to inject as the
values of other args.Pinject looks on binding specs for methods named like provider methods and
then creates explicit bindings for them.>>>classSomeClass(object):...def__init__(self,foo):...self.foo=foo...>>>classSomeBindingSpec(pinject.BindingSpec):...defprovide_foo(self):...return'some-complex-foo'...>>>obj_graph=pinject.new_object_graph(binding_specs=[SomeBindingSpec()])>>>some_class=obj_graph.provide(SomeClass)>>>printsome_class.foo'some-complex-foo'>>>Pinject looks on binding specs for methods whose names start withprovide_, and it assumes that the methods are providers for whatever the
rest of their method names are.  For instance, Pinject assumes that the methodprovide_foo_bar()is a provider method for the arg namefoo_bar.Pinject injects all args of provider methods that have no default when it
calls the provider method.>>>classSomeClass(object):...def__init__(self,foobar):...self.foobar=foobar...>>>classSomeBindingSpec(pinject.BindingSpec):...defprovide_foobar(self,bar,hyphen='-'):...return'foo'+hyphen+bar...defprovide_bar(self):...return'bar'...>>>obj_graph=pinject.new_object_graph(binding_specs=[SomeBindingSpec()])>>>some_class=obj_graph.provide(SomeClass)>>>printsome_class.foobar'foo-bar'>>>Binding precedenceBindings have precedence: explicit bindings take precedence over implicit
bindings.Explicit bindings are the bindings that come from binding specs.Implicit bindings are the bindings created for classes in themodulesandclassesargs passed tonew_object_graph().Pinject will prefer an explicit to an implicit binding.>>>classSomeClass(object):...def__init__(self,foo):...self.foo=foo...>>>classFoo(object):...pass...>>>classSomeBindingSpec(pinject.BindingSpec):...defconfigure(self,bind):...bind('foo',to_instance='foo-instance')...>>>obj_graph=pinject.new_object_graph(binding_specs=[SomeBindingSpec()])>>>some_class=obj_graph.provide(SomeClass)>>>printsome_class.foo'foo-instance'>>>If you have two classes named the same thing, Pinject will have two different
(and thus conflicting) implicit bindings.  But Pinject will not complain
unless you try to use those bindings.  Pinjectwillcomplain if you try to
create different (and thus conflicting) explicit bindings.SafetyPinject tries to strike a balance between being helpful and being safe.
Sometimes, you may want or need to change this balance.new_object_graph()uses implicit bindings by default.  If you worry that
you may accidentally inject a class or use a provider function
unintentionally, then you can makenew_object_graph()ignore implicit
bindings, by settingonly_use_explicit_bindings=True.  If you do so, then
Pinject will only use explicit bindings.If you want to promote an implicit binding to be an explicit binding, you can
annotate the corresponding class with@inject().  The@inject()decorator lets you create explicit bindings without needing to create binding
specs, as long as you can live with the binding defaults (e.g., no annotations
on args, see below).>>>classExplicitlyBoundClass(object):...@pinject.inject()...def__init__(self,foo):...self.foo=foo...>>>classImplicitlyBoundClass(object):...def__init__(self,foo):...self.foo=foo...>>>classSomeBindingSpec(pinject.BindingSpec):...defconfigure(self,bind):...bind('foo',to_instance='explicit-foo')...>>>obj_graph=pinject.new_object_graph(binding_specs=[SomeBindingSpec()],...only_use_explicit_bindings=True)>>># obj_graph.provide(ImplicitlyBoundClass)  # would raise a NonExplicitlyBoundClassError>>>some_class=obj_graph.provide(ExplicitlyBoundClass)>>>printsome_class.foo'explicit-foo'>>>You can also promote an implicit binding to explicit by using@annotated_arg()(see below), with or without@inject()as well.(Previous versions of Pinject included an@injectabledecorator.  That is
deprecated in favor of@inject().  Note that@inject()needs parens,
whereas@injectabledidn’t.)On the opposite side of permissiveness, Pinject by default will complain if a
provider method returnsNone.  If you really want to turn off this default
behavior, you can passallow_injecting_none=Truetonew_object_graph().AnnotationsPinjectannotationslet you have different objects injected for the same arg
name.  For instance, you may have two classes in different parts of your
codebase named the same thing, and you want to use the same arg name in
different parts of your codebase.On the arg side, an annotation tells Pinject only to inject using a binding
whose binding key includes the annotation object.  You can use@annotate_arg()on an initializer, or on a provider method, to specify the
annotation object.On the binding side, an annotation changes the binding so that the key of the
binding includes the annotation object.  When usingbind()in a binding
spec’sconfigure()method, you can pass anannotated_witharg to
specify the annotation object.>>>classSomeClass(object):...@pinject.annotate_arg('foo','annot')...def__init__(self,foo):...self.foo=foo...>>>classSomeBindingSpec(pinject.BindingSpec):...defconfigure(self,bind):...bind('foo',annotated_with='annot',to_instance='foo-with-annot')...bind('foo',annotated_with=12345,to_instance='12345-foo')...>>>obj_graph=pinject.new_object_graph(binding_specs=[SomeBindingSpec()])>>>some_class=obj_graph.provide(SomeClass)>>>printsome_class.foo'foo-with-annot'>>>Also on the binding side, when defining a provider method, you can use the@provides()decorator.  The decorator lets you pass anannotated_witharg to specify the annotation object.  The decorator’s first param,arg_namealso lets you override what arg name you want the provider to be
for.  This is optional but useful if you want the same binding spec to have
two provider methods for the same arg name but annotated differently.
(Otherwise, the methods would need to be named the same, since they’re for the
same arg name.)>>>classSomeClass(object):...@pinject.annotate_arg('foo','annot')...def__init__(self,foo):...self.foo=foo...>>>classSomeBindingSpec(pinject.BindingSpec):...@pinject.provides('foo',annotated_with='annot')...defprovide_annot_foo(self):...return'foo-with-annot'...@pinject.provides('foo',annotated_with=12345)...defprovide_12345_foo(self):...return'12345-foo'...>>>obj_graph=pinject.new_object_graph(binding_specs=[SomeBindingSpec()])>>>some_class=obj_graph.provide(SomeClass)>>>printsome_class.foo'foo-with-annot'>>>When requiring a binding, via therequirearg passed into theconfigure()method of a binding spec, you can pass the argannotated_withto require an annotated binding.>>>classMainBindingSpec(pinject.BindingSpec):...defconfigure(self,require):...require('foo',annotated_with='annot')...>>>classNonSatisfyingBindingSpec(pinject.BindingSpec):...defconfigure(self,bind):...bind('foo',to_instance='an-unannotated-foo')...>>>classSatisfyingBindingSpec(pinject.BindingSpec):...defconfigure(self,bind):...bind('foo',annotated_with='annot',to_instance='an-annotated-foo')...>>>obj_graph=pinject.new_object_graph(...binding_specs=[MainBindingSpec(),SatisfyingBindingSpec()])# works>>># obj_graph = pinject.new_object_graph(...#     binding_specs=[MainBindingSpec(),...#                    NonSatisfyingBindingSpec()])  # would raise a MissingRequiredBindingError>>>You can use any kind of object as an annotation object as long as it
implements__eq__()and__hash__().ScopesBy default, Pinject remembers the object it injected into a (possibly
annotated) arg, so that it can inject the same object into other args with the
same name.  This means that, for each arg name, a single instance of the
bound-to class, or a single instance returned by a provider method, is created
by default.>>>classSomeClass(object):...def__init__(self,foo):...self.foo=foo...>>>classSomeBindingSpec(pinject.BindingSpec):...defprovide_foo(self):...returnobject()...>>>obj_graph=pinject.new_object_graph(binding_specs=[SomeBindingSpec()])>>>some_class_1=obj_graph.provide(SomeClass)>>>some_class_2=obj_graph.provide(SomeClass)>>>printsome_class_1.fooissome_class_2.fooTrue>>>In some cases, you may want to create new instances, always or sometimes,
instead of reusing them each time they’re injected.  If so, you want to usescopes.A scope controls memoization (i.e., caching).  A scope can choose to cache
never, sometimes, or always.Pinject has two built-in scopes.Singleton scope(SINGLETON) is the
default and always caches.Prototype scope(PROTOTYPE) is the other
built-in option and does no caching whatsoever.Every binding is associated with a scope.  You can specify a scope for a
binding by decorating a provider method with@in_scope(), or by passing anin_scopearg tobind()in a binding spec’sconfigure()method.>>>classSomeClass(object):...def__init__(self,foo):...self.foo=foo...>>>classSomeBindingSpec(pinject.BindingSpec):...@pinject.provides(in_scope=pinject.PROTOTYPE)...defprovide_foo(self):...returnobject()...>>>obj_graph=pinject.new_object_graph(binding_specs=[SomeBindingSpec()])>>>some_class_1=obj_graph.provide(SomeClass)>>>some_class_2=obj_graph.provide(SomeClass)>>>printsome_class_1.fooissome_class_2.fooFalse>>>If a binding specifies no scope explicitly, then it is in singleton scope.
Implicit class bindings are always in singleton scope.Memoization of class bindings works at the class level, not at the binding key
level.  This means that, if you bind two arg names (or the same arg name with
two different annotations) to the same class, and the class is in a memoizing
scope, then the same class instance will be provided when you inject the
different arg names.>>>classInjectedClass(object):...pass...>>>classSomeObject(object):...def__init__(self,foo,bar):...self.foo=foo...self.bar=bar...>>>classSomeBindingSpec(pinject.BindingSpec):...defconfigure(self,bind):...bind('foo',to_class=InjectedClass)...bind('bar',to_class=InjectedClass)...>>>obj_graph=pinject.new_object_graph(...binding_specs=[SomeBindingSpec()])>>>some_object=obj_graph.provide(SomeObject)>>>printsome_object.fooissome_object.barTrue>>>Pinject memoizes class bindings this way because this is more likely to be
what you mean if you bind two different arg names to the same class in
singleton scope: you want only one instance of the class, even though it may
be injected in multiple places.Provider bindingsSometimes, you need to inject not just a single instance of some class, but
rather you need to inject the ability to create instances on demand.
(Clearly, this is most useful when the binding you’re using is not in the
singleton scope, otherwise you’ll always get the same instance, and you may as
well just inject that..)You could inject the Pinject object graph, but you’d have to do that
dependency injection manually (Pinject doesn’t inject itself!), and you’d be
injecting a huge set of capabilities when your class really only needs to
instantiate objects of one type.To solve this, Pinject createsprovider bindingsfor each bound arg name.
It will look at the arg name for the prefixprovide_, and if it finds that
prefix, it assumes you want to inject a provider function for whatever the
rest of the arg name is.  For instance, if you have an arg namedprovide_foo_bar, then Pinject will inject a zero-arg function that, when
called, provides whatever the arg namefoo_baris bound to.>>>classFoo(object):...def__init__(self):...self.forty_two=42...>>>classSomeBindingSpec(pinject.BindingSpec):...defconfigure(self,bind):...bind('foo',to_class=Foo,in_scope=pinject.PROTOTYPE)...>>>classNeedsProvider(object):...def__init__(self,provide_foo):...self.provide_foo=provide_foo...>>>obj_graph=pinject.new_object_graph(binding_specs=[SomeBindingSpec()])>>>needs_provider=obj_graph.provide(NeedsProvider)>>>printneeds_provider.provide_foo()isneeds_provider.provide_foo()False>>>printneeds_provider.provide_foo().forty_two42>>>Pinject will always look for theprovide_prefix as a signal to inject a
provider function, anywhere it injects dependencies (initializer args, binding
spec provider methods, etc.).  This does mean that it’s quite difficult, say,
to inject an instance of a class namedProvideFooBarinto an arg namedprovide_foo_bar, but assuming you’re naming your classes as noun phrases
instead of verb phrases, this shouldn’t be a problem.Watch out: don’t confuseprovider bindings, which let you inject args namedprovide_somethingwith provider functions; andprovider methods, which are methods of binding specs that provide instances of some arg name.Partial injectionProvider bindings are useful when you want to create instances of a class on
demand.  But a zero arg provider function will always return an instance
configured the same way (within a given scope).  Sometimes, you want the
ability to parameterize the provided instances, e.g., based on run-time user
configuration.  You want the ability to create instances where part of the
initialization data is provided per-instance at run-time and part of the
initialization data is injected as dependencies.To do this, other dependency injection libraries have you define factory
classes.  You inject dependencies into the factory class’s initializer
function, and then you call the factory class’s creation method with the
per-instance data.>>>classWidgetFactory(object):...def__init__(self,widget_polisher):...self._widget_polisher=widget_polisher...defnew(self,color):# normally would contain some non-trivial code......returnsome_function_of(self._widget_polisher,color)...>>>classSomeBindingSpec(pinject.BindingSpec):...defprovide_something_with_colored_widgets(self,colors,widget_factory):...returnSomethingWithColoredWidgets(...[widget_factory.new(color)forcolorincolors])...>>>You can follow this pattern in Pinject, but it involves boring boilerplate for
the factory class, saving away the initializer-injected dependencies to be
used in the creation method.  Plus, you have to create yet another...Factoryclass, which makes you feel like you’re programming in java,
not python.As a less repetitive alternative, Pinject lets you usepartial injectionon
the provider functions returned by provider bindings.  You use the@inject()decorator to tell Pinject ahead of time which args you expect to
pass directly (vs. automatic injection), and then you pass those args directly
when calling the provider function.>>>classSomeBindingSpec(pinject.BindingSpec):...@pinject.inject(['widget_polisher'])...defprovide_widget(self,color,widget_polisher):...returnsome_function_of(widget_polisher,color)...defprovide_something_needing_widgets(self,colors,provide_widget):...returnSomethingNeedingWidgets(...[provide_widget(color)forcolorincolors])...>>>The first arg to@inject(),arg_names, specifies which args of the
decorated method should be injected as dependencies.  If specified, it must be
a non-empty sequence of names of the decorated method’s args.  The remaining
decorated method args will be passed directly.In the example above, note that, although there is a method calledprovide_widget()and an arg ofprovide_something_needing_widgets()calledprovide_widget, these are not exactly the same!  The latter is a
dependency-injected wrapper around the former.  The wrapper ensures that thecolorarg is passed directly and then injects thewidget_polisherdependency.The@inject()decorator works to specify args passed directly both for
provider bindings to provider methods (as in the example above) and for
provider bindings to classes (where you can pass args directly to the
initializer, as in the example below).>>>classWidget(object):...@pinject.inject(['widget_polisher'])...def__init__(self,color,widget_polisher):...pass# normally something involving color and widget_polisher...>>>classSomeBindingSpec(pinject.BindingSpec):...defprovide_something_needing_widgets(self,colors,provide_widget):...returnSomethingNeedingWidgets(...[provide_widget(color)forcolorincolors])...>>>The@inject()decorator also takes anall_exceptarg.  You can use
this, instead of the (first positional)arg_namesarg, if it’s clearer and
more concise to say which args arenotinjected (i.e., which args are passed
directly).>>>classWidget(object):...# equivalent to @pinject.inject(['widget_polisher']):...@pinject.inject(all_except=['color'])...def__init__(self,color,widget_polisher):...pass# normally something involving color and widget_polisher...>>>If botharg_namesandall_exceptare omitted, then all args are
injected by Pinject, and none are passed directly.  (Botharg_namesandall_exceptmay not be specified at the same time.)  Wildcard positional
and keyword args (i.e.,*pargsand**kwargs) are always passed
directly, not injected.If you use@inject()to mark at least one arg of a provider method (or
initializer) as passed directly, then you may no longer directly inject that
provider method’s corresponding arg name.  You must instead use a provider
binding to inject a provider function, and then pass the required direct
arg(s), as in the examples above.Custom scopesIf you want to, you can create your own custom scope.  A custom scope is
useful when you have some objects that need to be reused (i.e., cached) but
whose lifetime is shorter than the entire lifetime of your program.A custom scope is any class that implements theScopeinterface.classScope(object):defprovide(self,binding_key,default_provider_fn):raiseNotImplementedError()Thebinding_keypassed toprovide()will be an object implementing__eq__()and__hash__()but otherwise opaque (you shouldn’t need to
introspect it).  You can think of the binding key roughly as encapsulating the
arg name and annotation (if any).  Thedefault_provider_fnpassed toprovide()is a zero-arg function that, when called, provides an instance
of whatever should be provided.The job of a scope’sprovide()function is to return a cached object if
available and appropriate, otherwise to return (and possibly cache) the result
of calling the default provider function.Scopes almost always have other methods that control clearing the scope’s
cache.  For instance, a scope may have “enter scope” and “exit scope” methods,
or a single direct “clear cache” method.  When passing a custom scope to
Pinject, your code should keep a handle to the custom scope and use that
handle to clear the scope’s cache at the appropriate time.You can use one or more custom scopes by passing a map fromscope identifierto scope as theid_to_scopearg ofnew_object_graph().>>>classMyScope(pinject.Scope):...def__init__(self):...self._cache={}...defprovide(self,binding_key,default_provider_fn):...ifbinding_keynotinself._cache:...self._cache[binding_key]=default_provider_fn()...returnself._cache[binding_key]...defclear(self):...self._cache={}...>>>classSomeClass(object):...def__init__(self,foo):...self.foo=foo...>>>classSomeBindingSpec(pinject.BindingSpec):...@pinject.provides(in_scope='my custom scope')...defprovide_foo(self):...returnobject()...>>>my_scope=MyScope()>>>obj_graph=pinject.new_object_graph(...binding_specs=[SomeBindingSpec()],...id_to_scope={'my custom scope':my_scope})>>>some_class_1=obj_graph.provide(SomeClass)>>>some_class_2=obj_graph.provide(SomeClass)>>>my_scope.clear()>>>some_class_3=obj_graph.provide(SomeClass)>>>printsome_class_1.fooissome_class_2.fooTrue>>>printsome_class_2.fooissome_class_3.fooFalse>>>A scope identifier can be any object implementing__eq__()and__hash__().If you plan to use Pinject in a multi-threaded environment (and even if you
don’t plan to now but may some day), you should make your custom scope
thread-safe.  The example custom scope above could be trivially (but more
verbosely) rewritten to be thread-safe, as in the example below.  The lock is
reentrant so that something inMyScopecan be injected into something else
inMyScope.>>>classMyScope(pinject.Scope):...def__init__(self):...self._cache={}...self._rlock=threading.RLock()...defprovide(self,binding_key,default_provider_fn):...withself._rlock:...ifbinding_keynotinself._cache:...self._cache[binding_key]=default_provider_fn()...returnself._cache[binding_key]...defclear(self):...withself._rlock:...self._cache={}>>>Scope accessibilityTo prevent yourself from injecting objects where they don’t belong, you may
want to validate one object being injected into another w.r.t. scope.For instance, you may have created a custom scope for HTTP requests handled by
your program.  Objects in request scope would be cached for the duration of a
single HTTP request.  You may want to verify that objects in request scope
never get injected into objects in singleton scope.  Such an injection is
likely not to make semantic sense, since it would make something tied to one
HTTP request be used for the duration of your program.Pinject lets you pass a validation function as theis_scope_usable_from_scopearg tonew_object_graph().  This function
takes two scope identifiers and returnsTrueiff an object in the first
scope can be injected into an object of the second scope.>>>classRequestScope(pinject.Scope):...defstart_request(self):...self._cache={}...defprovide(self,binding_key,default_provider_fn):...ifbinding_keynotinself._cache:...self._cache[binding_key]=default_provider_fn()...returnself._cache[binding_key]...>>>classSomeClass(object):...def__init__(self,foo):...self.foo=foo...>>>classSomeBindingSpec(pinject.BindingSpec):...@pinject.provides(in_scope=pinject.SINGLETON)...defprovide_foo(bar):...return'foo-'+bar...@pinject.provides(in_scope='request scope')...defprovide_bar():...return'-bar'...>>>defis_usable(scope_id_inner,scope_id_outer):...returnnot(scope_id_inner=='request scope'and...scope_id_outer==scoping.SINGLETON)...>>>my_request_scope=RequestScope()>>>obj_graph=pinject.new_object_graph(...binding_specs=[SomeBindingSpec()],...id_to_scope={'request scope':my_request_scope},...is_scope_usable_from_scope=is_usable)>>>my_request_scope.start_request()>>># obj_graph.provide(SomeClass)  # would raise a BadDependencyScopeError>>>The default scope accessibility validator allows objects from any scope to be
injected into objects from any other scope.Changing naming conventionsIf your code follows PEP8 naming coventions, then you’re likely happy with the
default implicit bindings (where the classFooBargets bound to the arg
namefoo_bar) and whereprovide_foo_bar()is a binding spec’s provider
method for the arg namefoo_bar.But if not, read on!Customizing implicit bindingsnew_object_graph()takes aget_arg_names_from_class_namearg.  This is
the function that is used to determine implicit class bindings.  This function
takes in a class name (e.g.,FooBar) and returns the arg names to which
that class should be implicitly bound (e.g.,['foo_bar']).  Its default
behavior is described in the “implicit class bindings” section above, but that
default behavior can be overridden.For instance, suppose that your code uses a library that names many classes
with the leading letter X (e.g.,XFooBar), and you’d like to be able to
bind that to a corresponding arg name without the leading X (e.g.,foo_bar).>>>importre>>>defcustom_get_arg_names(class_name):...stripped_class_name=re.sub('^_?X?','',class_name)...return[re.sub('(?!^)([A-Z]+)',r'_\1',stripped_class_name).lower()]...>>>printcustom_get_arg_names('XFooBar')['foo_bar']>>>printcustom_get_arg_names('XLibraryClass')['library_class']>>>classOuterClass(object):...def__init__(self,library_class):...self.library_class=library_class...>>>classXLibraryClass(object):...def__init__(self):...self.forty_two=42...>>>obj_graph=pinject.new_object_graph(...get_arg_names_from_class_name=custom_get_arg_names)>>>outer_class=obj_graph.provide(OuterClass)>>>printouter_class.library_class.forty_two42>>>The function passed as theget_arg_names_from_class_namearg tonew_object_graph()can return as many or as few arg names as it wants.  If
it always returns the empty list (i.e., if it islambda _: []), then that
disables implicit class bindings.Customizing binding spec method namesThe standard binding spec methods to configure bindings and declare
dependencies are namedconfigureanddependencies, by default.  If you
need to, you can change their names by passingconfigure_method_nameand/ordependencies_method_nameas args tonew_object_graph().>>>classNonStandardBindingSpec(pinject.BindingSpec):...defConfigure(self,bind):...bind('forty_two',to_instance=42)...>>>classSomeClass(object):...def__init__(self,forty_two):...self.forty_two=forty_two...>>>obj_graph=pinject.new_object_graph(...binding_specs=[NonStandardBindingSpec()],...configure_method_name='Configure')>>>some_class=obj_graph.provide(SomeClass)>>>printsome_class.forty_two42>>>Customizing provider method namesnew_object_graph()takes aget_arg_names_from_provider_fn_namearg.
This is the function that is used to identify provider methods on binding
specs.  This function takes in the name of a potential provider method (e.g.,provide_foo_bar) and returns the arg names for which the provider method
is a provider, if any (e.g.,['foo_bar']).  Its default behavior is
described in the “provider methods” section above, but that default behavior
can be overridden.For instance, suppose that you work for a certain large corporation whose
python style guide makes you name functions inCamelCase, and so you need
to name the provider method for the arg namefoo_barmore likeProvideFooBarthanprovide_foo_bar.>>>importre>>>defCustomGetArgNames(provider_fn_name):...ifprovider_fn_name.startswith('Provide'):...provided_camelcase=provider_fn_name[len('Provide'):]...return[re.sub('(?!^)([A-Z]+)',r'_\1',provided_camelcase).lower()]...else:...return[]...>>>printCustomGetArgNames('ProvideFooBar')['foo_bar']>>>printCustomGetArgNames('ProvideFoo')['foo']>>>classSomeClass(object):...def__init__(self,foo):...self.foo=foo...>>>classSomeBindingSpec(pinject.BindingSpec):...defProvideFoo(self):...return'some-foo'...>>>obj_graph=pinject.new_object_graph(...binding_specs=[SomeBindingSpec()],...get_arg_names_from_provider_fn_name=CustomGetArgNames)>>>some_class=obj_graph.provide(SomeClass)>>>printsome_class.foo'some-foo'>>>The function passed as theget_arg_names_from_provider_fn_namearg tonew_object_graph()can return as many or as few arg names as it wants.  If
it returns an empty list, then that potential provider method is assumed not
actually to be a provider method.MiscellaneousPinject raises helpful exceptions whose messages include the file and line
number of errors.  So, Pinject by default will shorten the stack trace of
exceptions that it raises, so that you don’t see the many levels of function
calls within the Pinject library.In some situations, though, the complete stack trace is helpful, e.g., when
debugging Pinject, or when your code calls Pinject, which calls back into your
code, which calls back into Pinject.  In such cases, to disable exception
stack shortening, you can passuse_short_stack_traces=Falsetonew_object_graph().GotchasPinject has a few things to watch out for.Thread safetyPinject’s default scope isSINGLETON.  If you have a multi-threaded
program, it’s likely that some or all of the things that Pinject provides from
singleton scope will be used in multiple threads.  So, it’s important that you
ensure that such classes are thread-safe.Similarly, it’s important that your custom scope classes are thread-safe.
Even if the objects they provide are only used in a single thread, it may be
that the object graph (and therefore the scope itself) will be used
simultaneously in multiple threads.Remember to make locks re-entrant on your custom scope classes, or otherwise
deal with one object in your custom scope trying to inject another object in
your custom scope.That’s it for gotchas, for now.Condensed summaryIf you are already familiar with dependency injection libraries such as Guice,
this section gives you a condensed high level summary of Pinject and how it
might be similar to or different than other dependency injection libraries.
(If you don’t understand it, no problem.  The rest of the documentation covers
everything listed here.)Pinject uses code and decorators to configure injection, not a separate config file.Bindings are keyed by arg name, (not class type, since Python is dynamically typed).Pinject automatically creates bindings tosome_classarg names forSomeClassclasses.You can ask Pinject only to create bindings from binding specs and classes whose__init__()is marked with@inject().A binding spec is a class that creates explicit bindings.A binding spec can bind arg names to classes or to instances.A binding spec can bind arg namesfooto provider methodsprovide_foo().Binding specs can depend on (i.e., include) other binding specs.You can annotate args and bindings to distinguish among args/bindings for the same arg name.Pinject has two built-in scopes: “singleton” (always memoized; the default) and “prototype” (never memoized).You can define custom scopes, and you can configure which scopes are accessible from which other scopes.Pinject doesn’t allow injectingNoneby default, but you can turn off that check.Changelogv0.13: masterv0.12: 28 Nov, 2018Support Python 3Add two maintainers: @trein and @huanv0.10.2:Fixed bug: allows binding specs containing only provider methods.v0.10.1:Fixed bug: allows omitting custom namedconfigure()binding spec method.v0.10:Added default__eq__()toBindingSpec, so that DAG binding spec dependencies can have equal but not identical dependencies.Allowed customizingconfigure()anddependencies()binding spec method names.Deprecated@injectablein favor of@inject.Added partial injection.Addedrequirearg to allow binding specconfiguremethods to declare but not define bindings.Sped up tests (and probably general functionality) by 10x.Documented more design decisions.Added@copy_args_to_internal_fieldsand@copy_args_to_public_fields.RenamedInjectableDecoratorAppliedToNonInitErrortoDecoratorAppliedToNonInitError.v0.9:Added validation of python types of public args.Improved error messages for all Pinject-raised exceptions.Addeduse_short_stack_tracesarg tonew_object_graph().Allowed multiple@provideson single provider method.v0.8:First released version.MaintainersKurt Steinkraus @kurtGuilherme Trein @treinHuan LI @huanLicenseApache-2.0Pinject and GoogleThough Google owns this project’s copyright, this project is not an official
Google product.