Anbarryprojects / fastapi-babel

FastAPI babel support pybable tools like translation of text, formatting of dates, times and numbers, and time zones.
MIT License
46 stars 14 forks source link

LookupError: <ContextVar name='gettext' at 0x0000016824CC2B30> #40

Open levente-murgas opened 2 weeks ago

levente-murgas commented 2 weeks ago

Hi!

First of all, thank you for this amazing library! I'd like to reopen this issue because I have a similar problem and I wasn't able to solve it. I'm using Version: 0.0.9.

In my application I use the _() inside a worker function using ThreadPoolExecutor. The error I'm receiving is the same as this issue:

\fastapi_babel\core.py", line 123, in _
    gettext = _context_var.get()
LookupError: <ContextVar name='gettext' at 0x0000016824CC2B30>

Here's a simplified version of my issue, which still illustrates the problem

from fastapi_babel import Babel, BabelConfigs, BabelMiddleware
from fastapi_babel.core import _
from fastapi import FastAPI, Header
from typing_extensions import Annotated
from typing import Union, Callable

from concurrent.futures import ThreadPoolExecutor, as_completed

app = FastAPI()
babel_configs = BabelConfigs(
    ROOT_DIR=__file__,
    BABEL_DEFAULT_LOCALE="en",
    BABEL_TRANSLATION_DIRECTORY="lang",
)

app.add_middleware(
    BabelMiddleware, babel_configs=babel_configs
)

# Passes, no problemo
@app.get("/test0")
async def func_0(accept_language: Annotated[Union[str, None], Header()] = None):
    return {"text": _("Hello, World!")}

def getHW():
    return _("Hello, World!")

# Still passes, no problemo
@app.get("/test1")
async def func_1(accept_language: Annotated[Union[str, None], Header()] = None):
    return {"text": getHW()}

# LookupError: <ContextVar name='gettext' at 0x0000016824CC2B30> :(
@app.get("/test2")
async def func_2(accept_language: Annotated[Union[str, None], Header()] = None
    ):
    future_to_index = {}
    index_to_result = {}
    with ThreadPoolExecutor() as executor:
        future_to_index = {executor.submit(getHW): i for i in range(10)}
        for future in as_completed(future_to_index):
            index = future_to_index[future]
            res = future.result()
            index_to_result[index] = res
    return {"text": index_to_result}

Do you have any suggestions on how to resolve this issue @Legopapurida ? I read your comment mentioning lazy_gettext, but I was not able to apply it to my case...

Legopapurida commented 1 week ago

I have answered your problem here 36#