{ "info": { "author": "Ron DuPlain", "author_email": "ron.duplain@gmail.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 4 - Beta", "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.2", "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: Implementation :: PyPy", "Topic :: Software Development :: Libraries :: Python Modules", "Topic :: Utilities" ], "description": "=========================================\n ``jeni`` injects annotated dependencies\n=========================================\n\n**jeni** lets developers build applications and not e.g. web applications.\n\nOverview\n========\n\n1. Configure each dependency in the project (requirements.txt, config, ...).\n2. Write code with natural call signatures taking those dependencies as input.\n3. Implement a **Provider** for each dependency, register with an **Injector**.\n\njeni runs on Python 2.7, Python 3.2 through 3.4, and pypy.\n\n\nMotivation\n==========\n\nWrite code as its meant to be written, without pegging function call signatures\nto some monolithic object that only applies to a specific runtime. This is\nabout more than just testing. This is about composition.\n\njeni's design principle is to have all annotated callables usable in a context\nthat knows nothing about jeni. Any callable is as relevant to a fresh Python\nREPL as it is to an injector.\n\n\nAnnotations\n===========\n\nAnnotations are implemented as decorators for Python2. In Python 3, either\ndecorators or function annotations can be used for injection.\n\n\nCore API\n========\n\n``annotate``\n------------\n\nAnnotate a callable with a decorator to provide data for Injectors.\n\nIntended use::\n\n from jeni import annotate\n\n @annotate('foo', 'bar')\n def function(foo, bar):\n return\n\nAn `Injector` would then need to register providers for 'foo' and 'bar'\nin order to apply this function; an injector with such providers can\napply the annotated function without any further information::\n\n injector.apply(function)\n\nTo get a partially applied function, to call later::\n\n fn = injector.partial(function)\n fn()\n\nAnnotation does not alter the callable's default behavior.\nCall it normally::\n\n foo, bar = 'foo', 'bar'\n function(foo, bar)\n\nOn Python 2, use decorators to annotate.\nOn Python 3, use either decorators or function annotations::\n\n from jeni import annotate\n\n @annotate\n def function(foo: 'foo', bar: 'bar'):\n return\n\nNote that when using Python function annotations, all injected values\nare provided as keyword arguments.\n\nSince function annotations could be interpreted differently by\ndifferent packages, injectors do not use ``function.__annotations__``\ndirectly. Functions opt in by a simple ``@annotate``\ndecoration. Functions with Python annotations which have not been\ndecorated are assumed to not be decorated for injection.\n\n(For this reason, annotating a callable with a single note where the\nnote is a callable is not supported.)\n\nNotes which are provided to `annotate` (above 'foo' and 'bar') can be\nany hashable object (i.e. object able to be used as a key in a dict)\nand is not limited to strings. If tuples are used as notes, they must\nbe of length 2, and `('maybe', ...)` and `('partial', ...)` are\nreserved.\n\n\n``Provider``\n------------\n\nProvide a single prepared dependency.\n\n\n``Provider.get(self, name=None)``\n---------------------------------\n\nImplement in subclass.\n\nAnnotations in the form of ``'object:name'`` will pass the `name` value\nto the `get` method of the registered `Provider` (in this case, the\nprovider registered with the `Injector` to provide `object`). This\nget-by-name pattern is useful for providers which have a dependency\nwhich supports lookups by key (e.g. HTTP headers or records in a\nkey-value store).\n\n\n``Provider.close(self)``\n------------------------\n\nBy default, does nothing. Close objects as needed in subclass.\n\nProvider close methods should not intentionally raise errors.\nSpecifically, if a dependency has transactions, the transaction should\nbe committed or rolled back before close is called, and not left as an\noperation to be called during the close phase.\n\nProvider close methods must not take an argument; an injector cannot\napply provided values on a close method since some providers may have\nalready been closed. If an injected value is needed for the close\nmethod, annotate ``__init__`` and access the value via `self`.\n\n\n``Injector``\n------------\n\nCollects dependencies and reads annotations to inject them.\n\n\n``Injector.__init__(self, provide_self=False)``\n-----------------------------------------------\n\nA subclass could take arguments, but should pass keywords to super.\n\nAn Injector subclass inherits the provider registry of its base\nclasses, but can override any provider by re-registering notes. When\norganizing a project, create an Injector subclass to serve as the\nobject to register all providers. This allows for the project to have\nits own namespace of registered dependencies. This registry can be\ncustomized by further subclasses, either for injecting mocks in testing\nor providing alternative dependencies in a different runtime::\n\n from jeni import Injector as BaseInjector\n\n class Injector(BaseInjector):\n \"Subclass provides namespace when registering providers.\"\n\nBy default, the injector does not provide itself, but will when asked::\n\n injector = Injector(provide_self=True)\n injector.get('injector')\n\nThis is useful in a context manager::\n\n with Injector(provide_self=True) as injector:\n injector.get('injector')\n\nAnnotate with note 'injector' to inject the injector.\n\n\n``Injector.sub(cls, *mixins_and_dicts, **values)``\n--------------------------------------------------\n\nCreate and instantiate a sub-injector.\n\nMixins and local value dicts can be passed in as arguments. Local\nvalues can also be passed in as keyword arguments.\n\n\n``Injector.provider(cls, note, provider=None, name=False)``\n-----------------------------------------------------------\n\nRegister a provider, either a Provider class or a generator.\n\nProvider class::\n\n from jeni import Injector as BaseInjector\n from jeni import Provider\n\n class Injector(BaseInjector):\n pass\n\n @Injector.provider('hello')\n class HelloProvider(Provider):\n def get(self, name=None):\n if name is None:\n name = 'world'\n return 'Hello, {}!'.format(name)\n\nSimple generator::\n\n @Injector.provider('answer')\n def answer():\n yield 42\n\nIf a generator supports get with a name argument::\n\n @Injector.provider('spam', name=True)\n def spam():\n count_str = yield 'spam'\n while True:\n count_str = yield 'spam' * int(count_str)\n\nRegistration can be a decorator or a direct method call::\n\n Injector.provider('hello', HelloProvider)\n\n\n``Injector.factory(cls, note, fn=None)``\n----------------------------------------\n\nRegister a function as a provider.\n\nFunction (name support is optional)::\n\n from jeni import Injector as BaseInjector\n from jeni import Provider\n\n class Injector(BaseInjector):\n pass\n\n @Injector.factory('echo')\n def echo(name=None):\n return name\n\nRegistration can be a decorator or a direct method call::\n\n Injector.factory('echo', echo)\n\n\n``Injector.value(cls, note, scalar)``\n-------------------------------------\n\nRegister a single value to be provided.\n\nSupports base notes only, does not support get-by-name notes.\n\n\n``Injector.apply(self, fn, *a, **kw)``\n--------------------------------------\n\nFully apply annotated callable, returning callable's result.\n\n\n``Injector.partial(self, fn, *user_args, **user_kwargs)``\n---------------------------------------------------------\n\nReturn function with closure to lazily inject annotated callable.\n\nRepeat calls to the resulting function will reuse injections from the\nfirst call.\n\nPositional arguments are provided in this order:\n\n1. positional arguments provided by injector\n2. positional arguments provided in `partial_fn = partial(fn, *args)`\n3. positional arguments provided in `partial_fn(*args)`\n\nKeyword arguments are resolved in this order (later override earlier):\n\n1. keyword arguments provided by injector\n2. keyword arguments provided in `partial_fn = partial(fn, **kwargs)`\n3. keyword arguments provided in `partial_fn(**kargs)`\n\nNote that Python function annotations (in Python 3) are injected as\nkeyword arguments, as documented in `annotate`, which affects the\nargument order here.\n\n`annotate.partial` accepts arguments in same manner as this `partial`.\n\n\n``Injector.eager_partial(self, fn, *a, **kw)``\n----------------------------------------------\n\nPartially apply annotated callable, returning a partial function.\n\nBy default, `partial` is lazy so that injections only happen when they\nare needed. Use `eager_partial` in place of `partial` when a guarantee\nof injection is needed at the time the partially applied function is\ncreated.\n\n`eager_partial` resolves arguments similarly to `partial` but relies on\n`functools.partial` for argument resolution when calling the final\npartial function.\n\n\n``Injector.apply_regardless(self, fn, *a, **kw)``\n-------------------------------------------------\n\nLike `apply`, but applies if callable is not annotated.\n\n\n``Injector.partial_regardless(self, fn, *a, **kw)``\n---------------------------------------------------\n\nLike `partial`, but applies if callable is not annotated.\n\n\n``Injector.eager_partial_regardless(self, fn, *a, **kw)``\n---------------------------------------------------------\n\nLike `eager_partial`, but applies if callable is not annotated.\n\n\n``Injector.get(self, note)``\n----------------------------\n\nResolve a single note into an object.\n\n\n``Injector.close(self)``\n------------------------\n\nClose injector & injected Provider instances, including generators.\n\nProviders are closed in the reverse order in which they were opened,\nand each provider is only closed once. Providers are closed if accessed\nby the injector, even if a dependency is not successfully provided. As\nsuch, providers should determine whether or not anything needs to be\ndone in the close method.\n\n\n``Injector.enter(self)``\n------------------------\n\nEnter context-manager without with-block. See also: `exit`.\n\nUseful for before- and after-hooks which cannot use a with-block.\n\n\n``Injector.exit(self)``\n-----------------------\n\nExit context-manager without with-block. See also: `enter`.\n\n\nAdditional API\n==============\n\n``annotate.wraps``\n------------------\n\nLike ``functools.wraps``, with support for annotations.\n\n\n``annotate.maybe``\n------------------\n\nWrap a keyword note to record that its resolution is optional.\n\nNormally all annotations require fulfilled dependencies, but if a\nkeyword argument is annotated as `maybe`, then on apply, an injector\ndoes not attempt to pass dependencies which are unset or not provided::\n\n from jeni import annotate\n\n @annotate('foo', bar=annotate.maybe('bar'))\n def foobar(foo, bar=None):\n return\n\n\n``annotate.partial``\n--------------------\n\nWrap a note for injection of a partially applied function.\n\nThis allows for annotated functions to be injected for composition::\n\n from jeni import annotate\n\n @annotate('foo', bar=annotate.maybe('bar'))\n def foobar(foo, bar=None):\n return\n\n @annotate('foo', annotate.partial(foobar))\n def bazquux(foo, fn):\n # fn: injector.partial(foobar)\n return\n\nKeyword arguments are treated as `maybe` when using partial, in order\nto allow partial application of only the notes which can be provided,\nwhere the caller could then apply arguments known to be unavailable in\nthe injector. Note that with Python 3 function annotations, all\nannotations are injected as keyword arguments.\n\nInjections on the partial function are lazy and not applied until the\ninjected partial function is called. See `eager_partial` to inject\neagerly.\n\n\n``annotate.eager_partial``\n--------------------------\n\nWrap a note for injection of an eagerly partially applied function.\n\nUse this instead of `partial` when eager injection is needed in place\nof lazy injection.\n\n\n``InjectorProxy``\n-----------------\n\nForwards getattr & getitem to enclosed injector.\n\nIf an injector has 'hello' registered::\n\n from jeni import InjectorProxy\n deps = InjectorProxy(injector)\n deps.hello\n\nGet by name can use dict-style access::\n\n deps['hello:name']\n\n\nLicense\n=======\n\nCopyright 2013-2015 Ron DuPlain (see AUTHORS file).\n\nReleased under the BSD License (see LICENSE file).", "description_content_type": null, "docs_url": null, "download_url": "UNKNOWN", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/rduplain/jeni-python", "keywords": null, "license": "BSD", "maintainer": null, "maintainer_email": null, "name": "jeni", "package_url": "https://pypi.org/project/jeni/", "platform": "UNKNOWN", "project_url": "https://pypi.org/project/jeni/", "project_urls": { "Download": "UNKNOWN", "Homepage": "https://github.com/rduplain/jeni-python" }, "release_url": "https://pypi.org/project/jeni/0.4.1/", "requires_dist": null, "requires_python": null, "summary": "jeni injects annotated dependencies", "version": "0.4.1" }, "last_serial": 1725615, "releases": { "0.3.1": [ { "comment_text": "", "digests": { "md5": "a0a7fe33d8a03ebdc74a45296afa11b7", "sha256": "dad880c18868083f90d97ed882207f80c94998519abb88e084974e96ff9033e4" }, "downloads": -1, "filename": "jeni-0.3.1.tar.bz2", "has_sig": false, "md5_digest": "a0a7fe33d8a03ebdc74a45296afa11b7", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 13533, "upload_time": "2014-06-28T18:01:20", "url": "https://files.pythonhosted.org/packages/f4/57/a2325a2b144f086a9e807b3e5e0cbfb9cd48633ec1d13eb0ec50b3a4a702/jeni-0.3.1.tar.bz2" }, { "comment_text": "", "digests": { "md5": "3e6cab36aa80fe977add25011b5564cf", "sha256": "2124c51950db1f75429d8f309e5e755135d8829132197d5456a07a963d25ca2b" }, "downloads": -1, "filename": "jeni-0.3.1.zip", "has_sig": false, "md5_digest": "3e6cab36aa80fe977add25011b5564cf", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 23960, "upload_time": "2014-06-28T18:01:23", "url": "https://files.pythonhosted.org/packages/57/fc/801121e03870769680df048bd24d8b1020289c5775147b2f7b98d5cc1eab/jeni-0.3.1.zip" } ], "0.3.2": [ { "comment_text": "", "digests": { "md5": "dc0a387274534d2835df1f8469cffe95", "sha256": "d067773e4f2bbb7be2baac9c0c0bbd1a6b123e66c78142f5ec3f00681dd2eddd" }, "downloads": -1, "filename": "jeni-0.3.2.tar.bz2", "has_sig": false, "md5_digest": "dc0a387274534d2835df1f8469cffe95", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 13590, "upload_time": "2014-07-14T01:00:01", "url": "https://files.pythonhosted.org/packages/13/67/cb7aff4bedc20cfc533b61817ab620dd3dc5b590d74525e1d460854533b6/jeni-0.3.2.tar.bz2" }, { "comment_text": "", "digests": { "md5": "e821646563add4c921ccd3398c0cb2c5", "sha256": "9014c9ba652f2f07fa588b789f740416cbcd23469f0f51029a7aefbef02a2785" }, "downloads": -1, "filename": "jeni-0.3.2.zip", "has_sig": false, "md5_digest": "e821646563add4c921ccd3398c0cb2c5", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 24037, "upload_time": "2014-07-14T01:00:04", "url": "https://files.pythonhosted.org/packages/56/25/1c02078043171db32e35ed0cc4f8769e7c2603df2a7bf19fff0ae499eb20/jeni-0.3.2.zip" } ], "0.3.3": [ { "comment_text": "", "digests": { "md5": "82848eb4905d0e545bfb714e7fc9c532", "sha256": "5f266edd86ee8eb6f948cabf6925d5bafb84740262ba6314c8b1b23174e80a24" }, "downloads": -1, "filename": "jeni-0.3.3.tar.bz2", "has_sig": false, "md5_digest": "82848eb4905d0e545bfb714e7fc9c532", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 14081, "upload_time": "2014-07-21T23:54:48", "url": "https://files.pythonhosted.org/packages/74/d1/0b2639a5feeccdc4e926495960166d5ecab4c9dac195810e85ecb2d72c31/jeni-0.3.3.tar.bz2" }, { "comment_text": "", "digests": { "md5": "f56d7b39c0a83cb3646e3061c15c51f9", "sha256": "a9671231d2a9cdcf6e874c343a3965209595ad4b252bbad2598bd107390255cd" }, "downloads": -1, "filename": "jeni-0.3.3.zip", "has_sig": false, "md5_digest": "f56d7b39c0a83cb3646e3061c15c51f9", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 24873, "upload_time": "2014-07-21T23:54:51", "url": "https://files.pythonhosted.org/packages/2e/9f/8d40ee00537e2a0588ae80ef4c2db07823c52198ab02117ced569e9be06d/jeni-0.3.3.zip" } ], "0.3.4": [ { "comment_text": "", "digests": { "md5": "f44da98cce8b4aca73a90d0696d1639a", "sha256": "62d17a9d78b7a7669f84595e29453d42ab95d3c5169c04598b8a52b6db46965a" }, "downloads": -1, "filename": "jeni-0.3.4.tar.bz2", "has_sig": false, "md5_digest": "f44da98cce8b4aca73a90d0696d1639a", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 15816, "upload_time": "2014-08-31T17:30:16", "url": "https://files.pythonhosted.org/packages/c3/e0/9ff2926ccc7a7f0e220b3c3b5f0dddb0b602b8db61fc5fe88ab8f6b23a22/jeni-0.3.4.tar.bz2" }, { "comment_text": "", "digests": { "md5": "34420c231f782198efeccf0a3d61efe4", "sha256": "d9d4d89ff720ac5cf2be865dde84278b8ee6846852bbb5bb5dc0bd9f277c1e41" }, "downloads": -1, "filename": "jeni-0.3.4.zip", "has_sig": false, "md5_digest": "34420c231f782198efeccf0a3d61efe4", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 28156, "upload_time": "2014-08-31T17:30:22", "url": "https://files.pythonhosted.org/packages/77/4d/8eca3df78891bff8578d77ddd2e3888955230ffcc1d9ef1d6626076cb607/jeni-0.3.4.zip" } ], "0.3.5": [ { "comment_text": "", "digests": { "md5": "bc6194ba2f469e53e7e38008487d7f99", "sha256": "1c39814e197a7d55ca0e9832d627878f81d648b7301738e4108df5380d1d449a" }, "downloads": -1, "filename": "jeni-0.3.5.tar.bz2", "has_sig": false, "md5_digest": "bc6194ba2f469e53e7e38008487d7f99", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 16078, "upload_time": "2014-09-24T21:02:01", "url": "https://files.pythonhosted.org/packages/c5/27/c1c793cf7d61424c2c764d6e6df9de18f224af9fc30916663dabc541f4d3/jeni-0.3.5.tar.bz2" }, { "comment_text": "", "digests": { "md5": "f4391a9106d6b0fd8eb58fdba5a0aa21", "sha256": "3f15b53d832ff08280f282629d58ea61cad4ff65ac878b588b6c7bc5769ecf65" }, "downloads": -1, "filename": "jeni-0.3.5.zip", "has_sig": false, "md5_digest": "f4391a9106d6b0fd8eb58fdba5a0aa21", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 28710, "upload_time": "2014-09-24T21:02:04", "url": "https://files.pythonhosted.org/packages/2b/24/3776e0d3114ae3cf5c33870bb555cc4df781653cf7c71881c29714e423b6/jeni-0.3.5.zip" } ], "0.3.6": [ { "comment_text": "", "digests": { "md5": "37f5998a64b9b529a3c8ff65e673e6ea", "sha256": "3e6f2026d6aae8bff176b89e109f2750f055e4e69f62b813dc3a960396d77028" }, "downloads": -1, "filename": "jeni-0.3.6.tar.bz2", "has_sig": false, "md5_digest": "37f5998a64b9b529a3c8ff65e673e6ea", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 16315, "upload_time": "2015-03-11T15:13:13", "url": "https://files.pythonhosted.org/packages/77/bb/d1fac816724923483142b066f350a808f9fb1b831cdf4c1ed9c4ff695127/jeni-0.3.6.tar.bz2" }, { "comment_text": "", "digests": { "md5": "f1c62a83136f110304da3443cfb092b5", "sha256": "14ba8fdd04cfd2630858d8e61a86762849a7011343a8f96f93ffeb942f572873" }, "downloads": -1, "filename": "jeni-0.3.6.zip", "has_sig": false, "md5_digest": "f1c62a83136f110304da3443cfb092b5", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 29206, "upload_time": "2015-03-11T15:13:16", "url": "https://files.pythonhosted.org/packages/51/76/a9b3d7bd9ee110a198c19401b26a8c160a696f1a585a1c308dddc56a39a7/jeni-0.3.6.zip" } ], "0.3.7": [ { "comment_text": "", "digests": { "md5": "0600ec4aef8f2d85c5ee6faa90dc546a", "sha256": "d9008cd96358202fcd2c2383068ad0c3a7d720778ccb7ad957ab2a92cac77a81" }, "downloads": -1, "filename": "jeni-0.3.7.tar.bz2", "has_sig": false, "md5_digest": "0600ec4aef8f2d85c5ee6faa90dc546a", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 17730, "upload_time": "2015-07-07T16:19:06", "url": "https://files.pythonhosted.org/packages/3a/54/2eaa237b1fe8dcbe42b29e08f13ad4eb8d8b048e482cc62de580a060f782/jeni-0.3.7.tar.bz2" }, { "comment_text": "", "digests": { "md5": "e63c9e60ad53a8f8abf2dea4a28bd40d", "sha256": "d80861e9daddc2d3f089ae2f493d1c636c644463ce6481384ca570f60e7b5003" }, "downloads": -1, "filename": "jeni-0.3.7.zip", "has_sig": false, "md5_digest": "e63c9e60ad53a8f8abf2dea4a28bd40d", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 31330, "upload_time": "2015-07-07T16:19:10", "url": "https://files.pythonhosted.org/packages/10/56/606497ea1ae28a88cfe31ce0c94dba1ed95ec55945d2768e6940d4d08e22/jeni-0.3.7.zip" } ], "0.3.8": [ { "comment_text": "", "digests": { "md5": "6c8c1a46db5e7f711e0af7efba2a708d", "sha256": "d0123b373a361332759d3188fbe1520947c6a5795fdda4d88d1fbd513ccd59e9" }, "downloads": -1, "filename": "jeni-0.3.8.tar.bz2", "has_sig": false, "md5_digest": "6c8c1a46db5e7f711e0af7efba2a708d", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 17558, "upload_time": "2015-07-21T21:07:53", "url": "https://files.pythonhosted.org/packages/cc/5a/1c1702c07ec9d8b1591c8aedf36c22fb90387843362e001ef5916af2a0a8/jeni-0.3.8.tar.bz2" }, { "comment_text": "", "digests": { "md5": "6d716b713f52ebf0c460b5343e294f46", "sha256": "dc7aca0aa57f572777ec3a58c71b4f85bed6c8282893d22042b89b6597a9c3dc" }, "downloads": -1, "filename": "jeni-0.3.8.zip", "has_sig": false, "md5_digest": "6d716b713f52ebf0c460b5343e294f46", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 31075, "upload_time": "2015-07-21T21:07:57", "url": "https://files.pythonhosted.org/packages/7f/73/d71a8054eb431b4f045219c82d98eab3e9fb0075f80135e04a22f47e5b24/jeni-0.3.8.zip" } ], "0.4.0": [ { "comment_text": "", "digests": { "md5": "a7c4296cb51e62c89685026b101419f5", "sha256": "f8171cfba22cbe626dfd39fbbbb031acfb106d438871b32ed494ed670d12aa8c" }, "downloads": -1, "filename": "jeni-0.4.0.tar.bz2", "has_sig": false, "md5_digest": "a7c4296cb51e62c89685026b101419f5", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 17561, "upload_time": "2015-07-23T00:29:01", "url": "https://files.pythonhosted.org/packages/55/ae/88755910a5da6507ead029191c0b8a50bf2f2736e5e3a303edfc3482aa70/jeni-0.4.0.tar.bz2" }, { "comment_text": "", "digests": { "md5": "bde08703b8c44d1556be098e29e8b063", "sha256": "c496df331757607c9c98c13acb3d93ef5be2a3d175a93973ccaf118b3edc2626" }, "downloads": -1, "filename": "jeni-0.4.0.zip", "has_sig": false, "md5_digest": "bde08703b8c44d1556be098e29e8b063", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 31180, "upload_time": "2015-07-23T00:29:04", "url": "https://files.pythonhosted.org/packages/d1/06/5892ef4d274dfe9cbff24892ece47e1d545246002c1bc2ed85f31d66b674/jeni-0.4.0.zip" } ], "0.4.1": [ { "comment_text": "", "digests": { "md5": "6d05da5eb687fbb7a310249a4167cc4a", "sha256": "f9e4fe4fba0c660c46ee6b4e471d5c07f8a91e207f9ce21b869a97b96dc7c6bd" }, "downloads": -1, "filename": "jeni-0.4.1.tar.bz2", "has_sig": false, "md5_digest": "6d05da5eb687fbb7a310249a4167cc4a", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 17559, "upload_time": "2015-09-16T19:22:02", "url": "https://files.pythonhosted.org/packages/1f/35/9c16cc93a946e8cd4a4dcd661e92f70eb6bbf71cb6b4faecff00aa0818ab/jeni-0.4.1.tar.bz2" }, { "comment_text": "", "digests": { "md5": "26792a1e059bb0f4cb885076e5b8412b", "sha256": "c9bca43db82a9642233d72c69c77ba96b4f0f7f56e5c95bed45f047bad357504" }, "downloads": -1, "filename": "jeni-0.4.1.zip", "has_sig": false, "md5_digest": "26792a1e059bb0f4cb885076e5b8412b", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 31199, "upload_time": "2015-09-16T19:22:13", "url": "https://files.pythonhosted.org/packages/7a/41/c8355db682c0a2bb107ec45fee84acd65b2a08f5ad1ac8700cceb2c12871/jeni-0.4.1.zip" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "6d05da5eb687fbb7a310249a4167cc4a", "sha256": "f9e4fe4fba0c660c46ee6b4e471d5c07f8a91e207f9ce21b869a97b96dc7c6bd" }, "downloads": -1, "filename": "jeni-0.4.1.tar.bz2", "has_sig": false, "md5_digest": "6d05da5eb687fbb7a310249a4167cc4a", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 17559, "upload_time": "2015-09-16T19:22:02", "url": "https://files.pythonhosted.org/packages/1f/35/9c16cc93a946e8cd4a4dcd661e92f70eb6bbf71cb6b4faecff00aa0818ab/jeni-0.4.1.tar.bz2" }, { "comment_text": "", "digests": { "md5": "26792a1e059bb0f4cb885076e5b8412b", "sha256": "c9bca43db82a9642233d72c69c77ba96b4f0f7f56e5c95bed45f047bad357504" }, "downloads": -1, "filename": "jeni-0.4.1.zip", "has_sig": false, "md5_digest": "26792a1e059bb0f4cb885076e5b8412b", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 31199, "upload_time": "2015-09-16T19:22:13", "url": "https://files.pythonhosted.org/packages/7a/41/c8355db682c0a2bb107ec45fee84acd65b2a08f5ad1ac8700cceb2c12871/jeni-0.4.1.zip" } ] }