{ "info": { "author": "Kurt Steinkraus", "author_email": "kurt@steinkraus.us", "bugtrack_url": null, "classifiers": [], "description": "=========\n Pinject\n=========\n\n.. image:: https://badge.fury.io/py/pinject.svg\n :target: https://pypi.org/project/pinject/\n.. image:: https://travis-ci.com/google/pinject.svg?branch=master\n :target: https://travis-ci.com/google/pinject\n.. image:: https://pepy.tech/badge/pinject\n :target: https://pepy.tech/badge/pinject\n.. image:: https://pepy.tech/badge/pinject/month\n :target: https://pepy.tech/badge/pinject\n\nPinject is a dependency injection library for python.\n\nThe primary goal of Pinject is to help you assemble objects into graphs in an\neasy, maintainable way.\n\nIf you are already familiar with other dependency injection libraries, you may\nwant to read the condensed summary section at the end, so that you get an idea\nof what Pinject is like and how it might differ from libraries you're used to.\n\nThere is a changelog of differences between released versions near the end of\nthis README.\n\nWhy Pinject?\n============\n\nIf you're wondering why to use a dependency injection library at all: if\nyou're writing a lot of object-oriented code in python, then it will make your\nlife easier. See, for instance:\n\n* https://en.wikipedia.org/wiki/Dependency_injection\n* http://lmgtfy.com/?q=dependency+injection\n\nIf you're wondering why to use Pinject instead of another python dependency\ninjection library, a few of reasons are:\n\n* Pinject is much easier to get started with. Forget having to decorate your code with ``@inject_this`` and ``@annotate_that`` just to get started. With Pinject, you call ``new_object_graph()``, one line, and you're good to go.\n* Pinject is a *pythonic* dependency 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.\n* 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.\n* 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.\n\nLook at the simplest getting-started examples for Pinject and for other\nsimilar libraries. Pinject should be uniformly easier to use, clearer to\nread, and less boilerplate that you need to add. If you don't find this to be\nthe case, email!\n\nInstallation\n============\n\nThe easiest way to install Pinject is to get the latest released version from\nPyPI:\n\n.. code-block:: shell\n\n sudo pip install pinject\n\nIf you are interested in the developing version, you can install the next version from Test PyPI:\n\n.. code-block:: shell\n\n sudo pip install \\\n --no-deps \\\n --no-cache \\\n --upgrade \\\n --index-url https://test.pypi.org/simple/ \\\n pinject\n\nYou can also check out all the source code, including tests, designs, and\nTODOs:\n\n.. code-block:: shell\n\n git clone https://github.com/google/pinject\n\nBasic dependency injection\n==========================\n\nThe most important function in the ``pinject`` module is\n``new_object_graph()``. This creates an ``ObjectGraph``, which you can use to\ninstantiate objects using dependency injection. If you pass no args to\n``new_object_graph()``, it will return a reasonably configured default\n``ObjectGraph``.\n\n.. code-block:: python\n\n >>> class OuterClass(object):\n ... def __init__(self, inner_class):\n ... self.inner_class = inner_class\n ...\n >>> class InnerClass(object):\n ... def __init__(self):\n ... self.forty_two = 42\n ...\n >>> obj_graph = pinject.new_object_graph()\n >>> outer_class = obj_graph.provide(OuterClass)\n >>> print outer_class.inner_class.forty_two\n 42\n >>>\n\nAs you can see, you don't need to tell Pinject how to construct its\n``ObjectGraph``, and you don't need to put decorators in your code. Pinject has\nreasonable defaults that allow it to work out of the box.\n\nA Pinject *binding* is an association between an *arg name* and a *provider*.\nIn the example above, Pinject created a binding between the arg name\n``inner_class`` and an implicitly created provider for the class\n``InnerClass``. The binding it had created was how Pinject knew that it\nshould pass an instance of ``InnerClass`` as the value of the ``inner_class``\narg when instantiating ``OuterClass``.\n\nImplicit class bindings\n=======================\n\nPinject creates implicit bindings for classes. The implicit bindings assume\nyour code follows PEP8 conventions: your classes are named in ``CamelCase``,\nand your args are named in ``lower_with_underscores``. Pinject transforms\nclass names to injectable arg names by lowercasing words and connecting them\nwith underscores. It will also ignore any leading underscore on the class\nname.\n\n+-------------+-------------+\n| Class name | Arg name |\n+=============+=============+\n| ``Foo`` | ``foo`` |\n+-------------+-------------+\n| ``FooBar`` | ``foo_bar`` |\n+-------------+-------------+\n| ``_Foo`` | ``foo`` |\n+-------------+-------------+\n| ``_FooBar`` | ``foo_bar`` |\n+-------------+-------------+\n\nIf two classes map to the same arg name, whether those classes are in the same\nmodule or different modules, Pinject will not create an implicit binding for\nthat arg name (though it will not raise an error).\n\nFinding classes and providers for implicit bindings\n===================================================\n\nSo far, the examples have not told ``new_object_graph()`` the classes for\nwhich it should create implicit bindings. ``new_object_graph()`` by default\nlooks in all imported modules, but you may occasionally want to restrict the\nclasses for which ``new_object_graph()`` creates implicit bindings. If so,\n``new_object_graph()`` has two args for this purpose.\n\n* The ``modules`` arg specifies in which (python) modules to look for classes; this defaults to ``ALL_IMPORTED_MODULES``.\n* The ``classes`` arg specifies a exact list of classes; this defaults to ``None``.\n\n.. code-block:: python\n\n >>> class SomeClass(object):\n ... def __init__(self, foo):\n ... self.foo = foo\n ...\n >>> class Foo(object):\n ... pass\n ...\n >>> obj_graph = pinject.new_object_graph(modules=None, classes=[SomeClass])\n >>> # obj_graph.provide(SomeClass) # would raise a NothingInjectableForArgError\n >>> obj_graph = pinject.new_object_graph(modules=None, classes=[SomeClass, Foo])\n >>> some_class = obj_graph.provide(SomeClass)\n >>>\n\nAuto-copying args to fields\n===========================\n\nOne thing that can get tedious about dependency injection via initializers is\nthat you need to write ``__init__()`` methods that copy args to fields. These\n``__init__()`` methods can get repetitive, especially when you have several\ninitializer args.\n\n.. code-block:: python\n\n >>> class ClassWithTediousInitializer(object):\n ... def __init__(self, foo, bar, baz, quux):\n ... self._foo = foo\n ... self._bar = bar\n ... self._baz = baz\n ... self._quux = quux\n ...\n >>>\n\nPinject provides decorators that you can use to avoid repetitive initializer\nbodies.\n\n* ``@copy_args_to_internal_fields`` prepends an underscore, i.e., it copies an arg named ``foo`` to a field named ``_foo``. It's useful for normal classes.\n* ``@copy_args_to_public_fields`` copies the arg named as-is, i.e., it copies an arg named ``foo`` to a field named ``foo``. It's useful for data objects.\n\n.. code-block:: python\n\n >>> class ClassWithTediousInitializer(object):\n ... @pinject.copy_args_to_internal_fields\n ... def __init__(self, foo, bar, baz, quux):\n ... pass\n ...\n >>> cwti = ClassWithTediousInitializer('a-foo', 'a-bar', 'a-baz', 'a-quux')\n >>> print cwti._foo\n 'a-foo'\n >>>\n\nWhen using these decorators, you'll normally ``pass`` in the body of the\ninitializer, but you can put other statements there if you need to. The args\nwill be copied to fields before the initializer body is executed.\n\nThese decorators can be applied to initializers that take ``**kwargs`` but not\ninitializers that take ``*pargs`` (since it would be unclear what field name\nto use).\n\nBinding specs\n=============\n\nTo create any bindings more complex than the implicit class bindings described\nabove, you use a *binding spec*. A binding spec is any python class that\ninherits from ``BindingSpec``. A binding spec can do three things:\n\n* Its ``configure()`` method can create explicit bindings to classes or instances, as well as requiring bindings without creating them.\n* Its ``dependencies()`` method can return depended-on binding specs.\n* It can have provider methods, for which explicit bindings are created.\n\nThe ``new_object_graph()`` function takes a sequence of binding spec instances\nas its ``binding_specs`` arg. ``new_object_graph()`` takes binding spec\ninstances, rather than binding spec classes, so that you can manually inject\nany initial dependencies into the binding specs as needed.\n\nBinding specs should generally live in files named ``binding_specs.py``, where\neach file is named in the plural even if there is exactly one binding spec in\nit. Ideally, a directory's worth of functionality should be coverable with a\nsingle binding spec. If not, you can create multiple binding specs in the\nsame ``binding_specs.py`` file. If you have so many binding specs that you\nneed to split them into multiple files, you should name them each with a\n``_binding_specs.py`` suffix.\n\nBinding spec ``configure()`` methods\n------------------------------------\n\nPinject creates implicit bindings for classes, but sometimes the implicit\nbindings aren't what you want. For instance, if you have\n``SomeReallyLongClassName``, you may not want to name your initializer args\n``some_really_long_class_name`` but instead use something shorter like\n``long_name``, just for this class.\n\nFor such situations, you can create explicit bindings using the\n``configure()`` method of a binding spec. The ``configure()`` method takes a\nfunction ``bind()`` as an arg and calls that function to create explicit\nbindings.\n\n.. code-block:: python\n\n >>> class SomeClass(object):\n ... def __init__(self, long_name):\n ... self.long_name = long_name\n ...\n >>> class SomeReallyLongClassName(object):\n ... def __init__(self):\n ... self.foo = 'foo'\n ...\n >>> class MyBindingSpec(pinject.BindingSpec):\n ... def configure(self, bind):\n ... bind('long_name', to_class=SomeReallyLongClassName)\n ...\n >>> obj_graph = pinject.new_object_graph(binding_specs=[MyBindingSpec()])\n >>> some_class = obj_graph.provide(SomeClass)\n >>> print some_class.long_name.foo\n 'foo'\n >>>\n\nThe ``bind()`` function passed to a binding function binds its first arg,\nwhich must be an arg name (as a ``str``), to exactly one of two kinds of\nthings.\n\n* Using ``to_class`` binds to a class. When the binding is used, Pinject injects an instance of the class.\n* Using ``to_instance`` binds to an instance of some object. Every time the binding is used, Pinject uses that instance.\n\n.. code-block:: python\n\n >>> class SomeClass(object):\n ... def __init__(self, foo):\n ... self.foo = foo\n ...\n >>> class MyBindingSpec(pinject.BindingSpec):\n ... def configure(self, bind):\n ... bind('foo', to_instance='a-foo')\n ...\n >>> obj_graph = pinject.new_object_graph(binding_specs=[MyBindingSpec()])\n >>> some_class = obj_graph.provide(SomeClass)\n >>> print some_class.foo\n 'a-foo'\n >>>\n\nThe ``configure()`` method of a binding spec also may take a function\n``require()`` as an arg and use that function to require that a binding be\npresent without actually defining that binding. ``require()`` takes as args\nthe name of the arg for which to require a binding.\n\n.. code-block:: python\n\n >>> class MainBindingSpec(pinject.BindingSpec):\n ... def configure(self, require):\n ... require('foo')\n ...\n >>> class RealFooBindingSpec(pinject.BindingSpec):\n ... def configure(self, bind):\n ... bind('foo', to_instance='a-real-foo')\n ...\n >>> class StubFooBindingSpec(pinject.BindingSpec):\n ... def configure(self, bind):\n ... bind('foo', to_instance='a-stub-foo')\n ...\n >>> class SomeClass(object):\n ... def __init__(self, foo):\n ... self.foo = foo\n ...\n >>> obj_graph = pinject.new_object_graph(\n ... binding_specs=[MainBindingSpec(), RealFooBindingSpec()])\n >>> some_class = obj_graph.provide(SomeClass)\n >>> print some_class.foo\n 'a-real-foo'\n >>> # pinject.new_object_graph(\n ... # binding_specs=[MainBindingSpec()]) # would raise a MissingRequiredBindingError\n ...\n >>>\n\nBeing able to require a binding without defining the binding is useful when\nyou know the code will need some dependency satisfied, but there is more than\none implementation that satisfies that dependency, e.g., there may be a real\nRPC client and a fake RPC client. Declaring the dependency means that any\nexpected but missing bindings will be detected early, when\n``new_object_graph()`` is called, rather than in the middle of running your\nprogram.\n\nYou'll notice that the ``configure()`` methods above have different\nsignatures, sometimes taking the arg ``bind`` and sometimes taking the arg\n``require``. ``configure()`` methods must take at least one arg that is\neither ``bind`` or ``require``, and they may have both args. Pinject will\npass whichever arg or args your ``configure()`` method needs.\n\nBinding spec dependencies\n-------------------------\n\nBinding specs can declare dependencies. A binding spec declares its\ndependencies by returning a sequence of instances of the dependent binding\nspecs from its ``dependencies()`` method.\n\n.. code-block:: python\n\n >>> class ClassOne(object):\n ... def __init__(self, foo):\n ... self.foo = foo\n ....\n >>> class BindingSpecOne(pinject.BindingSpec):\n ... def configure(self, bind):\n ... bind('foo', to_instance='foo-')\n ...\n >>> class ClassTwo(object):\n ... def __init__(self, class_one, bar):\n ... self.foobar = class_one.foo + bar\n ...\n >>> class BindingSpecTwo(pinject.BindingSpec):\n ... def configure(self, bind):\n ... bind('bar', to_instance='-bar')\n ... def dependencies(self):\n ... return [BindingSpecOne()]\n ...\n >>> obj_graph = pinject.new_object_graph(binding_specs=[BindingSpecTwo()])\n >>> class_two = obj_graph.provide(ClassTwo)\n >>> print class_two.foobar\n 'foo--bar'\n >>>\n\nIf classes from module A are injected as collaborators into classes from\nmodule B, then you should consider having the binding spec for module B depend\non the binding spec for module A. In the example above, ``ClassOne`` is\ninjected as a collaborator into ``ClassTwo``, and so ``BindingSpecTwo`` (the\nbinding spec for ``ClassTwo``) depends on ``BindingSpecOne`` (the binding spec\nfor ``ClassOne``).\n\nIn this way, you can build a graph of binding spec dependencies that mirrors\nthe graph of collaborator dependencies.\n\nSince explicit bindings cannot conflict (see the section below on binding\nprecedence), a binding spec should only have dependencies that there will\nnever be a choice about using. If there may be a choice, then it is better to\nlist the binding specs separately and explicitly when calling\n``new_object_graph()``.\n\nThe binding spec dependencies can be a directed acyclic graph (DAG); that is,\nbinding spec A can be a dependency of B and of C, and binding spec D can have\ndependencies on B and C. Even though there are multiple dependency paths from\nD to A, the bindings in binding spec A will only be evaluated once.\n\nThe binding spec instance of A that is a dependency of B is considered the\nsame as the instance that is a dependency of C if the two instances are equal\n(via ``__eq__()``). The default implementation of ``__eq__()`` in\n``BindingSpec`` says that two binding specs are equal if they are of exactly\nthe same python type. You will need to override ``__eq__()`` (as well as\n``__hash__()``) if your binding spec is parameterized, i.e., if it takes one\nor more initializer args so that two instances of the binding spec may behave\ndifferently.\n\n.. code-block:: python\n\n >>> class SomeBindingSpec(pinject.BindingSpec):\n ... def __init__(self, the_instance):\n ... self._the_instance = the_instance\n ... def configure(self, bind):\n ... bind('foo', to_instance=self._the_instance)\n ... def __eq__(self, other):\n ... return (type(self) == type(other) and\n ... self._the_instance == other._the_instance)\n ... def __hash__(self):\n ... return hash(type(self)) ^ hash(self._the_instance)\n ...\n >>>\n\nProvider methods\n----------------\n\nIf it takes more to instantiate a class than calling its initializer and\ninjecting initializer args, then you can write a *provider method* for it.\nPinject can use provider methods to instantiate objects used to inject as the\nvalues of other args.\n\nPinject looks on binding specs for methods named like provider methods and\nthen creates explicit bindings for them.\n\n.. code-block:: python\n\n >>> class SomeClass(object):\n ... def __init__(self, foo):\n ... self.foo = foo\n ...\n >>> class SomeBindingSpec(pinject.BindingSpec):\n ... def provide_foo(self):\n ... return 'some-complex-foo'\n ...\n >>> obj_graph = pinject.new_object_graph(binding_specs=[SomeBindingSpec()])\n >>> some_class = obj_graph.provide(SomeClass)\n >>> print some_class.foo\n 'some-complex-foo'\n >>>\n\nPinject looks on binding specs for methods whose names start with\n``provide_``, and it assumes that the methods are providers for whatever the\nrest of their method names are. For instance, Pinject assumes that the method\n``provide_foo_bar()`` is a provider method for the arg name ``foo_bar``.\n\nPinject injects all args of provider methods that have no default when it\ncalls the provider method.\n\n.. code-block:: python\n\n >>> class SomeClass(object):\n ... def __init__(self, foobar):\n ... self.foobar = foobar\n ...\n >>> class SomeBindingSpec(pinject.BindingSpec):\n ... def provide_foobar(self, bar, hyphen='-'):\n ... return 'foo' + hyphen + bar\n ... def provide_bar(self):\n ... return 'bar'\n ...\n >>> obj_graph = pinject.new_object_graph(binding_specs=[SomeBindingSpec()])\n >>> some_class = obj_graph.provide(SomeClass)\n >>> print some_class.foobar\n 'foo-bar'\n >>>\n\nBinding precedence\n==================\n\nBindings have precedence: explicit bindings take precedence over implicit\nbindings.\n\n* Explicit bindings are the bindings that come from binding specs.\n* Implicit bindings are the bindings created for classes in the ``modules`` and ``classes`` args passed to ``new_object_graph()``.\n\nPinject will prefer an explicit to an implicit binding.\n\n.. code-block:: python\n\n >>> class SomeClass(object):\n ... def __init__(self, foo):\n ... self.foo = foo\n ...\n >>> class Foo(object):\n ... pass\n ...\n >>> class SomeBindingSpec(pinject.BindingSpec):\n ... def configure(self, bind):\n ... bind('foo', to_instance='foo-instance')\n ...\n >>> obj_graph = pinject.new_object_graph(binding_specs=[SomeBindingSpec()])\n >>> some_class = obj_graph.provide(SomeClass)\n >>> print some_class.foo\n 'foo-instance'\n >>>\n\nIf you have two classes named the same thing, Pinject will have two different\n(and thus conflicting) implicit bindings. But Pinject will not complain\nunless you try to use those bindings. Pinject *will* complain if you try to\ncreate different (and thus conflicting) explicit bindings.\n\nSafety\n======\n\nPinject tries to strike a balance between being helpful and being safe.\nSometimes, you may want or need to change this balance.\n\n``new_object_graph()`` uses implicit bindings by default. If you worry that\nyou may accidentally inject a class or use a provider function\nunintentionally, then you can make ``new_object_graph()`` ignore implicit\nbindings, by setting ``only_use_explicit_bindings=True``. If you do so, then\nPinject will only use explicit bindings.\n\nIf you want to promote an implicit binding to be an explicit binding, you can\nannotate the corresponding class with ``@inject()``. The ``@inject()``\ndecorator lets you create explicit bindings without needing to create binding\nspecs, as long as you can live with the binding defaults (e.g., no annotations\non args, see below).\n\n.. code-block:: python\n\n >>> class ExplicitlyBoundClass(object):\n ... @pinject.inject()\n ... def __init__(self, foo):\n ... self.foo = foo\n ...\n >>> class ImplicitlyBoundClass(object):\n ... def __init__(self, foo):\n ... self.foo = foo\n ...\n >>> class SomeBindingSpec(pinject.BindingSpec):\n ... def configure(self, bind):\n ... bind('foo', to_instance='explicit-foo')\n ...\n >>> obj_graph = pinject.new_object_graph(binding_specs=[SomeBindingSpec()],\n ... only_use_explicit_bindings=True)\n >>> # obj_graph.provide(ImplicitlyBoundClass) # would raise a NonExplicitlyBoundClassError\n >>> some_class = obj_graph.provide(ExplicitlyBoundClass)\n >>> print some_class.foo\n 'explicit-foo'\n >>>\n\nYou can also promote an implicit binding to explicit by using\n``@annotated_arg()`` (see below), with or without ``@inject()`` as well.\n\n(Previous versions of Pinject included an ``@injectable`` decorator. That is\ndeprecated in favor of ``@inject()``. Note that ``@inject()`` needs parens,\nwhereas ``@injectable`` didn't.)\n\nOn the opposite side of permissiveness, Pinject by default will complain if a\nprovider method returns ``None``. If you really want to turn off this default\nbehavior, you can pass ``allow_injecting_none=True`` to\n``new_object_graph()``.\n\nAnnotations\n===========\n\nPinject *annotations* let you have different objects injected for the same arg\nname. For instance, you may have two classes in different parts of your\ncodebase named the same thing, and you want to use the same arg name in\ndifferent parts of your codebase.\n\nOn the arg side, an annotation tells Pinject only to inject using a binding\nwhose binding key includes the annotation object. You can use\n``@annotate_arg()`` on an initializer, or on a provider method, to specify the\nannotation object.\n\nOn the binding side, an annotation changes the binding so that the key of the\nbinding includes the annotation object. When using ``bind()`` in a binding\nspec's ``configure()`` method, you can pass an ``annotated_with`` arg to\nspecify the annotation object.\n\n.. code-block:: python\n\n >>> class SomeClass(object):\n ... @pinject.annotate_arg('foo', 'annot')\n ... def __init__(self, foo):\n ... self.foo = foo\n ...\n >>> class SomeBindingSpec(pinject.BindingSpec):\n ... def configure(self, bind):\n ... bind('foo', annotated_with='annot', to_instance='foo-with-annot')\n ... bind('foo', annotated_with=12345, to_instance='12345-foo')\n ...\n >>> obj_graph = pinject.new_object_graph(binding_specs=[SomeBindingSpec()])\n >>> some_class = obj_graph.provide(SomeClass)\n >>> print some_class.foo\n 'foo-with-annot'\n >>>\n\nAlso on the binding side, when defining a provider method, you can use the\n``@provides()`` decorator. The decorator lets you pass an ``annotated_with``\narg to specify the annotation object. The decorator's first param,\n``arg_name`` also lets you override what arg name you want the provider to be\nfor. This is optional but useful if you want the same binding spec to have\ntwo provider methods for the same arg name but annotated differently.\n(Otherwise, the methods would need to be named the same, since they're for the\nsame arg name.)\n\n.. code-block:: python\n\n >>> class SomeClass(object):\n ... @pinject.annotate_arg('foo', 'annot')\n ... def __init__(self, foo):\n ... self.foo = foo\n ...\n >>> class SomeBindingSpec(pinject.BindingSpec):\n ... @pinject.provides('foo', annotated_with='annot')\n ... def provide_annot_foo(self):\n ... return 'foo-with-annot'\n ... @pinject.provides('foo', annotated_with=12345)\n ... def provide_12345_foo(self):\n ... return '12345-foo'\n ...\n >>> obj_graph = pinject.new_object_graph(binding_specs=[SomeBindingSpec()])\n >>> some_class = obj_graph.provide(SomeClass)\n >>> print some_class.foo\n 'foo-with-annot'\n >>>\n\nWhen requiring a binding, via the ``require`` arg passed into the\n``configure()`` method of a binding spec, you can pass the arg\n``annotated_with`` to require an annotated binding.\n\n.. code-block:: python\n\n >>> class MainBindingSpec(pinject.BindingSpec):\n ... def configure(self, require):\n ... require('foo', annotated_with='annot')\n ...\n >>> class NonSatisfyingBindingSpec(pinject.BindingSpec):\n ... def configure(self, bind):\n ... bind('foo', to_instance='an-unannotated-foo')\n ...\n >>> class SatisfyingBindingSpec(pinject.BindingSpec):\n ... def configure(self, bind):\n ... bind('foo', annotated_with='annot', to_instance='an-annotated-foo')\n ...\n >>> obj_graph = pinject.new_object_graph(\n ... binding_specs=[MainBindingSpec(), SatisfyingBindingSpec()]) # works\n >>> # obj_graph = pinject.new_object_graph(\n ... # binding_specs=[MainBindingSpec(),\n ... # NonSatisfyingBindingSpec()]) # would raise a MissingRequiredBindingError\n >>>\n\nYou can use any kind of object as an annotation object as long as it\nimplements ``__eq__()`` and ``__hash__()``.\n\nScopes\n======\n\nBy default, Pinject remembers the object it injected into a (possibly\nannotated) arg, so that it can inject the same object into other args with the\nsame name. This means that, for each arg name, a single instance of the\nbound-to class, or a single instance returned by a provider method, is created\nby default.\n\n.. code-block:: python\n\n >>> class SomeClass(object):\n ... def __init__(self, foo):\n ... self.foo = foo\n ...\n >>> class SomeBindingSpec(pinject.BindingSpec):\n ... def provide_foo(self):\n ... return object()\n ...\n >>> obj_graph = pinject.new_object_graph(binding_specs=[SomeBindingSpec()])\n >>> some_class_1 = obj_graph.provide(SomeClass)\n >>> some_class_2 = obj_graph.provide(SomeClass)\n >>> print some_class_1.foo is some_class_2.foo\n True\n >>>\n\nIn some cases, you may want to create new instances, always or sometimes,\ninstead of reusing them each time they're injected. If so, you want to use\n*scopes*.\n\nA scope controls memoization (i.e., caching). A scope can choose to cache\nnever, sometimes, or always.\n\nPinject has two built-in scopes. *Singleton scope* (``SINGLETON``) is the\ndefault and always caches. *Prototype scope* (``PROTOTYPE``) is the other\nbuilt-in option and does no caching whatsoever.\n\nEvery binding is associated with a scope. You can specify a scope for a\nbinding by decorating a provider method with ``@in_scope()``, or by passing an\n``in_scope`` arg to ``bind()`` in a binding spec's ``configure()`` method.\n\n.. code-block:: python\n\n >>> class SomeClass(object):\n ... def __init__(self, foo):\n ... self.foo = foo\n ...\n >>> class SomeBindingSpec(pinject.BindingSpec):\n ... @pinject.provides(in_scope=pinject.PROTOTYPE)\n ... def provide_foo(self):\n ... return object()\n ...\n >>> obj_graph = pinject.new_object_graph(binding_specs=[SomeBindingSpec()])\n >>> some_class_1 = obj_graph.provide(SomeClass)\n >>> some_class_2 = obj_graph.provide(SomeClass)\n >>> print some_class_1.foo is some_class_2.foo\n False\n >>>\n\nIf a binding specifies no scope explicitly, then it is in singleton scope.\nImplicit class bindings are always in singleton scope.\n\nMemoization of class bindings works at the class level, not at the binding key\nlevel. This means that, if you bind two arg names (or the same arg name with\ntwo different annotations) to the same class, and the class is in a memoizing\nscope, then the same class instance will be provided when you inject the\ndifferent arg names.\n\n.. code-block:: python\n\n >>> class InjectedClass(object):\n ... pass\n ...\n >>> class SomeObject(object):\n ... def __init__(self, foo, bar):\n ... self.foo = foo\n ... self.bar = bar\n ...\n >>> class SomeBindingSpec(pinject.BindingSpec):\n ... def configure(self, bind):\n ... bind('foo', to_class=InjectedClass)\n ... bind('bar', to_class=InjectedClass)\n ...\n >>> obj_graph = pinject.new_object_graph(\n ... binding_specs=[SomeBindingSpec()])\n >>> some_object = obj_graph.provide(SomeObject)\n >>> print some_object.foo is some_object.bar\n True\n >>>\n\nPinject memoizes class bindings this way because this is more likely to be\nwhat you mean if you bind two different arg names to the same class in\nsingleton scope: you want only one instance of the class, even though it may\nbe injected in multiple places.\n\nProvider bindings\n=================\n\nSometimes, you need to inject not just a single instance of some class, but\nrather you need to inject the ability to create instances on demand.\n(Clearly, this is most useful when the binding you're using is not in the\nsingleton scope, otherwise you'll always get the same instance, and you may as\nwell just inject that..)\n\nYou could inject the Pinject object graph, but you'd have to do that\ndependency injection manually (Pinject doesn't inject itself!), and you'd be\ninjecting a huge set of capabilities when your class really only needs to\ninstantiate objects of one type.\n\nTo solve this, Pinject creates *provider bindings* for each bound arg name.\nIt will look at the arg name for the prefix ``provide_``, and if it finds that\nprefix, it assumes you want to inject a provider function for whatever the\nrest of the arg name is. For instance, if you have an arg named\n``provide_foo_bar``, then Pinject will inject a zero-arg function that, when\ncalled, provides whatever the arg name ``foo_bar`` is bound to.\n\n.. code-block:: python\n\n >>> class Foo(object):\n ... def __init__(self):\n ... self.forty_two = 42\n ...\n >>> class SomeBindingSpec(pinject.BindingSpec):\n ... def configure(self, bind):\n ... bind('foo', to_class=Foo, in_scope=pinject.PROTOTYPE)\n ...\n >>> class NeedsProvider(object):\n ... def __init__(self, provide_foo):\n ... self.provide_foo = provide_foo\n ...\n >>> obj_graph = pinject.new_object_graph(binding_specs=[SomeBindingSpec()])\n >>> needs_provider = obj_graph.provide(NeedsProvider)\n >>> print needs_provider.provide_foo() is needs_provider.provide_foo()\n False\n >>> print needs_provider.provide_foo().forty_two\n 42\n >>>\n\nPinject will always look for the ``provide_`` prefix as a signal to inject a\nprovider function, anywhere it injects dependencies (initializer args, binding\nspec provider methods, etc.). This does mean that it's quite difficult, say,\nto inject an instance of a class named ``ProvideFooBar`` into an arg named\n``provide_foo_bar``, but assuming you're naming your classes as noun phrases\ninstead of verb phrases, this shouldn't be a problem.\n\nWatch out: don't confuse\n\n* *provider bindings*, which let you inject args named ``provide_something`` with provider functions; and\n* *provider methods*, which are methods of binding specs that provide instances of some arg name.\n\nPartial injection\n=================\n\nProvider bindings are useful when you want to create instances of a class on\ndemand. But a zero arg provider function will always return an instance\nconfigured the same way (within a given scope). Sometimes, you want the\nability to parameterize the provided instances, e.g., based on run-time user\nconfiguration. You want the ability to create instances where part of the\ninitialization data is provided per-instance at run-time and part of the\ninitialization data is injected as dependencies.\n\nTo do this, other dependency injection libraries have you define factory\nclasses. You inject dependencies into the factory class's initializer\nfunction, and then you call the factory class's creation method with the\nper-instance data.\n\n.. code-block:: python\n\n >>> class WidgetFactory(object):\n ... def __init__(self, widget_polisher):\n ... self._widget_polisher = widget_polisher\n ... def new(self, color): # normally would contain some non-trivial code...\n ... return some_function_of(self._widget_polisher, color)\n ...\n >>> class SomeBindingSpec(pinject.BindingSpec):\n ... def provide_something_with_colored_widgets(self, colors, widget_factory):\n ... return SomethingWithColoredWidgets(\n ... [widget_factory.new(color) for color in colors])\n ...\n >>>\n\nYou can follow this pattern in Pinject, but it involves boring boilerplate for\nthe factory class, saving away the initializer-injected dependencies to be\nused in the creation method. Plus, you have to create yet another\n``...Factory`` class, which makes you feel like you're programming in java,\nnot python.\n\nAs a less repetitive alternative, Pinject lets you use *partial injection* on\nthe provider functions returned by provider bindings. You use the\n``@inject()`` decorator to tell Pinject ahead of time which args you expect to\npass directly (vs. automatic injection), and then you pass those args directly\nwhen calling the provider function.\n\n.. code-block:: python\n\n >>> class SomeBindingSpec(pinject.BindingSpec):\n ... @pinject.inject(['widget_polisher'])\n ... def provide_widget(self, color, widget_polisher):\n ... return some_function_of(widget_polisher, color)\n ... def provide_something_needing_widgets(self, colors, provide_widget):\n ... return SomethingNeedingWidgets(\n ... [provide_widget(color) for color in colors])\n ...\n >>>\n\nThe first arg to ``@inject()``, ``arg_names``, specifies which args of the\ndecorated method should be injected as dependencies. If specified, it must be\na non-empty sequence of names of the decorated method's args. The remaining\ndecorated method args will be passed directly.\n\nIn the example above, note that, although there is a method called\n``provide_widget()`` and an arg of ``provide_something_needing_widgets()``\ncalled ``provide_widget``, these are not exactly the same! The latter is a\ndependency-injected wrapper around the former. The wrapper ensures that the\n``color`` arg is passed directly and then injects the ``widget_polisher``\ndependency.\n\nThe ``@inject()`` decorator works to specify args passed directly both for\nprovider bindings to provider methods (as in the example above) and for\nprovider bindings to classes (where you can pass args directly to the\ninitializer, as in the example below).\n\n.. code-block:: python\n\n >>> class Widget(object):\n ... @pinject.inject(['widget_polisher'])\n ... def __init__(self, color, widget_polisher):\n ... pass # normally something involving color and widget_polisher\n ...\n >>> class SomeBindingSpec(pinject.BindingSpec):\n ... def provide_something_needing_widgets(self, colors, provide_widget):\n ... return SomethingNeedingWidgets(\n ... [provide_widget(color) for color in colors])\n ...\n >>>\n\nThe ``@inject()`` decorator also takes an ``all_except`` arg. You can use\nthis, instead of the (first positional) ``arg_names`` arg, if it's clearer and\nmore concise to say which args are *not* injected (i.e., which args are passed\ndirectly).\n\n.. code-block:: python\n\n >>> class Widget(object):\n ... # equivalent to @pinject.inject(['widget_polisher']):\n ... @pinject.inject(all_except=['color'])\n ... def __init__(self, color, widget_polisher):\n ... pass # normally something involving color and widget_polisher\n ...\n >>>\n\nIf both ``arg_names`` and ``all_except`` are omitted, then all args are\ninjected by Pinject, and none are passed directly. (Both ``arg_names`` and\n``all_except`` may not be specified at the same time.) Wildcard positional\nand keyword args (i.e., ``*pargs`` and ``**kwargs``) are always passed\ndirectly, not injected.\n\nIf you use ``@inject()`` to mark at least one arg of a provider method (or\ninitializer) as passed directly, then you may no longer directly inject that\nprovider method's corresponding arg name. You must instead use a provider\nbinding to inject a provider function, and then pass the required direct\narg(s), as in the examples above.\n\nCustom scopes\n=============\n\nIf you want to, you can create your own custom scope. A custom scope is\nuseful when you have some objects that need to be reused (i.e., cached) but\nwhose lifetime is shorter than the entire lifetime of your program.\n\nA custom scope is any class that implements the ``Scope`` interface.\n\n.. code-block:: python\n\n class Scope(object):\n def provide(self, binding_key, default_provider_fn):\n raise NotImplementedError()\n\nThe ``binding_key`` passed to ``provide()`` will be an object implementing\n``__eq__()`` and ``__hash__()`` but otherwise opaque (you shouldn't need to\nintrospect it). You can think of the binding key roughly as encapsulating the\narg name and annotation (if any). The ``default_provider_fn`` passed to\n``provide()`` is a zero-arg function that, when called, provides an instance\nof whatever should be provided.\n\nThe job of a scope's ``provide()`` function is to return a cached object if\navailable and appropriate, otherwise to return (and possibly cache) the result\nof calling the default provider function.\n\nScopes almost always have other methods that control clearing the scope's\ncache. For instance, a scope may have \"enter scope\" and \"exit scope\" methods,\nor a single direct \"clear cache\" method. When passing a custom scope to\nPinject, your code should keep a handle to the custom scope and use that\nhandle to clear the scope's cache at the appropriate time.\n\nYou can use one or more custom scopes by passing a map from *scope identifier*\nto scope as the ``id_to_scope`` arg of ``new_object_graph()``.\n\n.. code-block:: python\n\n >>> class MyScope(pinject.Scope):\n ... def __init__(self):\n ... self._cache = {}\n ... def provide(self, binding_key, default_provider_fn):\n ... if binding_key not in self._cache:\n ... self._cache[binding_key] = default_provider_fn()\n ... return self._cache[binding_key]\n ... def clear(self):\n ... self._cache = {}\n ...\n >>> class SomeClass(object):\n ... def __init__(self, foo):\n ... self.foo = foo\n ...\n >>> class SomeBindingSpec(pinject.BindingSpec):\n ... @pinject.provides(in_scope='my custom scope')\n ... def provide_foo(self):\n ... return object()\n ...\n >>> my_scope = MyScope()\n >>> obj_graph = pinject.new_object_graph(\n ... binding_specs=[SomeBindingSpec()],\n ... id_to_scope={'my custom scope': my_scope})\n >>> some_class_1 = obj_graph.provide(SomeClass)\n >>> some_class_2 = obj_graph.provide(SomeClass)\n >>> my_scope.clear()\n >>> some_class_3 = obj_graph.provide(SomeClass)\n >>> print some_class_1.foo is some_class_2.foo\n True\n >>> print some_class_2.foo is some_class_3.foo\n False\n >>>\n\nA scope identifier can be any object implementing ``__eq__()`` and\n``__hash__()``.\n\nIf you plan to use Pinject in a multi-threaded environment (and even if you\ndon't plan to now but may some day), you should make your custom scope\nthread-safe. The example custom scope above could be trivially (but more\nverbosely) rewritten to be thread-safe, as in the example below. The lock is\nreentrant so that something in ``MyScope`` can be injected into something else\nin ``MyScope``.\n\n.. code-block:: python\n\n >>> class MyScope(pinject.Scope):\n ... def __init__(self):\n ... self._cache = {}\n ... self._rlock = threading.RLock()\n ... def provide(self, binding_key, default_provider_fn):\n ... with self._rlock:\n ... if binding_key not in self._cache:\n ... self._cache[binding_key] = default_provider_fn()\n ... return self._cache[binding_key]\n ... def clear(self):\n ... with self._rlock:\n ... self._cache = {}\n >>>\n\nScope accessibility\n===================\n\nTo prevent yourself from injecting objects where they don't belong, you may\nwant to validate one object being injected into another w.r.t. scope.\n\nFor instance, you may have created a custom scope for HTTP requests handled by\nyour program. Objects in request scope would be cached for the duration of a\nsingle HTTP request. You may want to verify that objects in request scope\nnever get injected into objects in singleton scope. Such an injection is\nlikely not to make semantic sense, since it would make something tied to one\nHTTP request be used for the duration of your program.\n\nPinject lets you pass a validation function as the\n``is_scope_usable_from_scope`` arg to ``new_object_graph()``. This function\ntakes two scope identifiers and returns ``True`` iff an object in the first\nscope can be injected into an object of the second scope.\n\n.. code-block:: python\n\n >>> class RequestScope(pinject.Scope):\n ... def start_request(self):\n ... self._cache = {}\n ... def provide(self, binding_key, default_provider_fn):\n ... if binding_key not in self._cache:\n ... self._cache[binding_key] = default_provider_fn()\n ... return self._cache[binding_key]\n ...\n >>> class SomeClass(object):\n ... def __init__(self, foo):\n ... self.foo = foo\n ...\n >>> class SomeBindingSpec(pinject.BindingSpec):\n ... @pinject.provides(in_scope=pinject.SINGLETON)\n ... def provide_foo(bar):\n ... return 'foo-' + bar\n ... @pinject.provides(in_scope='request scope')\n ... def provide_bar():\n ... return '-bar'\n ...\n >>> def is_usable(scope_id_inner, scope_id_outer):\n ... return not (scope_id_inner == 'request scope' and\n ... scope_id_outer == scoping.SINGLETON)\n ...\n >>> my_request_scope = RequestScope()\n >>> obj_graph = pinject.new_object_graph(\n ... binding_specs=[SomeBindingSpec()],\n ... id_to_scope={'request scope': my_request_scope},\n ... is_scope_usable_from_scope=is_usable)\n >>> my_request_scope.start_request()\n >>> # obj_graph.provide(SomeClass) # would raise a BadDependencyScopeError\n >>>\n\nThe default scope accessibility validator allows objects from any scope to be\ninjected into objects from any other scope.\n\nChanging naming conventions\n===========================\n\nIf your code follows PEP8 naming coventions, then you're likely happy with the\ndefault implicit bindings (where the class ``FooBar`` gets bound to the arg\nname ``foo_bar``) and where ``provide_foo_bar()`` is a binding spec's provider\nmethod for the arg name ``foo_bar``.\n\nBut if not, read on!\n\nCustomizing implicit bindings\n-----------------------------\n\n``new_object_graph()`` takes a ``get_arg_names_from_class_name`` arg. This is\nthe function that is used to determine implicit class bindings. This function\ntakes in a class name (e.g., ``FooBar``) and returns the arg names to which\nthat class should be implicitly bound (e.g., ``['foo_bar']``). Its default\nbehavior is described in the \"implicit class bindings\" section above, but that\ndefault behavior can be overridden.\n\nFor instance, suppose that your code uses a library that names many classes\nwith the leading letter X (e.g., ``XFooBar``), and you'd like to be able to\nbind that to a corresponding arg name without the leading X (e.g.,\n``foo_bar``).\n\n.. code-block:: python\n\n >>> import re\n >>> def custom_get_arg_names(class_name):\n ... stripped_class_name = re.sub('^_?X?', '', class_name)\n ... return [re.sub('(?!^)([A-Z]+)', r'_\\1', stripped_class_name).lower()]\n ...\n >>> print custom_get_arg_names('XFooBar')\n ['foo_bar']\n >>> print custom_get_arg_names('XLibraryClass')\n ['library_class']\n >>> class OuterClass(object):\n ... def __init__(self, library_class):\n ... self.library_class = library_class\n ...\n >>> class XLibraryClass(object):\n ... def __init__(self):\n ... self.forty_two = 42\n ...\n >>> obj_graph = pinject.new_object_graph(\n ... get_arg_names_from_class_name=custom_get_arg_names)\n >>> outer_class = obj_graph.provide(OuterClass)\n >>> print outer_class.library_class.forty_two\n 42\n >>>\n\nThe function passed as the ``get_arg_names_from_class_name`` arg to\n``new_object_graph()`` can return as many or as few arg names as it wants. If\nit always returns the empty list (i.e., if it is ``lambda _: []``), then that\ndisables implicit class bindings.\n\nCustomizing binding spec method names\n-------------------------------------\n\nThe standard binding spec methods to configure bindings and declare\ndependencies are named ``configure`` and ``dependencies``, by default. If you\nneed to, you can change their names by passing ``configure_method_name``\nand/or ``dependencies_method_name`` as args to ``new_object_graph()``.\n\n.. code-block:: python\n\n >>> class NonStandardBindingSpec(pinject.BindingSpec):\n ... def Configure(self, bind):\n ... bind('forty_two', to_instance=42)\n ...\n >>> class SomeClass(object):\n ... def __init__(self, forty_two):\n ... self.forty_two = forty_two\n ...\n >>> obj_graph = pinject.new_object_graph(\n ... binding_specs=[NonStandardBindingSpec()],\n ... configure_method_name='Configure')\n >>> some_class = obj_graph.provide(SomeClass)\n >>> print some_class.forty_two\n 42\n >>>\n\nCustomizing provider method names\n---------------------------------\n\n``new_object_graph()`` takes a ``get_arg_names_from_provider_fn_name`` arg.\nThis is the function that is used to identify provider methods on binding\nspecs. This function takes in the name of a potential provider method (e.g.,\n``provide_foo_bar``) and returns the arg names for which the provider method\nis a provider, if any (e.g., ``['foo_bar']``). Its default behavior is\ndescribed in the \"provider methods\" section above, but that default behavior\ncan be overridden.\n\nFor instance, suppose that you work for a certain large corporation whose\npython style guide makes you name functions in ``CamelCase``, and so you need\nto name the provider method for the arg name ``foo_bar`` more like\n``ProvideFooBar`` than ``provide_foo_bar``.\n\n.. code-block:: python\n\n >>> import re\n >>> def CustomGetArgNames(provider_fn_name):\n ... if provider_fn_name.startswith('Provide'):\n ... provided_camelcase = provider_fn_name[len('Provide'):]\n ... return [re.sub('(?!^)([A-Z]+)', r'_\\1', provided_camelcase).lower()]\n ... else:\n ... return []\n ...\n >>> print CustomGetArgNames('ProvideFooBar')\n ['foo_bar']\n >>> print CustomGetArgNames('ProvideFoo')\n ['foo']\n >>> class SomeClass(object):\n ... def __init__(self, foo):\n ... self.foo = foo\n ...\n >>> class SomeBindingSpec(pinject.BindingSpec):\n ... def ProvideFoo(self):\n ... return 'some-foo'\n ...\n >>> obj_graph = pinject.new_object_graph(\n ... binding_specs=[SomeBindingSpec()],\n ... get_arg_names_from_provider_fn_name=CustomGetArgNames)\n >>> some_class = obj_graph.provide(SomeClass)\n >>> print some_class.foo\n 'some-foo'\n >>>\n\nThe function passed as the ``get_arg_names_from_provider_fn_name`` arg to\n``new_object_graph()`` can return as many or as few arg names as it wants. If\nit returns an empty list, then that potential provider method is assumed not\nactually to be a provider method.\n\nMiscellaneous\n=============\n\nPinject raises helpful exceptions whose messages include the file and line\nnumber of errors. So, Pinject by default will shorten the stack trace of\nexceptions that it raises, so that you don't see the many levels of function\ncalls within the Pinject library.\n\nIn some situations, though, the complete stack trace is helpful, e.g., when\ndebugging Pinject, or when your code calls Pinject, which calls back into your\ncode, which calls back into Pinject. In such cases, to disable exception\nstack shortening, you can pass ``use_short_stack_traces=False`` to\n``new_object_graph()``.\n\nGotchas\n=======\n\nPinject has a few things to watch out for.\n\nThread safety\n-------------\n\nPinject's default scope is ``SINGLETON``. If you have a multi-threaded\nprogram, it's likely that some or all of the things that Pinject provides from\nsingleton scope will be used in multiple threads. So, it's important that you\nensure that such classes are thread-safe.\n\nSimilarly, it's important that your custom scope classes are thread-safe.\nEven if the objects they provide are only used in a single thread, it may be\nthat the object graph (and therefore the scope itself) will be used\nsimultaneously in multiple threads.\n\nRemember to make locks re-entrant on your custom scope classes, or otherwise\ndeal with one object in your custom scope trying to inject another object in\nyour custom scope.\n\nThat's it for gotchas, for now.\n\nCondensed summary\n=================\n\nIf you are already familiar with dependency injection libraries such as Guice,\nthis section gives you a condensed high level summary of Pinject and how it\nmight be similar to or different than other dependency injection libraries.\n(If you don't understand it, no problem. The rest of the documentation covers\neverything listed here.)\n\n* Pinject uses code and decorators to configure injection, not a separate config file.\n* Bindings are keyed by arg name, (not class type, since Python is dynamically typed).\n* Pinject automatically creates bindings to ``some_class`` arg names for ``SomeClass`` classes.\n* You can ask Pinject only to create bindings from binding specs and classes whose ``__init__()`` is marked with ``@inject()``.\n* A binding spec is a class that creates explicit bindings.\n* A binding spec can bind arg names to classes or to instances.\n* A binding spec can bind arg names ``foo`` to provider methods ``provide_foo()``.\n* Binding specs can depend on (i.e., include) other binding specs.\n* You can annotate args and bindings to distinguish among args/bindings for the same arg name.\n* Pinject has two built-in scopes: \"singleton\" (always memoized; the default) and \"prototype\" (never memoized).\n* You can define custom scopes, and you can configure which scopes are accessible from which other scopes.\n* Pinject doesn't allow injecting ``None`` by default, but you can turn off that check.\n\nChangelog\n=========\n\nv0.13: master\n\nv0.12: 28 Nov, 2018\n\n* Support Python 3\n* Add two maintainers: @trein and @huan\n\nv0.10.2:\n\n* Fixed bug: allows binding specs containing only provider methods.\n\nv0.10.1:\n\n* Fixed bug: allows omitting custom named ``configure()`` binding spec method.\n\nv0.10:\n\n* Added default ``__eq__()`` to ``BindingSpec``, so that DAG binding spec dependencies can have equal but not identical dependencies.\n* Allowed customizing ``configure()`` and ``dependencies()`` binding spec method names.\n* Deprecated ``@injectable`` in favor of ``@inject``.\n* Added partial injection.\n* Added ``require`` arg to allow binding spec ``configure`` methods to declare but not define bindings.\n* Sped up tests (and probably general functionality) by 10x.\n* Documented more design decisions.\n* Added ``@copy_args_to_internal_fields`` and ``@copy_args_to_public_fields``.\n* Renamed ``InjectableDecoratorAppliedToNonInitError`` to ``DecoratorAppliedToNonInitError``.\n\nv0.9:\n\n* Added validation of python types of public args.\n* Improved error messages for all Pinject-raised exceptions.\n* Added ``use_short_stack_traces`` arg to ``new_object_graph()``.\n* Allowed multiple ``@provides`` on single provider method.\n\nv0.8:\n\n* First released version.\n\nMaintainers\n===========\n\n* Kurt Steinkraus @kurt\n* Guilherme Trein @trein\n* Huan LI @huan\n\nLicense\n=======\nApache-2.0\n\nPinject and Google\n==================\n\nThough Google owns this project's copyright, this project is not an official\nGoogle product.\n\n\n", "description_content_type": "", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/google/pinject", "keywords": "", "license": "Apache License 2.0", "maintainer": "", "maintainer_email": "", "name": "pinject", "package_url": "https://pypi.org/project/pinject/", "platform": "all", "project_url": "https://pypi.org/project/pinject/", "project_urls": { "Homepage": "https://github.com/google/pinject" }, "release_url": "https://pypi.org/project/pinject/0.14.1/", "requires_dist": [ "six (>=1.7.3)", "decorator (>=4.3.0)" ], "requires_python": "", "summary": "A pythonic dependency injection library", "version": "0.14.1" }, "last_serial": 5315845, "releases": { "0.10": [ { "comment_text": "", "digests": { "md5": "3d6067db8bcc1471993ad47fb0fe63b1", "sha256": "ed5495ffab981295f2d26426f56bab01c18347502fed8fa3fb63873a358cc420" }, "downloads": -1, "filename": "pinject-0.10.1.tar.gz", "has_sig": false, "md5_digest": "3d6067db8bcc1471993ad47fb0fe63b1", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 47942, "upload_time": "2013-08-15T14:37:51", "url": "https://files.pythonhosted.org/packages/e8/66/cb404c2ed0e35d15cc30e0a2dbe1682ff08a2b89b7a626a7640f607a174f/pinject-0.10.1.tar.gz" } ], "0.10.1": [], "0.10.2": [ { "comment_text": "", "digests": { "md5": "2cab6c3f387d2b024800e4c333cd36b1", "sha256": "38ea2f457bf02635544c6784ee7a9f8c1f4faf2fd04dccd9b352b3c00710e968" }, "downloads": -1, "filename": "pinject-0.10.2.tar.gz", "has_sig": false, "md5_digest": "2cab6c3f387d2b024800e4c333cd36b1", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 48042, "upload_time": "2013-08-16T15:57:28", "url": "https://files.pythonhosted.org/packages/a9/9a/412b1f4dff67957835297ad6489bb7e3fce2e27e11966786dceb57dd509b/pinject-0.10.2.tar.gz" } ], "0.12.2": [ { "comment_text": "", "digests": { "md5": "6f701613426497c2e1ef4417440336a1", "sha256": "4a1f58b9e6e34395fb530bb7599f39ed0b23b930aadf0d13dd5522ba8aedf4a7" }, "downloads": -1, "filename": "pinject-0.12.2-py3-none-any.whl", "has_sig": false, "md5_digest": "6f701613426497c2e1ef4417440336a1", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 47198, "upload_time": "2018-11-27T17:52:11", "url": "https://files.pythonhosted.org/packages/90/a4/552706ef0c2095310d040e3af902fdc0f558a0db4f353a09171dffa674a4/pinject-0.12.2-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "faab2189ac42291e830a4f819e0a9736", "sha256": "4f5f07b8acbfb713cc1d89caa0a12c33b9a10e849172a7d49fcbbd7b0fd8d39e" }, "downloads": -1, "filename": "pinject-0.12.2.tar.gz", "has_sig": false, "md5_digest": "faab2189ac42291e830a4f819e0a9736", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 60032, "upload_time": "2018-11-27T17:52:13", "url": "https://files.pythonhosted.org/packages/85/c8/0a30586cb50a976355c059a1029b569915bc94a7f18c6d846d1a65e613c7/pinject-0.12.2.tar.gz" } ], "0.12.6": [ { "comment_text": "", "digests": { "md5": "cff4f1846612af3c0b59b620480443b7", "sha256": "728bf4339604a8c327e8dc2fdc13dc316c1ab4ee485249990fb93510817d8a5f" }, "downloads": -1, "filename": "pinject-0.12.6-py3-none-any.whl", "has_sig": false, "md5_digest": "cff4f1846612af3c0b59b620480443b7", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 47087, "upload_time": "2018-11-29T04:04:56", "url": "https://files.pythonhosted.org/packages/27/53/a545b129b7e8010c220c1152fffe735a4c39d18921b428aee5ad3af52972/pinject-0.12.6-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "a017b233b8c6eecfd47600262547026a", "sha256": "1a54be1872ee919c150151fbb4e50a8d5c3f89b24054e4925f17768729fab262" }, "downloads": -1, "filename": "pinject-0.12.6.tar.gz", "has_sig": false, "md5_digest": "a017b233b8c6eecfd47600262547026a", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 59954, "upload_time": "2018-11-29T04:04:58", "url": "https://files.pythonhosted.org/packages/3c/85/1a422b22b0e7d6f4b017597d78fa6ebdfd401e668d8a92f06165f5e43f48/pinject-0.12.6.tar.gz" } ], "0.14.1": [ { "comment_text": "", "digests": { "md5": "24846fd788c75ac896efcdbd8e7a4334", "sha256": "dfc4981a36d3f7cf2fa82bd8922f713c769004fe7af935def3e2a52147aeda66" }, "downloads": -1, "filename": "pinject-0.14.1-py3-none-any.whl", "has_sig": false, "md5_digest": "24846fd788c75ac896efcdbd8e7a4334", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 42979, "upload_time": "2019-05-25T08:04:36", "url": "https://files.pythonhosted.org/packages/fd/67/9025a31cbadca4d88880a6856b9b3052e970981d49dc9fa3f9ee46793022/pinject-0.14.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "57ac1f33685ff85aa31f0e2433cae97d", "sha256": "0f0a0b14f9df87a85b529a21cdaf530269b1f24fb303d418583a12bb53f69382" }, "downloads": -1, "filename": "pinject-0.14.1.tar.gz", "has_sig": false, "md5_digest": "57ac1f33685ff85aa31f0e2433cae97d", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 60348, "upload_time": "2019-05-25T08:04:39", "url": "https://files.pythonhosted.org/packages/4c/4e/5e311f48898e22e2116c53739e91c20477993f50da21b603259b72c3a65b/pinject-0.14.1.tar.gz" } ], "0.8": [ { "comment_text": "", "digests": { "md5": "277b9a2e889753ba20abeed2f3f37ae2", "sha256": "aafb3617bc2067e3ce58ae2fdc98f05491ce707028d6bc47cd8a7c23884d3f9a" }, "downloads": -1, "filename": "pinject-0.8.tar.gz", "has_sig": false, "md5_digest": "277b9a2e889753ba20abeed2f3f37ae2", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 37054, "upload_time": "2013-06-29T04:30:18", "url": "https://files.pythonhosted.org/packages/37/ae/432985f759e3e8842f87de81bb6a2f2bba3eb5e63dec61ca3167952dd177/pinject-0.8.tar.gz" } ], "0.9": [ { "comment_text": "", "digests": { "md5": "da36ae78cfcac588d5c040fc56d11145", "sha256": "638a4da8894350298606c7228387b37599d189c76f7a9abcacfa23c2e1072701" }, "downloads": -1, "filename": "pinject-0.10.tar.gz", "has_sig": false, "md5_digest": "da36ae78cfcac588d5c040fc56d11145", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 47896, "upload_time": "2013-08-02T17:09:46", "url": "https://files.pythonhosted.org/packages/7e/ec/af093f3c0b2e5eb136af6d56b4cbc66badc443dce93d3ff96b061b691fad/pinject-0.10.tar.gz" }, { "comment_text": "", "digests": { "md5": "39dfad314e871c80a9cae4004d3f076a", "sha256": "429e1e78c0ea9f9324212dd4e6703c2c60b71c3a1c6e8ec5f21b059c9bdcd3a6" }, "downloads": -1, "filename": "pinject-0.9.tar.gz", "has_sig": false, "md5_digest": "39dfad314e871c80a9cae4004d3f076a", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 39130, "upload_time": "2013-07-08T04:06:37", "url": "https://files.pythonhosted.org/packages/15/29/dcf9225e422fc0d8aa70dd2a7b9a2c5a0f3c75101109b02039379454102c/pinject-0.9.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "24846fd788c75ac896efcdbd8e7a4334", "sha256": "dfc4981a36d3f7cf2fa82bd8922f713c769004fe7af935def3e2a52147aeda66" }, "downloads": -1, "filename": "pinject-0.14.1-py3-none-any.whl", "has_sig": false, "md5_digest": "24846fd788c75ac896efcdbd8e7a4334", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 42979, "upload_time": "2019-05-25T08:04:36", "url": "https://files.pythonhosted.org/packages/fd/67/9025a31cbadca4d88880a6856b9b3052e970981d49dc9fa3f9ee46793022/pinject-0.14.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "57ac1f33685ff85aa31f0e2433cae97d", "sha256": "0f0a0b14f9df87a85b529a21cdaf530269b1f24fb303d418583a12bb53f69382" }, "downloads": -1, "filename": "pinject-0.14.1.tar.gz", "has_sig": false, "md5_digest": "57ac1f33685ff85aa31f0e2433cae97d", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 60348, "upload_time": "2019-05-25T08:04:39", "url": "https://files.pythonhosted.org/packages/4c/4e/5e311f48898e22e2116c53739e91c20477993f50da21b603259b72c3a65b/pinject-0.14.1.tar.gz" } ] }