wip/experiments

This commit is contained in:
Jörn-Michael Miehe 2022-09-03 15:40:46 +00:00
parent 37b1a1ee68
commit 5034115281
3 changed files with 37 additions and 31 deletions

View file

@ -1,3 +1,4 @@
import asyncio
import functools import functools
from typing import Any from typing import Any
@ -13,11 +14,29 @@ _WEBDAV_CLIENT = WebDAVclient.Client({
}) })
def run_in_executor(f):
"""
Decorator to make blocking function call asyncio compatible
https://stackoverflow.com/questions/41063331/how-to-use-asyncio-with-existing-blocking-library/
"""
@functools.wraps(f)
def inner(*args, **kwargs):
loop = asyncio.get_running_loop()
return loop.run_in_executor(
None,
functools.partial(f, *args, **kwargs),
)
return inner
@functools.lru_cache @functools.lru_cache
def webdav_resource(remote_path: Any) -> WebDAVclient.Resource: def webdav_resource(remote_path: Any) -> WebDAVclient.Resource:
return _WEBDAV_CLIENT.resource(remote_path) return _WEBDAV_CLIENT.resource(remote_path)
@run_in_executor
def webdav_list(remote_path: str) -> list: def webdav_list(remote_path: str) -> list:
return _WEBDAV_CLIENT.list(remote_path) return _WEBDAV_CLIENT.list(remote_path)

View file

@ -1,5 +1,3 @@
import asyncio
import functools
import logging import logging
import time import time
from io import BytesIO from io import BytesIO
@ -8,28 +6,11 @@ from typing import Any, Optional
from async_lru import alru_cache from async_lru import alru_cache
from webdav3.client import Resource from webdav3.client import Resource
from . import webdav_resource from . import run_in_executor, webdav_resource
_logger = logging.getLogger(__name__) _logger = logging.getLogger(__name__)
def _run_in_executor(f):
"""
Decorator to make blocking function call asyncio compatible
https://stackoverflow.com/questions/41063331/how-to-use-asyncio-with-existing-blocking-library/
"""
@functools.wraps(f)
def inner(*args, **kwargs):
loop = asyncio.get_running_loop()
return loop.run_in_executor(
None,
functools.partial(f, *args, **kwargs),
)
return inner
def _get_ttl_hash(seconds: int = 20) -> int: def _get_ttl_hash(seconds: int = 20) -> int:
""" """
Return the same value within `seconds` time period Return the same value within `seconds` time period
@ -45,7 +26,7 @@ async def _get_buffer(
) -> BytesIO: ) -> BytesIO:
del ttl_hash del ttl_hash
@_run_in_executor @run_in_executor
def buffer_inner(resource: Resource) -> BytesIO: def buffer_inner(resource: Resource) -> BytesIO:
_logger.info(f"updating {resource}") _logger.info(f"updating {resource}")
print(f"updating {resource}") print(f"updating {resource}")

View file

@ -1,6 +1,6 @@
import re import re
from dataclasses import dataclass from dataclasses import dataclass
from typing import Iterator from typing import Iterator, Protocol
from fastapi import HTTPException, status from fastapi import HTTPException, status
from webdav3.exceptions import RemoteResourceNotFound from webdav3.exceptions import RemoteResourceNotFound
@ -9,14 +9,20 @@ from .. import webdav_list
from ..dav_file import DavFile from ..dav_file import DavFile
@dataclass(frozen=True)
class NameLister(Protocol):
def __call__(self) -> Iterator[str]:
...
@dataclass(frozen=True) @dataclass(frozen=True)
class FileNameLister: class FileNameLister:
remote_path: str remote_path: str
re: re.Pattern[str] re: re.Pattern[str]
def __call__(self) -> Iterator[str]: async def __call__(self) -> Iterator[str]:
try: try:
file_names = webdav_list(self.remote_path) file_names = await webdav_list(self.remote_path)
return ( return (
name name
@ -29,20 +35,20 @@ class FileNameLister:
@dataclass(frozen=True) @dataclass(frozen=True)
class FilePrefixFinder: class PrefixFinder:
lister: FileNameLister lister: NameLister
def __call__(self, prefix: str) -> Iterator[str]: async def __call__(self, prefix: str) -> Iterator[str]:
return ( return (
file_name file_name
for file_name in self.lister() for file_name in (await self.lister())
if file_name.lower().startswith(prefix.lower()) if file_name.lower().startswith(prefix.lower())
) )
@dataclass(frozen=True) @dataclass(frozen=True)
class FilePrefixLoader: class FilePrefixLoader:
finder: FilePrefixFinder finder: PrefixFinder
@property @property
def responses(self) -> dict: def responses(self) -> dict:
@ -62,8 +68,8 @@ class FilePrefixLoader:
}, },
} }
def __call__(self, prefix: str) -> DavFile: async def __call__(self, prefix: str) -> DavFile:
file_names = list(self.finder(prefix)) file_names = list(await self.finder(prefix))
if not (file_names): if not (file_names):
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND) raise HTTPException(status_code=status.HTTP_404_NOT_FOUND)