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

HH-199532 upgrade dependencies #661

Merged
merged 1 commit into from
Nov 24, 2023
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
14 changes: 8 additions & 6 deletions docs/dependency_injection.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Dependencies are great for running common actions before actual request processi
Here is what a dependencies may look like:

```python
from frontik.dependency_manager import dep
from frontik.dependency_manager import dependency


async def get_session_dependency(handler: PageHandler) -> Session:
Expand All @@ -21,7 +21,7 @@ class Page(PageHandler):
# Can be used on class level
dependencies = (another_dependency,)

async def get_page(self, session=dep(get_session_dependency)):
async def get_page(self, session=dependency(get_session_dependency)):
self.json.put({'result': session})
```

Expand All @@ -38,8 +38,9 @@ in class level will be taken, the rest from the graph depths will be discarded


There is an opportunity to specify priorities for dependencies:

```python
from frontik.dependency_manager import dep
from frontik.dependency_manager import dependency


async def get_session_dependency(handler: PageHandler) -> Session:
Expand All @@ -55,7 +56,7 @@ class Page(PageHandler):
another_dependency,
]

async def get_page(self, session=dep(get_session_dependency)):
async def get_page(self, session=dependency(get_session_dependency)):
self.json.put({'result': session})
```
If any of the _priority_dependency_names are present in the current graph,
Expand All @@ -64,8 +65,9 @@ In the given example `another_dependency` -> `get_session_dependency` -> `get_pa


*It is also possible to specify "async" dependencies:

```python
from frontik.dependency_manager import dep, async_deps
from frontik.dependency_manager import dependency, async_dependencies


async def get_session_dependency(handler: PageHandler) -> Session:
Expand All @@ -74,7 +76,7 @@ async def get_session_dependency(handler: PageHandler) -> Session:


class Page(PageHandler):
@async_deps([get_session_dependency])
@async_dependencies([get_session_dependency])
async def get_page(self):
self.json.put({'result': 'done'})
```
Expand Down
65 changes: 0 additions & 65 deletions docs/preprocessors.md

This file was deleted.

32 changes: 19 additions & 13 deletions frontik/dependency_manager/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,38 +2,40 @@

from typing import TYPE_CHECKING, Any

from frontik.dependency_manager.dependencies import DependencyMarker
from frontik.dependency_manager.dependencies import DependencyGroupMarker, DependencyMarker
from frontik.dependency_manager.graph_builder import build_sub_graph, get_dependency_graph
from frontik.dependency_manager.graph_runner import execute_graph
from frontik.preprocessors import DependencyGroupMarker, Preprocessor
from frontik.preprocessors import Preprocessor, make_full_name

if TYPE_CHECKING:
from collections.abc import Callable

from frontik.handler import PageHandler


def dep(dependency: Preprocessor | Callable | list[Callable]) -> Any:
def dependency(*deps: Preprocessor | Callable) -> Any:
"""
add dependency to page_method, it will be run before page_method and provide result

async def get_page(self, session=dep(get_session)):
...
"""
if isinstance(dependency, Preprocessor) and not isinstance(dependency.preprocessor_function, DependencyGroupMarker):
return DependencyMarker(dependency.preprocessor_function)
if len(deps) == 1:
dep = deps[0]

if isinstance(dependency, list):
return DependencyGroupMarker(dependency)
if isinstance(dep, Preprocessor):
return DependencyMarker(dep.preprocessor_function)

if callable(dependency):
return DependencyMarker(dependency)
if callable(dep):
return DependencyMarker(dep)

msg = 'Bad dependency type, only func or list[func]'
raise ValueError(msg)
raise ValueError('Bad dependency type, only func or list[func]')

else:
return DependencyGroupMarker(tuple(deps))

def async_deps(async_dependencies: list[Callable]) -> Callable:

def async_dependencies(async_deps: list[Callable]) -> Callable:
"""
add dependencies that will be run in parallel with page_method

Expand All @@ -43,7 +45,7 @@ async def get_page(self):
"""

def decorator(execute_page_method: Callable) -> Callable:
setattr(execute_page_method, '_async_deps', async_dependencies)
setattr(execute_page_method, '_async_deps', async_deps)
return execute_page_method

return decorator
Expand All @@ -59,3 +61,7 @@ async def execute_page_method_with_dependencies(handler: PageHandler, page_metho
setattr(handler, '_main_graph', main_graph)
await execute_graph(handler, main_graph)
return main_graph.root_dep.result


def make_dependencies_names_list(dependencies_list: list) -> list[str]:
return [make_full_name(d) for d in dependencies_list]
9 changes: 8 additions & 1 deletion frontik/dependency_manager/dependencies.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from frontik.preprocessors import make_full_name

if TYPE_CHECKING:
from collections.abc import Callable
from collections.abc import Callable, Iterable

from frontik.handler import PageHandler

Expand All @@ -17,6 +17,13 @@ def __init__(self, func: Callable) -> None:
self.func = func


class DependencyGroupMarker:
__name__ = 'dep_group'

def __init__(self, deps: Iterable[Callable]) -> None:
self.deps = deps


class Dependency:
def __init__(self, func: Callable) -> None:
self.func = func
Expand Down
21 changes: 13 additions & 8 deletions frontik/dependency_manager/graph_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,19 @@

import inspect
from copy import copy, deepcopy
from itertools import chain
from typing import TYPE_CHECKING, Any

from frontik.dependency_manager.dependencies import (
Dependency,
DependencyGraph,
DependencyGroupMarker,
DependencyMarker,
get_handler,
make_stub_dependency,
)
from frontik.preprocessors import (
DependencyGroupMarker,
Preprocessor,
get_all_preprocessors_functions,
get_simple_preprocessors_functions,
get_preprocessors,
make_full_name,
)

Expand Down Expand Up @@ -79,16 +77,15 @@ def get_dependency_graph(page_method_func: Callable, handler_cls: type) -> Depen
meta_graph = DependencyGraph(root_dep, handler_cls)

handler_dependencies = getattr(handler_cls, 'dependencies', [])
simple_preprocessors = chain(get_simple_preprocessors_functions(page_method_func), handler_dependencies)
all_preprocessors = chain(get_all_preprocessors_functions(page_method_func), handler_dependencies)
sid_dependencies = [*get_preprocessors(page_method_func), *handler_dependencies]

# collect dependencies which defined explicitly
_register_dependency_params(meta_graph, root_dep, add_to_args=False, deep_scan=False)
_register_side_dependencies(meta_graph, root_dep, simple_preprocessors, deep_scan=False)
_register_side_dependencies(meta_graph, root_dep, sid_dependencies, deep_scan=False)

# collect all dependencies with deep_scan
_register_dependency_params(meta_graph, root_dep, add_to_args=True, deep_scan=True)
_register_side_dependencies(meta_graph, root_dep, all_preprocessors, deep_scan=True)
_register_side_dependencies(meta_graph, root_dep, sid_dependencies, deep_scan=True)

async_dependencies = getattr(page_method_func, '_async_deps', [])
_register_async_dependencies(meta_graph, async_dependencies)
Expand Down Expand Up @@ -179,6 +176,14 @@ def _register_dependency_params(
if deep_scan:
_register_sub_dependency(graph, dependency, sub_dependency, add_to_args)

elif isinstance(param.default, DependencyGroupMarker):
if add_to_args:
dependency.args.append(None)
for sub_dependency_func in param.default.deps:
sub_dependency = _make_dependency_for_graph(graph, sub_dependency_func, deep_scan)
if deep_scan:
_register_sub_dependency(graph, dependency, sub_dependency, False)

elif issubclass(graph.handler_cls, param.annotation) or param_name == 'self':
sub_dependency = _make_dependency_for_graph(graph, get_handler, deep_scan)
graph.special_deps.add(sub_dependency)
Expand Down
35 changes: 3 additions & 32 deletions frontik/preprocessors.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,11 @@
from collections.abc import Callable, Generator
from collections.abc import Callable
from typing import Any


class DependencyGroupMarker:
__name__ = 'dep_group'

def __init__(self, deps: list[Callable]) -> None:
self.deps = deps


class Preprocessor:
"""Deprecated, use frontik.dependency_manager.Dependency"""

def __init__(self, preprocessor_function: Callable | DependencyGroupMarker) -> None:
def __init__(self, preprocessor_function: Callable) -> None:
self.preprocessor_function = preprocessor_function

@property
Expand All @@ -24,7 +17,7 @@ def __call__(self, page_func: Callable) -> Callable:
return page_func


def preprocessor(preprocessor_function: Callable | DependencyGroupMarker) -> Preprocessor:
def preprocessor(preprocessor_function: Callable) -> Preprocessor:
"""Deprecated, use frontik.dependency_manager.Dependency"""
return Preprocessor(preprocessor_function)

Expand All @@ -33,27 +26,5 @@ def get_preprocessors(func: Callable) -> list:
return getattr(func, '_preprocessors', [])


def get_simple_preprocessors_functions(func: Callable) -> Generator:
for preproc in getattr(func, '_preprocessors', []):
if not isinstance(preproc, DependencyGroupMarker):
yield preproc


def get_all_preprocessors_functions(func: Callable) -> Generator:
for preproc in getattr(func, '_preprocessors', []):
if isinstance(preproc, DependencyGroupMarker):
for func_or_preproc in preproc.deps:
if isinstance(func_or_preproc, Preprocessor):
yield func_or_preproc.preprocessor_function
else:
yield func_or_preproc
else:
yield preproc


def make_preprocessors_names_list(preprocessors_list: list) -> list[str]:
return [p.preprocessor_name if isinstance(p, Preprocessor) else make_full_name(p) for p in preprocessors_list]


def make_full_name(func: Callable | Any) -> str:
return f'{func.__module__}.{func.__name__}'
10 changes: 5 additions & 5 deletions frontik/testing.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,14 +114,14 @@ def _enable_consul(self):
options.consul_enabled = False

@pytest.fixture(scope='class', autouse=True)
async def inited_test_app(self, test_app, _enable_consul):
await test_app.init()
return test_app
async def inited_test_app(self, frontik_app, _enable_consul):
await frontik_app.init()
return frontik_app

@pytest.fixture(scope='class', autouse=True)
async def test_server_port(self, test_app):
async def test_server_port(self, frontik_app):
sock, port = bind_unused_port()
http_server = HTTPServer(test_app)
http_server = HTTPServer(frontik_app)
http_server.add_sockets([sock])

options.stderr_log = True
Expand Down
Loading