Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/HH-199532' into EXP-83809
Browse files Browse the repository at this point in the history
  • Loading branch information
HH ReleaseBot committed Nov 24, 2023
2 parents d9a272b + 9b87c19 commit 575d30c
Show file tree
Hide file tree
Showing 12 changed files with 397 additions and 462 deletions.
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

0 comments on commit 575d30c

Please sign in to comment.