Type annotating for ndb.tasklets

Viewed 195

GvRs App Engine ndb Library as well as monocle and - to my understanding - modern Javascript use Generators to make async code look like blocking code.

Things are decorated with @ndb.tasklet. They yield when they want to give back execution to the runloop and when they have their result ready they raise StopIteration(value) (or the alias ndb.Return):

@ndb.tasklet
def get_google_async():
    context = ndb.get_context()
    result = yield context.urlfetch("http://www.google.com/")
    if result.status_code == 200:
        raise ndb.Return(result.content)
    raise RuntimeError

To use such a Function you get a ndb.Future object back and call the get get_result() Function on that to wait for the result and get it. E.g.:

def get_google():
    future = get_google_async()
    # do something else in real code here
    return future.get_result()

This all works very nice. but how to add type Annotations? The correct types are:

  • get_google_async() -> ndb.Future (via yield)
  • ndb.tasklet(get_google_async) -> ndb.Future
  • ndb.tasklet(get_google_async).get_result() -> str

So far, I came only up with casting the async function.

def get_google():
    # type: () -> str
    future = get_google_async()
    # do something else in real code here
    return cast('str', future.get_result())

Unfortunately this is not only about urlfetch but about hundreds of Methods- mainly of ndb.Model.

1 Answers

get_google_async itself is a generator function, so type hints can be () -> Generator[ndb.Future, None, None], I think.

As for get_google, if you don't want to cast, type checking may work.

like

def get_google():
    # type: () -> Optional[str]
    future = get_google_async()
    # do something else in real code here
    res = future.get_result()
    if isinstance(res, str):
        return res
    # somehow convert res to str, or
    return None
Related