Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

technical reqs #18

Merged
merged 3 commits into from
Jan 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ Main ideas:
* **Simple API**. You need minimum of objects to start using library. You can easily integrate it with your task framework, examples provided.
* **Speed**. It is fast enough so you not to worry about. It is even faster than many of the analogs.

See more in [technical requirements](docs/technical_requirements.md)

### Quickstart

1. Create Provider subclass.
Expand Down Expand Up @@ -78,7 +80,7 @@ You can provide your own Scopes class if you are not satisfied with standard flo
**Provider** is a collection of functions which really provide some objects.
Provider itself is a class with some attributes and methods. Each of them is either result of `provide`, `alias` or `decorate`.

`@provide` can be used as a decorator for some method. This method will be called when corresponding dependency has to be created. Name of the moethod is not important: just check that it is different form other `Provider` attributes. Type hints do matter: they show what this method creates and what does it require. All method parameters are treated as other dependencies and created using container.
`@provide` can be used as a decorator for some method. This method will be called when corresponding dependency has to be created. Name of the method is not important: just check that it is different form other `Provider` attributes. Type hints do matter: they show what this method creates and what does it require. All method parameters are treated as other dependencies and created using container.

If `provide` is used with some class then that class itself is treated as a factory (`__init__` is analyzed for parameters). But do not forget to assing that call to some attribute otherwise it will be ignored.

Expand Down Expand Up @@ -148,7 +150,7 @@ async with make_async_container(MyProvider()) as container:
* Having some data connected with scope which you want to use when solving dependencies? Set it when entering scope. These classes can be used as parameters of your `provide` methods
```python
with make_container(MyProvider(), context={App: app}) as container:
with container({RequestClass: request_instance}) as request_container:
with container(context={RequestClass: request_instance}) as request_container:
pass
```

Expand Down
55 changes: 55 additions & 0 deletions docs/technical_requirements.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
## Technical requirements for IoC-container

#### 1. Scopes

1. Library should support various number of scopes
2. All dependencies are attached to scopes before any of them can be created
3. There should be default set of scopes
4. Scopes are ordered. Order is defined when declaring scopes.
5. Scope can be entered and exited.
6. Scope can be entered not earlier than enter into previous one.
7. Same scope can be entered multiple times concurrently.
8. If the same dependency is requested more than one time within the scope the same instance is returned. Cache is not shared between concurrent instances of same scope
9. Dependency can require other dependencies of the same or previous scope.

#### 2. Concurrency

1. Containers should be allowed to use with multithreading or asyncio. Not required to support both within same object.
2. Dependency creation using async functions should be supported if container is configured to run in asyncio
3. Concurrent entrance of scopes must not break requirement of single instance of dependency. Type of concurrency model can be configured when creating container
4. User of container may be allowed to switch synchronization on or off for performance tuning

#### 3. Clean dependencies

1. Usage of container must not require modification of objects we are creating
2. Container must not require to be global variable.
4. Container can require code changes on the borders of scopes (e.g. application start, middlewares, request handlers)

#### 4. Lifecycle

1. Dependencies which require some cleanup must be cleaned up on the scope exit
2. Dependencies which do not require cleanup should somehow be supported

#### 5. Context data

1. It should be allowed to pass some data when entering the scope
2. Context data must be accessible when creating dependencies

#### 6. Modularity

1. There can be multiple containers within same code base for different purposes
2. There must be a way to assemble a container from some reusable parts.
3. Assembling of container should be done in runtime in local scope

#### 7. Usability

1. There should be a way to create dependency based on its `__init__`
2. When creating a dependency there should be a way to decide which subtype is used and request only its dependencies
3. There should be a way to reuse same object for multiple requested types
4. There should be a way to decorate dependency just adding new providers

#### 8. Integration

1. Additional helpers should be provided for some popular frameworks. E.g: flask, fastapi, aiogram, celery, apscheduler
2. These helpers should be optional
3. Additional integrations should be done without changing library code
8 changes: 4 additions & 4 deletions requirements_dev.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
ruff
pytest
pytest-asyncio
pytest-repeat
ruff==0.1.*
pytest==7.*
pytest-asyncio==0.23.*
pytest-repeat==0.9.*
Loading