feat: use generator for stream results#926
Conversation
google/cloud/firestore_v1/query.py
Outdated
| yield QueryPartition(self, start_at, None) | ||
|
|
||
|
|
||
| class Iterator(page_iterator.Iterator): |
There was a problem hiding this comment.
Why turn this into a page_iterator? Previously, it just returned a standard python generator
There was a problem hiding this comment.
I was using datastore as a reference, but apparently as you noted below, I could just use a class to wrap this method.
google/cloud/firestore_v1/query.py
Outdated
| yield QueryPartition(self, start_at, None) | ||
|
|
||
|
|
||
| class Iterator(page_iterator.Iterator): |
There was a problem hiding this comment.
also: I know this is early, but I'd probably prefer to give the iterator a more descriptive name
There was a problem hiding this comment.
I tentatively changed the name to StreamIterator. Maybe we can find a better name, such as DocsIterator?
| def __aiter__(self): | ||
| return self._generator | ||
|
|
||
| def __anext__(self): |
There was a problem hiding this comment.
I think you shouldn't need to implement the next functions, only iter/aiter. But I could be wrong
If we do need anext as well, you can probably just do
def __anext__(self):
return self._generator.__anext__()
There was a problem hiding this comment.
Thanks, this looks much more succinct! I think we will need to keep the next methods, because it's one of the methods that generator has.
| try: | ||
| return next(self._generator) | ||
| except StopIteration: | ||
| return None |
There was a problem hiding this comment.
One thought: previously, we were returning generator objects. If you decide to implement next, maybe we should turn this into a full generator and implement send and throw too to be safe?
(I don't think these would be used by current users, but it would keep everything consistent)
There was a problem hiding this comment.
I feel like I had better implement these, because send and throw are quite useful in coroutines.
There was a problem hiding this comment.
If we were to go this route, should we rename the iterator to generator? Are we going too far on this 😂
There was a problem hiding this comment.
Yeah, I guess since the old type annotation was Generator, maybe we should make this into a full StreamGenerator class to be consistent (not that the type annotations can be relied on)
daniel-sanche
left a comment
There was a problem hiding this comment.
A couple small comments about imports and docstrings, but LGTM!
| Returns: | ||
| async_stream_iterator.AsyncStreamIterator: A generator of the query | ||
| results. | ||
| `AsyncStreamGenerator[DocumentSnapshot]`: |
There was a problem hiding this comment.
Do you need the ` quotes here? Do you know if devsite renders this well?
There was a problem hiding this comment.
Honestly I'm not super sure about this. I added the backticks because they are used in many other type annotations (for example). (A quick search shows the backtick makes sphinx create a link in the docs, but I'm not very clear about which documentation standard we are following.) Maybe we can clean this up along with other type annotations in a future PR. WDYT?
| retry: Optional[retries.AsyncRetry] = gapic_v1.method.DEFAULT, | ||
| timeout: Optional[float] = None, | ||
| ) -> async_stream_iterator.AsyncStreamIterator: | ||
| ) -> "AsyncStreamGenerator[DocumentSnapshot]": |
There was a problem hiding this comment.
Do you need quotes here? It looks like AsyncStreamGenerator is imported
There was a problem hiding this comment.
I added the quotes because [DocumentSnapshot] part would cause an error, because AsyncStreamGenerator isn't recognized as a generator in type hints. I wasn't able to find how to do it, so I resorted to using a string. I don't have a strong opinion on this. What do you think?
| ) | ||
|
|
||
| from google.cloud.firestore_v1 import async_stream_iterator, transaction | ||
| from google.cloud.firestore_v1.base_document import DocumentSnapshot |
There was a problem hiding this comment.
Is this just used for type annotations? If so, you can put it in an if TYPE_CHECKING block to avoid importing it in production
StreamGeneratorclass for all class methodsstream()to return, instead of using the Python built-in generator.AsyncStreamGeneratorfor the async clients