Quart (Flask) пользовательский URLForResolver не работает должным образом - PullRequest
0 голосов
/ 21 января 2020

Кажется, у нас возникла "проблема" с Flask (и как таковой Quart), из-за которой мы не можем использовать url_for маршрутизацию к другим приложениям, даже если мы должны использовать диспетчеризацию приложений. Хотя это можно решить с помощью специального распознавателя URL-адресов, используемого в DispactherMiddleware. Это упомянуто в этой Flask проблеме github Я пытался использовать это, но я думаю, что это нужно изменить, чтобы быть asyn c, но я не знаю как. Все, что я пробую, терпит неудачу

Пока у меня есть этот класс URLForResolver, но он возвращает <coroutine object URLForResolver.__call__ at 0x7fbf7912fac0> вместо URL

class URLForResolver:
    """
    A URL resolver that provides resolution of `url_for` across multiple apps.
    """

    def __init__(
        self, 
        apps: List['Quart']) -> None:
        self.apps = apps
        self.cache = {}

        for app in apps:
            app.url_build_error_handlers.append(self)

    async def __call__(
        self, 
        error, 
        endpoint: str, 
        values: Dict) -> None:
        if endpoint in self.cache:
            print(f'[+] endpoint::: {endpoint} is in cache')
            app = self.cache[endpoint]
            if app:
                async with app.app_context():#, app.test_request_context():
                    print(f'[+] returning endpoint::: {url_for(endpoint, **values)}')
                    return url_for(endpoint, **values)
            else:
                raise error

        for app in self.apps:
            if app is current_app:
                continue

            for rule in app.url_map.iter_rules():
                print(f'[+] iterating rules::: {rule.endpoint}')
                if rule.endpoint == endpoint:
                    print(f'[+] rule.endpoint == endpoint::: {rule.endpoint} == {endpoint}')
                    self.cache[endpoint] = app
                    #return url_for(endpoint, **values)
                    return self(error, endpoint, values)

        self.cache[endpoint] = None
        raise error

Я использую класс Resolver следующим образом;

class DispatcherMiddleware:
    def __init__(
        self, 
        mounts: Dict[str, ASGIFramework]) -> None:
        self.mounts = mounts
        self.url_for_resolver = URLForResolver(list(self.mounts.values()))

    async def __call__(
        self, 
        scope: dict, 
        receive: Callable, 
        send: Callable) -> None:
        for path, app in self.mounts.items():
            if scope['type'] not in {'http', 'websocket'}:
                return await invoke_asgi(app, scope, receive, send)
            if scope['path'].startswith(path):
                scope['path'] = scope['path'][len(path) :] or '/'
                return await invoke_asgi(app, scope, receive, send)
        await send({
            'type': 'http.response.start', 
            'status': 404, 
            'headers': [(b'content-length', b'0')]
        })
        await send({'type': 'http.response.body'})
...