pinjet-core


Namepinjet-core JSON
Version 0.0.1b1 PyPI version JSON
download
home_pageNone
SummarySmall like a pin, fast like a jet! A lightweight Dependency Injection library for python
upload_time2024-04-13 13:09:06
maintainerNone
docs_urlNone
authorabetrack3 (Abrar Shahriar Abeed)
requires_pythonNone
licenseNone
keywords python dependency injection di framework ioc inversion of control
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            
# Pinjet
#### Small like a pin, fast like a jet! A lightweight Dependency Injection library for Python

---

## Installation

```shell
pip install pinjet-core
```
---

## Introdcution

Numerous Dependency Injection (DI) frameworks exist for Python, yet none are flawless or intuitive, whether in terms of syntax or programmatically configuring. This led to the creation of Pinjet, a simple and intuitive DI library, that requires minimal or no configuration code at all. Simply annotate your classes and methods with **Pinjet decorators**, and it take cares of the rest. Pinjet follows **annotation-first** approach, drawing inspiration from Java **Spring** and **Spring Boot**, making project initialization as effortless as possible. This approach is particularly beneficial for developers experienced in Java and Spring Boot, easing their transition to **Pinjet** projects.

*In Pinjet, the terms "annotation" and "decorator" are frequently interchanged and carry the same meaning.*

#### Quick Exmaple
```python
from pinjet.core.resolver.dependency_resolver import DependencyResolver
from pinjet.core.annotations.injectable import injectable

@injectable
class InjectableClassToBeResolved:
    pass

result = DependencyResolver.resolve(InjectableClassToBeResolved)

```

Pinjet simplifies the usage by employing `@injectable` to mark any classes requiring injection. Unlike Spring Boot, where figuring out when to use `@Component` or `@Service` can be daunting, Pinjet offers a more straightforward approach.

---

## Customizing Dependency Scope

By default, any class marked with `@injectable` is considered a singleton, ensuring the same instance is returned every time `resolve()` is called. However, if you prefer a new instance on each call to `resolve()`, simply specify the dependency scope as **PROTOTYPE** in `@injectable`.

#### Example
```python

from pinjet.core.annotations.injectable import injectable
from pinjet.core.constants.dependency_scope import DependencyScope
from pinjet.core.resolver.dependency_resolver import DependencyResolver


@injectable(scope=DependencyScope.PROTOTYPE)
class PrototypeClassToBeResolved:
    pass

resolved_instance_1 = DependencyResolver.resolve(PrototypeClassToBeResolved)
resolved_instance_2 = DependencyResolver.resolve(PrototypeClassToBeResolved)

is_different_instance: bool = resolved_instance_1 is not resolved_instance_2 # True
```

---

## Customization with Providers

Pinjet allows customization of class instantiation and resolution via `@provider` and `@provides`. For instance:

```python
from argparse import ArgumentParser
from pinjet.core.annotations.provider import provider, provides
from pinjet.core.resolver.dependency_resolver import DependencyResolver

@provider
class ArgumentParserProvider:

    @provides
    def get_argument_parser(self) -> ArgumentParser:
        argument_parser = ArgumentParser()
        argument_parser.add_argument('--environment', type=str, required=False)
        argument_parser.set_defaults(configuration='development')
        return argument_parser

argument_parser = DependencyResolver.resolve(ArgumentParser)
```

This approach is also applicable when injecting classes from third-party libraries that cannot be modified to include `@injectable`.

---

## Scanning Ahead of Time

For any Python projects where codes are distributed across modules, Pinjet recommends wrapping the program's starting point, which is often, `__main__()` with `@pinjet_application`. This allows Pinjet to:

- scan the repository to identify all dependencies with the help of `@pinjet_application`
- ensuring `DependencyResolver` is primed to serve the application.

#### Example

```python
from argparse import ArgumentParser

from pinjet.core.annotations.bootstrap import pinjet_application
from pinjet.core.resolver.dependency_resolver import DependencyResolver


@pinjet_application
def __main__():

    argument_parser: ArgumentParser = DependencyResolver.resolve(ArgumentParser)


if __name__ == '__main__':
    __main__()
```
Here ArgumentParser is configured to instantiate using `@provider` and `@provides` on a separate module which Pinjet is not aware of, if the program starting point is not marked with `@pinjet_application`

---

## Decorator Type Safety

To enhance developer experience, Pinjet introduces decorator type safety. For example, `@injectable` is exclusively meant for **classes**, while `@pinjet_application` is meant for **functions**. Introducing `@target`, a special decorator, which ensures decorators are applied to their intended elements.

#### Quick Demonstration

```python
from functools import wraps
from pinjet.core.annotations.target import target
from pinjet.core.constants.element_type import ElementType

@target(ElementType.FUNCTION)
def simple_function_decorator(function):

    @wraps(function)
    def decorator(*args, **kwargs):

        result = function(*args, **kwargs)

        return result

    return decorator

@simple_function_decorator
def sample_function_to_be_decorated():
    print('Inside sample_method_to_be_decorated')

sample_function_to_be_decorated() # prints: 'Inside sample_method_to_be_decorated'

```

With `@target` we are now enforcing that the decorator `simple_function_decorator` can only be used on functions. Attempting to use a decorator on an incorrect element type will raise a `TargetElementTypeMisMatchException` with a comprehensive error message.

You can write your own custom decorator and enforce its usage with `@target` as well!

---

## Development Status

Pinjet is in its early stages and under active development. Numerous features are planned for future releases. Suggestions, improvements, and open-source contributions are most welcome. While the project may initially seem small like a pin, it is poised to grow as fast as a jet!

---

# Thank you

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "pinjet-core",
    "maintainer": null,
    "docs_url": null,
    "requires_python": null,
    "maintainer_email": null,
    "keywords": "python, dependency injection, di framework, ioc, inversion of control",
    "author": "abetrack3 (Abrar Shahriar Abeed)",
    "author_email": "<abrarshahriar2361@gmail.com>",
    "download_url": "https://files.pythonhosted.org/packages/ee/e8/baf81d478f2c515d31b3431952d6f8fffe29d876d06d1544046c8bcba024/pinjet-core-0.0.1b1.tar.gz",
    "platform": null,
    "description": "\n# Pinjet\n#### Small like a pin, fast like a jet! A lightweight Dependency Injection library for Python\n\n---\n\n## Installation\n\n```shell\npip install pinjet-core\n```\n---\n\n## Introdcution\n\nNumerous Dependency Injection (DI) frameworks exist for Python, yet none are flawless or intuitive, whether in terms of syntax or programmatically configuring. This led to the creation of Pinjet, a simple and intuitive DI library, that requires minimal or no configuration code at all. Simply annotate your classes and methods with **Pinjet decorators**, and it take cares of the rest. Pinjet follows **annotation-first** approach, drawing inspiration from Java **Spring** and **Spring Boot**, making project initialization as effortless as possible. This approach is particularly beneficial for developers experienced in Java and Spring Boot, easing their transition to **Pinjet** projects.\n\n*In Pinjet, the terms \"annotation\" and \"decorator\" are frequently interchanged and carry the same meaning.*\n\n#### Quick Exmaple\n```python\nfrom pinjet.core.resolver.dependency_resolver import DependencyResolver\nfrom pinjet.core.annotations.injectable import injectable\n\n@injectable\nclass InjectableClassToBeResolved:\n    pass\n\nresult = DependencyResolver.resolve(InjectableClassToBeResolved)\n\n```\n\nPinjet simplifies the usage by employing `@injectable` to mark any classes requiring injection. Unlike Spring Boot, where figuring out when to use `@Component` or `@Service` can be daunting, Pinjet offers a more straightforward approach.\n\n---\n\n## Customizing Dependency Scope\n\nBy default, any class marked with `@injectable` is considered a singleton, ensuring the same instance is returned every time `resolve()` is called. However, if you prefer a new instance on each call to `resolve()`, simply specify the dependency scope as **PROTOTYPE** in `@injectable`.\n\n#### Example\n```python\n\nfrom pinjet.core.annotations.injectable import injectable\nfrom pinjet.core.constants.dependency_scope import DependencyScope\nfrom pinjet.core.resolver.dependency_resolver import DependencyResolver\n\n\n@injectable(scope=DependencyScope.PROTOTYPE)\nclass PrototypeClassToBeResolved:\n    pass\n\nresolved_instance_1 = DependencyResolver.resolve(PrototypeClassToBeResolved)\nresolved_instance_2 = DependencyResolver.resolve(PrototypeClassToBeResolved)\n\nis_different_instance: bool = resolved_instance_1 is not resolved_instance_2 # True\n```\n\n---\n\n## Customization with Providers\n\nPinjet allows customization of class instantiation and resolution via `@provider` and `@provides`. For instance:\n\n```python\nfrom argparse import ArgumentParser\nfrom pinjet.core.annotations.provider import provider, provides\nfrom pinjet.core.resolver.dependency_resolver import DependencyResolver\n\n@provider\nclass ArgumentParserProvider:\n\n    @provides\n    def get_argument_parser(self) -> ArgumentParser:\n        argument_parser = ArgumentParser()\n        argument_parser.add_argument('--environment', type=str, required=False)\n        argument_parser.set_defaults(configuration='development')\n        return argument_parser\n\nargument_parser = DependencyResolver.resolve(ArgumentParser)\n```\n\nThis approach is also applicable when injecting classes from third-party libraries that cannot be modified to include `@injectable`.\n\n---\n\n## Scanning Ahead of Time\n\nFor any Python projects where codes are distributed across modules, Pinjet recommends wrapping the program's starting point, which is often, `__main__()` with `@pinjet_application`. This allows Pinjet to:\n\n- scan the repository to identify all dependencies with the help of `@pinjet_application`\n- ensuring `DependencyResolver` is primed to serve the application.\n\n#### Example\n\n```python\nfrom argparse import ArgumentParser\n\nfrom pinjet.core.annotations.bootstrap import pinjet_application\nfrom pinjet.core.resolver.dependency_resolver import DependencyResolver\n\n\n@pinjet_application\ndef __main__():\n\n    argument_parser: ArgumentParser = DependencyResolver.resolve(ArgumentParser)\n\n\nif __name__ == '__main__':\n    __main__()\n```\nHere ArgumentParser is configured to instantiate using `@provider` and `@provides` on a separate module which Pinjet is not aware of, if the program starting point is not marked with `@pinjet_application`\n\n---\n\n## Decorator Type Safety\n\nTo enhance developer experience, Pinjet introduces decorator type safety. For example, `@injectable` is exclusively meant for **classes**, while `@pinjet_application` is meant for **functions**. Introducing `@target`, a special decorator, which ensures decorators are applied to their intended elements.\n\n#### Quick Demonstration\n\n```python\nfrom functools import wraps\nfrom pinjet.core.annotations.target import target\nfrom pinjet.core.constants.element_type import ElementType\n\n@target(ElementType.FUNCTION)\ndef simple_function_decorator(function):\n\n    @wraps(function)\n    def decorator(*args, **kwargs):\n\n        result = function(*args, **kwargs)\n\n        return result\n\n    return decorator\n\n@simple_function_decorator\ndef sample_function_to_be_decorated():\n    print('Inside sample_method_to_be_decorated')\n\nsample_function_to_be_decorated() # prints: 'Inside sample_method_to_be_decorated'\n\n```\n\nWith `@target` we are now enforcing that the decorator `simple_function_decorator` can only be used on functions. Attempting to use a decorator on an incorrect element type will raise a `TargetElementTypeMisMatchException` with a comprehensive error message.\n\nYou can write your own custom decorator and enforce its usage with `@target` as well!\n\n---\n\n## Development Status\n\nPinjet is in its early stages and under active development. Numerous features are planned for future releases. Suggestions, improvements, and open-source contributions are most welcome. While the project may initially seem small like a pin, it is poised to grow as fast as a jet!\n\n---\n\n# Thank you\n",
    "bugtrack_url": null,
    "license": null,
    "summary": "Small like a pin, fast like a jet! A lightweight Dependency Injection library for python",
    "version": "0.0.1b1",
    "project_urls": null,
    "split_keywords": [
        "python",
        " dependency injection",
        " di framework",
        " ioc",
        " inversion of control"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "d36f07c91dda9eba1b5813ae8371abdfcc6b8363419f5aa72081cc2b27cc6b25",
                "md5": "9ac13e323f0d9e9c250070720ba99185",
                "sha256": "e823b8dabcb84ac36883dcd04e466ee479f1ce5f396b818f292da0adc53277ee"
            },
            "downloads": -1,
            "filename": "pinjet_core-0.0.1b1-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "9ac13e323f0d9e9c250070720ba99185",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": null,
            "size": 14423,
            "upload_time": "2024-04-13T13:09:04",
            "upload_time_iso_8601": "2024-04-13T13:09:04.084207Z",
            "url": "https://files.pythonhosted.org/packages/d3/6f/07c91dda9eba1b5813ae8371abdfcc6b8363419f5aa72081cc2b27cc6b25/pinjet_core-0.0.1b1-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "eee8baf81d478f2c515d31b3431952d6f8fffe29d876d06d1544046c8bcba024",
                "md5": "849927e614c35a60f2f6bd4c7586624f",
                "sha256": "76bb96e9e2ec873966bad978cb792a8c881e8e846b2794974368d15d8681563a"
            },
            "downloads": -1,
            "filename": "pinjet-core-0.0.1b1.tar.gz",
            "has_sig": false,
            "md5_digest": "849927e614c35a60f2f6bd4c7586624f",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": null,
            "size": 10965,
            "upload_time": "2024-04-13T13:09:06",
            "upload_time_iso_8601": "2024-04-13T13:09:06.517586Z",
            "url": "https://files.pythonhosted.org/packages/ee/e8/baf81d478f2c515d31b3431952d6f8fffe29d876d06d1544046c8bcba024/pinjet-core-0.0.1b1.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-04-13 13:09:06",
    "github": false,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "lcname": "pinjet-core"
}
        
Elapsed time: 0.40394s