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

[FEAT] python async support #378

Open
cmcconomyfwig opened this issue Jan 25, 2023 · 5 comments
Open

[FEAT] python async support #378

cmcconomyfwig opened this issue Jan 25, 2023 · 5 comments

Comments

@cmcconomyfwig
Copy link

What is the problem? Please describe.

I wish to be able to interact with sentinelhub via the python libraries asynchronously

Here's the solution

I've written up an async harness I have been using to work with the SentinelHub classes, maybe it can provide some inspiration.

from sentinelhub import SHConfig
from cache import AsyncTTL
import httpx
from urllib.parse import urlencode

@AsyncTTL(time_to_live=60*45)  # 45m in sec
async def get_sentinel_token(config: SHConfig) -> str:
    params = urlencode({
        'grant_type':'client_credentials',
        'client_id': config.sh_client_id,
        'client_secret': config.sh_client_secret,
    })
    url = f'{config.sh_auth_base_url}/oauth/token?{params}'
    headers = {
        "content-type": "application/x-www-form-urlencoded"
    }

    async with httpx.AsyncClient() as client:
    r = await client.post(url, headers=headers, timeout=10.0)
        r.raise_for_status()
        output = r.json()

    return output.get('access_token')

async def sentinel_request_async(request: SentinelHubRequest, config: SHConfig) -> Union[dict, bytes]:
    request.create_request()  # populate the download list.
    dl = request.download_list[0]
    headers = dl.headers

    async with httpx.AsyncClient() as client:
        access_token = await get_sentinel_token(config, client)
        headers['Authorization'] = f"Bearer {access_token}"
        r = await client.post(dl.url, headers=headers, json=dl.post_values, timeout=30.0)
        r.raise_for_status()

        if r.headers.get('content-type') == 'application/json':
            return r.json()
        elif r.headers.get('content-type') == 'image/tiff':
            return tiff.imread(BytesIO(r.read()))
        else:
            return r.read()  # bytes

The important thing is to ensure any I/O in the chain is performed in an async context, including things like token retrieval or any other network I/O.

Hope this helps.

@zigaLuksic
Copy link
Collaborator

Hi @cmcconomyfwig
thank you for the suggestion. Supporting async has been on our radar a couple of times in the past years. But since async is a rather all-or-nothing approach in Python, we never had the time to fully commit to it.
We hope to be able to include async support in a future version, but cannot promise anything at this point.

@cmcconomyfwig
Copy link
Author

Thanks for the reply, I understand that what I have above doesn't cover all the batch downloading capabilities you've built into the sync client, and it looks like quite the undertaking.

Whenever it is released, I look forward to transitioning to official APIs. In the meantime, I hope that others who are looking for any way to hook asynchronous calling into SentinelHub can make use of the snippet above.

@krishnaglodha
Copy link

krishnaglodha commented Jul 12, 2023

Hi @zigaLuksic , I have been working with HTTPX Async for few months now, I'd be happy to work on this task if needed

@zigaLuksic
Copy link
Collaborator

Hi @zigaLuksic , I have been working with HTTPX Async for few months now, I'd be happy to work on this task if needed

we very much appreciate the offer. but the current issue is that the structure of the sh-py is hard to adapt for such large changes. We do have a larger refactoring planned, and hopefully after that we would be able to start with async.

@krishnaglodha
Copy link

Hi @zigaLuksic , I have been working with HTTPX Async for few months now, I'd be happy to work on this task if needed

we very much appreciate the offer. but the current issue is that the structure of the sh-py is hard to adapt for such large changes. We do have a larger refactoring planned, and hopefully after that we would be able to start with async.

Thanks a lot for getting back, let me know if you need me on any other task, I'm available for contribution on GIS | Python | Documentation

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants