Name | diject JSON |
Version |
0.7.1
JSON |
| download |
home_page | None |
Summary | A powerful dependency injection framework that automatically injects objects, promoting loose coupling, improving testability, and centralizing configuration for easier maintenance. |
upload_time | 2025-02-22 11:30:25 |
maintainer | Mateusz Baran |
docs_url | None |
author | Mateusz Baran |
requires_python | >=3.11 |
license | MIT License Copyright (c) 2024 Mateusz Baran Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
keywords |
dependency
injection
|
VCS |
 |
bugtrack_url |
|
requirements |
No requirements were recorded.
|
Travis-CI |
No Travis.
|
coveralls test coverage |
No coveralls.
|
# diject
A powerful dependency injection framework that automatically injects objects,
promoting loose coupling, improving testability,
and centralizing configuration for easier maintenance.
## What is dependency injection?
Dependency Injection (DI) is a design pattern that decouples the creation of
an object's dependencies from the object itself. Instead of hard-coding dependencies,
they are provided ("injected") from the outside.
## Why Use Dependency Injection in Python?
Even though Python is a dynamically-typed language with flexible object construction, DI brings
significant benefits:
* **Better Structure**: By explicitly declaring dependencies, the code becomes self-documenting and
easier to understand.
* **Simplified Testing**: Dependencies can be replaced with mocks effortlessly, reducing the
overhead of setting up tests.
* **Enhanced Maintainability**: Changes to the implementation of a dependency do not ripple through
the codebase as long as the interface remains consistent.
## How to use diject?
**diject** simplifies the process of configuring and setting object dependencies.
The framework allows you to:
* Define your classes with explicit dependencies in the constructor.
* Configure a container where you specify how each dependency should be provided (as singletons,
factories, etc.).
* Use decorators (e.g., @di.inject) to automatically inject dependencies into functions or class
methods.
By centralizing the configuration in a container, diject enables consistent dependency management
across your application.
## Examples
### Basic Example
A typical Python application without dependency injection might instantiate dependencies directly:
```python
import os
class Database:
def __init__(self) -> None:
self.uri = os.getenv("DATABASE_URI") # <-- dependency
class Service:
def __init__(self) -> None:
self.db = Database() # <-- dependency
def main() -> None:
service = Service() # <-- dependency
# some logic here...
...
if __name__ == "__main__":
main()
```
### Dependency Injection Pattern
In a DI pattern, dependencies are passed into objects rather than being created inside them:
```python
import os
class Database:
def __init__(self, uri: str) -> None: # <-- dependency is injected
self.uri = uri
class Service:
def __init__(self, db: Database) -> None: # <-- dependency is injected
self.db = db
DATABASE = Database( # <-- create global database instance
uri=os.getenv("DATABASE_URI"),
)
def create_service() -> Service: # <-- creates new instance for each call
return Service(
db=DATABASE,
)
def main(service: Service) -> None: # <-- dependency is injected
# some logic here...
...
if __name__ == "__main__":
main(
service=create_service(), # <-- injecting dependency
)
```
### Using diject
With diject, you can simplify dependency management further by declaring a container for your
configurations:
```python
import os
import diject as di
class Database:
def __init__(self, uri: str) -> None: # <-- dependency is injected
self.uri = uri
class Service:
def __init__(self, db: Database) -> None: # <-- dependency is injected
self.db = db
class MainContainer(di.Container): # <-- container for configuration
database = di.Singleton[Database]( # <-- creates one instance for entire application
uri=os.getenv("DATABASE_URI"),
)
service = di.Factory[Service]( # <-- creates new instance for each call
db=database, # <-- injecting always the same database instance
)
@di.inject
def main(service: Service = MainContainer.service) -> None: # <-- injecting dependency by default
# some logic here...
...
if __name__ == "__main__":
main() # <-- service is injected automatically
```
# Key Concepts and Features
* **Sync & Async Support**: Seamlessly manage both synchronous and asynchronous dependencies.
* **Pure Python Implementation**: No need for external dependencies or language modifications.
* **Performance**: Low overhead with efficient dependency resolution.
* **Clear Debugging**: Built-in logging and debugging aids help trace dependency injection flow.
* **Type Safety**: Full MyPy and type annotation support ensures robust static analysis.
* **Easy Testing**: Simplified testing with native support for mocks and patches.
* **Integration**: Easily integrate with other frameworks and libraries.
* **Inheritance and Protocols**: Use Python's protocols to enforce contracts and ensure consistency
across implementations.
# Installation
```shell
pip install diject
```
# Providers
diject gives you fine-grained control over the lifecycle of your objects.
Consider the following example functions:
```python
def some_function(arg: str) -> str:
# some logic here...
return "some_output"
def some_iterator(arg: str) -> Iterator[str]:
# some preparation logic here...
yield "some_output"
# some clean up logic here...
```
## Creators
Creators are responsible for creating new instances whenever a dependency is requested.
### Factory
A **Factory** creates a new instance on every request.
```python
some_factory = di.Factory[some_function](arg="some_value")
```
## Services
Services manage dependencies that require a setup phase (before use) and a cleanup phase (after
use). They are especially useful for dependencies defined as generators, but they also work
with functions and classes.
### Singleton
A **Singleton** is lazily instantiated and then shared throughout the application's lifetime.
```python
some_singleton = di.Singleton[some_iterator](arg="some_value")
```
To clear the singleton's state, call:
```python
di.Provide[some_singleton].reset()
```
### Resource
A **Resource** is eagerly instantiated and shared for the application's lifetime.
```python
some_resource = di.Resource[some_iterator](arg="some_value")
```
Start the resource before use:
```python
di.Provide[some_resource].start()
```
Shutdown the resource to perform cleanup with all dependencies:
```python
di.Provide[some_resource].shutdown()
```
### Scoped
A **Scoped** provider behaves like a singleton within a specific scope. Within that scope, the
same instance is reused.
```python
scoped_provider = di.Scoped[some_iterator](arg="some_value")
```
You can inject a scoped dependency using the `@di.inject` decorator:
```python
@di.inject
def func(some_instance: Any = scoped_provider):
# Use some_instance within this function
pass
```
Or by using a context manager:
```python
with di.Provide[scoped_provider] as some_instance:
# Use some_instance within this block
pass
```
### Transient
A **Transient** dependency is similar to a scoped dependency but creates a new instance every time
it is requested—behaving like a factory.
```python
transient_provider = di.Transient[some_iterator](arg="some_value")
```
### Thread
A **Thread** dependency is similar to a singleton, but it creates and maintains separate instances
for each thread.
```python
thread_provider = di.Thread[some_iterator](arg="some_value")
```
## Object
An Object holds a constant value that is injected on request.
Instances defined in containers or as function arguments are automatically wrapped
by an ObjectProvider.
## Selector
Selectors allow you to include conditional logic (like an if statement) to configure
your application for different variants.
For example, to choose a repository implementation based on an environment variable:
```python
repository = di.Selector[os.getenv("DATABASE")](
in_memory=di.Factory[InMemoryRepository](),
mysql=di.Factory[MySqlRepository](),
)
```
You can also use a grouped approach if multiple selectors share the same selection variable:
```python
with di.Selector[os.getenv("DATABASE")] as Selector:
user_repository = Selector[UserRepository]()
book_repository = Selector[BookRepository]()
with Selector == "in_memory" as Option:
Option[user_repository] = di.Factory[InMemoryUserRepository]()
Option[book_repository] = di.Factory[InMemoryBookRepository]()
with Selector == "mysql" as Option:
Option[user_repository] = di.Factory[MySqlUserRepository]()
Option[book_repository] = di.Factory[MySqlBookRepository]()
```
## Container
Containers group related dependencies together. They are defined by subclassing di.Container:
```python
class MainContainer(di.Container):
service = di.Factory[Service]()
```
You can inject an entire container so that its attributes are automatically
provided within the same scope:
```python
with di.Provide[MainContainer] as container:
service = container.service # <-- container provide service object
# Use some_instance within this block
pass
```
## Attribute & Callable
Providers mimic the objects they create.
This means you can access attributes or call them directly,
and the actual object is instantiated lazily on request.
```python
factory = di.Factory[SomeClass]()
# Access an attribute (or call a method) on the provided instance:
some_value = di.Provide[factory.get_value()]()
```
# Providable
### Provide
Providers can be provided in five ways:
* as decorator
```python
@di.inject
def function(some_value: Any = some_provider):
pass
```
* Sync without scope
```python
some_value = di.Provide[some_provider]()
```
* Async without scope
```python
some_value = await di.Provide[some_provider]
```
* Sync with scope
```python
with di.Provide[some_provider] as some_value:
pass
```
* Async with scope
```python
async with di.Provide[some_provider] as some_value:
pass
```
### Traversal
The Travers functionality allows you to iterate over all providers. Its parameters include:
* **types**: Filter by specific provider types.
* **recursive**: Traverse providers recursively.
* **only_public**: Include only public providers.
* **only_selected**: Include only providers that have been selected.
```python
for name, provider in di.Provide[some_resource].travers():
pass
```
### Status
You can retrieve the status of a Resource to determine whether it has started, stopped,
or if an error occurred during startup:
```python
di.Provide[some_resource].status()
```
### Get provider
Retrieve the underlying provider instance.
This is primarily used to map a "pretender" type to its actual provider type:
```python
di.Provide[pretender].provider
```
# License
Distributed under the terms of the [MIT license](LICENSE),
**diject** is free and open source framework.
# Contribution
Contributions are always welcome! To ensure everything runs smoothly,
please run tests using `tox` before submitting your changes.
Your efforts help maintain the project's quality and drive continuous improvement.
# Issues
If you encounter any problems, please leave [issue](../../issues/new), along with a detailed
description.
---
*Happy coding with diject! Enjoy cleaner, more maintainable Python applications through effective
dependency injection.*
Raw data
{
"_id": null,
"home_page": null,
"name": "diject",
"maintainer": "Mateusz Baran",
"docs_url": null,
"requires_python": ">=3.11",
"maintainer_email": null,
"keywords": "Dependency Injection",
"author": "Mateusz Baran",
"author_email": null,
"download_url": "https://files.pythonhosted.org/packages/78/f5/ba2aea2dcebef4e335887dd7910977a9776ae0cff5f5fcae1e45e8c7727d/diject-0.7.1.tar.gz",
"platform": null,
"description": "# diject\n\nA powerful dependency injection framework that automatically injects objects,\npromoting loose coupling, improving testability,\nand centralizing configuration for easier maintenance.\n\n## What is dependency injection?\n\nDependency Injection (DI) is a design pattern that decouples the creation of\nan object's dependencies from the object itself. Instead of hard-coding dependencies,\nthey are provided (\"injected\") from the outside.\n\n## Why Use Dependency Injection in Python?\n\nEven though Python is a dynamically-typed language with flexible object construction, DI brings\nsignificant benefits:\n\n* **Better Structure**: By explicitly declaring dependencies, the code becomes self-documenting and\n easier to understand.\n* **Simplified Testing**: Dependencies can be replaced with mocks effortlessly, reducing the\n overhead of setting up tests.\n* **Enhanced Maintainability**: Changes to the implementation of a dependency do not ripple through\n the codebase as long as the interface remains consistent.\n\n## How to use diject?\n\n**diject** simplifies the process of configuring and setting object dependencies.\nThe framework allows you to:\n\n* Define your classes with explicit dependencies in the constructor.\n* Configure a container where you specify how each dependency should be provided (as singletons,\n factories, etc.).\n* Use decorators (e.g., @di.inject) to automatically inject dependencies into functions or class\n methods.\n\nBy centralizing the configuration in a container, diject enables consistent dependency management\nacross your application.\n\n## Examples\n\n### Basic Example\n\nA typical Python application without dependency injection might instantiate dependencies directly:\n\n```python\nimport os\n\n\nclass Database:\n def __init__(self) -> None:\n self.uri = os.getenv(\"DATABASE_URI\") # <-- dependency\n\n\nclass Service:\n def __init__(self) -> None:\n self.db = Database() # <-- dependency\n\n\ndef main() -> None:\n service = Service() # <-- dependency\n # some logic here...\n ...\n\n\nif __name__ == \"__main__\":\n main()\n```\n\n### Dependency Injection Pattern\n\nIn a DI pattern, dependencies are passed into objects rather than being created inside them:\n\n```python\nimport os\n\n\nclass Database:\n def __init__(self, uri: str) -> None: # <-- dependency is injected\n self.uri = uri\n\n\nclass Service:\n def __init__(self, db: Database) -> None: # <-- dependency is injected\n self.db = db\n\n\nDATABASE = Database( # <-- create global database instance\n uri=os.getenv(\"DATABASE_URI\"),\n)\n\n\ndef create_service() -> Service: # <-- creates new instance for each call\n return Service(\n db=DATABASE,\n )\n\n\ndef main(service: Service) -> None: # <-- dependency is injected\n # some logic here...\n ...\n\n\nif __name__ == \"__main__\":\n main(\n service=create_service(), # <-- injecting dependency\n )\n```\n\n### Using diject\n\nWith diject, you can simplify dependency management further by declaring a container for your\nconfigurations:\n\n```python\nimport os\nimport diject as di\n\n\nclass Database:\n def __init__(self, uri: str) -> None: # <-- dependency is injected\n self.uri = uri\n\n\nclass Service:\n def __init__(self, db: Database) -> None: # <-- dependency is injected\n self.db = db\n\n\nclass MainContainer(di.Container): # <-- container for configuration\n database = di.Singleton[Database]( # <-- creates one instance for entire application\n uri=os.getenv(\"DATABASE_URI\"),\n )\n\n service = di.Factory[Service]( # <-- creates new instance for each call\n db=database, # <-- injecting always the same database instance\n )\n\n\n@di.inject\ndef main(service: Service = MainContainer.service) -> None: # <-- injecting dependency by default\n # some logic here...\n ...\n\n\nif __name__ == \"__main__\":\n main() # <-- service is injected automatically\n```\n\n# Key Concepts and Features\n\n* **Sync & Async Support**: Seamlessly manage both synchronous and asynchronous dependencies.\n* **Pure Python Implementation**: No need for external dependencies or language modifications.\n* **Performance**: Low overhead with efficient dependency resolution.\n* **Clear Debugging**: Built-in logging and debugging aids help trace dependency injection flow.\n* **Type Safety**: Full MyPy and type annotation support ensures robust static analysis.\n* **Easy Testing**: Simplified testing with native support for mocks and patches.\n* **Integration**: Easily integrate with other frameworks and libraries.\n* **Inheritance and Protocols**: Use Python's protocols to enforce contracts and ensure consistency\n across implementations.\n\n# Installation\n\n```shell\npip install diject\n```\n\n# Providers\n\ndiject gives you fine-grained control over the lifecycle of your objects.\nConsider the following example functions:\n\n```python\ndef some_function(arg: str) -> str:\n # some logic here...\n return \"some_output\"\n\n\ndef some_iterator(arg: str) -> Iterator[str]:\n # some preparation logic here...\n yield \"some_output\"\n # some clean up logic here...\n```\n\n## Creators\n\nCreators are responsible for creating new instances whenever a dependency is requested.\n\n### Factory\n\nA **Factory** creates a new instance on every request.\n\n```python\nsome_factory = di.Factory[some_function](arg=\"some_value\")\n```\n\n## Services\n\nServices manage dependencies that require a setup phase (before use) and a cleanup phase (after\nuse). They are especially useful for dependencies defined as generators, but they also work\nwith functions and classes.\n\n### Singleton\n\nA **Singleton** is lazily instantiated and then shared throughout the application's lifetime.\n\n```python\nsome_singleton = di.Singleton[some_iterator](arg=\"some_value\")\n```\n\nTo clear the singleton's state, call:\n\n```python\ndi.Provide[some_singleton].reset()\n```\n\n### Resource\n\nA **Resource** is eagerly instantiated and shared for the application's lifetime.\n\n```python\nsome_resource = di.Resource[some_iterator](arg=\"some_value\")\n```\n\nStart the resource before use:\n\n```python\ndi.Provide[some_resource].start()\n```\n\nShutdown the resource to perform cleanup with all dependencies:\n\n```python\ndi.Provide[some_resource].shutdown()\n```\n\n### Scoped\n\nA **Scoped** provider behaves like a singleton within a specific scope. Within that scope, the\nsame instance is reused.\n\n```python\nscoped_provider = di.Scoped[some_iterator](arg=\"some_value\")\n```\n\nYou can inject a scoped dependency using the `@di.inject` decorator:\n\n```python\n@di.inject\ndef func(some_instance: Any = scoped_provider):\n # Use some_instance within this function\n pass\n```\n\nOr by using a context manager:\n\n```python\nwith di.Provide[scoped_provider] as some_instance:\n # Use some_instance within this block\n pass\n```\n\n### Transient\n\nA **Transient** dependency is similar to a scoped dependency but creates a new instance every time\nit is requested\u2014behaving like a factory.\n\n```python\ntransient_provider = di.Transient[some_iterator](arg=\"some_value\")\n```\n\n### Thread\n\nA **Thread** dependency is similar to a singleton, but it creates and maintains separate instances\nfor each thread.\n\n```python\nthread_provider = di.Thread[some_iterator](arg=\"some_value\")\n```\n\n## Object\n\nAn Object holds a constant value that is injected on request.\nInstances defined in containers or as function arguments are automatically wrapped\nby an ObjectProvider.\n\n## Selector\n\nSelectors allow you to include conditional logic (like an if statement) to configure\nyour application for different variants.\n\nFor example, to choose a repository implementation based on an environment variable:\n\n```python\nrepository = di.Selector[os.getenv(\"DATABASE\")](\n in_memory=di.Factory[InMemoryRepository](),\n mysql=di.Factory[MySqlRepository](),\n)\n```\n\nYou can also use a grouped approach if multiple selectors share the same selection variable:\n\n```python\nwith di.Selector[os.getenv(\"DATABASE\")] as Selector:\n user_repository = Selector[UserRepository]()\n book_repository = Selector[BookRepository]()\n\nwith Selector == \"in_memory\" as Option:\n Option[user_repository] = di.Factory[InMemoryUserRepository]()\n Option[book_repository] = di.Factory[InMemoryBookRepository]()\n\nwith Selector == \"mysql\" as Option:\n Option[user_repository] = di.Factory[MySqlUserRepository]()\n Option[book_repository] = di.Factory[MySqlBookRepository]()\n```\n\n## Container\n\nContainers group related dependencies together. They are defined by subclassing di.Container:\n\n```python\nclass MainContainer(di.Container):\n service = di.Factory[Service]()\n```\n\nYou can inject an entire container so that its attributes are automatically\nprovided within the same scope:\n\n```python\nwith di.Provide[MainContainer] as container:\n service = container.service # <-- container provide service object\n # Use some_instance within this block\n pass\n```\n\n## Attribute & Callable\n\nProviders mimic the objects they create.\nThis means you can access attributes or call them directly,\nand the actual object is instantiated lazily on request.\n\n```python\nfactory = di.Factory[SomeClass]()\n\n# Access an attribute (or call a method) on the provided instance:\nsome_value = di.Provide[factory.get_value()]()\n```\n\n# Providable\n\n### Provide\n\nProviders can be provided in five ways:\n* as decorator\n```python\n@di.inject\ndef function(some_value: Any = some_provider):\n pass\n```\n* Sync without scope\n```python\nsome_value = di.Provide[some_provider]()\n```\n* Async without scope\n```python\nsome_value = await di.Provide[some_provider]\n```\n* Sync with scope\n```python\nwith di.Provide[some_provider] as some_value:\n pass\n```\n* Async with scope\n```python\nasync with di.Provide[some_provider] as some_value:\n pass\n```\n\n### Traversal\n\nThe Travers functionality allows you to iterate over all providers. Its parameters include:\n\n* **types**: Filter by specific provider types.\n* **recursive**: Traverse providers recursively.\n* **only_public**: Include only public providers.\n* **only_selected**: Include only providers that have been selected.\n\n```python\nfor name, provider in di.Provide[some_resource].travers():\n pass\n```\n\n### Status\n\nYou can retrieve the status of a Resource to determine whether it has started, stopped,\nor if an error occurred during startup:\n\n```python\ndi.Provide[some_resource].status()\n```\n\n### Get provider\n\nRetrieve the underlying provider instance.\nThis is primarily used to map a \"pretender\" type to its actual provider type:\n\n```python\ndi.Provide[pretender].provider\n```\n\n# License\n\nDistributed under the terms of the [MIT license](LICENSE),\n**diject** is free and open source framework.\n\n# Contribution\n\nContributions are always welcome! To ensure everything runs smoothly,\nplease run tests using `tox` before submitting your changes.\nYour efforts help maintain the project's quality and drive continuous improvement.\n\n# Issues\n\nIf you encounter any problems, please leave [issue](../../issues/new), along with a detailed\ndescription.\n\n---\n\n*Happy coding with diject! Enjoy cleaner, more maintainable Python applications through effective\ndependency injection.*\n",
"bugtrack_url": null,
"license": "MIT License Copyright (c) 2024 Mateusz Baran Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ",
"summary": "A powerful dependency injection framework that automatically injects objects, promoting loose coupling, improving testability, and centralizing configuration for easier maintenance.",
"version": "0.7.1",
"project_urls": {
"repository": "https://github.com/mateuszbaransanok/diject"
},
"split_keywords": [
"dependency",
"injection"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "09686425b212f8d79266bf510dca032b0d6b06b84a6eb633b2d8757f632abfa7",
"md5": "c6ef5a2141fbce9559edf99935535a3b",
"sha256": "46f5689ea19ee989d95f3aec2bfa42156ccbdd033722bf3f3697941bc72bd4ad"
},
"downloads": -1,
"filename": "diject-0.7.1-py3-none-any.whl",
"has_sig": false,
"md5_digest": "c6ef5a2141fbce9559edf99935535a3b",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.11",
"size": 34097,
"upload_time": "2025-02-22T11:30:23",
"upload_time_iso_8601": "2025-02-22T11:30:23.162454Z",
"url": "https://files.pythonhosted.org/packages/09/68/6425b212f8d79266bf510dca032b0d6b06b84a6eb633b2d8757f632abfa7/diject-0.7.1-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "78f5ba2aea2dcebef4e335887dd7910977a9776ae0cff5f5fcae1e45e8c7727d",
"md5": "87a724a0f3806f5cf01355557eeaf43a",
"sha256": "ada8241ed4fe4fb1bb91ea5ec4febcec48d24084c5954fb4f575df53f097cbe5"
},
"downloads": -1,
"filename": "diject-0.7.1.tar.gz",
"has_sig": false,
"md5_digest": "87a724a0f3806f5cf01355557eeaf43a",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.11",
"size": 26329,
"upload_time": "2025-02-22T11:30:25",
"upload_time_iso_8601": "2025-02-22T11:30:25.253882Z",
"url": "https://files.pythonhosted.org/packages/78/f5/ba2aea2dcebef4e335887dd7910977a9776ae0cff5f5fcae1e45e8c7727d/diject-0.7.1.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-02-22 11:30:25",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "mateuszbaransanok",
"github_project": "diject",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "diject"
}