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

add imap_enumerated #160

Merged
merged 2 commits into from
Jun 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
name: release
on:
push:
tags:
- 'v*.*.*'

jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: setup python
uses: actions/setup-python@v2
with:
python-version: 3.9

- name: build
shell: bash
run: |
python -m pip install --upgrade wheel gevent
python setup.py sdist bdist_wheel --universal
- name: Release PyPI
shell: bash
env:
TWINE_USERNAME: ${{ secrets.TWINE_USERNAME }}
TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }}
run: |
pip install --upgrade twine
twine upload dist/*

- name: Release GitHub
uses: softprops/action-gh-release@v1
with:
files: "dist/*"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
20 changes: 20 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
on: [ push, pull_request ]

jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Setup Python
uses: actions/setup-python@v2
with:
python-version: 3.9

- name: Install dependencies
run: |
python -m pip install --upgrade pip
python -m pip install gevent requests pytest nose
- name: Test with pytest
run: |
pytest tests.py
27 changes: 0 additions & 27 deletions .travis.yml

This file was deleted.

16 changes: 16 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,22 @@ For some speed/performance gains, you may also want to use ``imap`` instead of `
print(resp)


There is also an enumerated version of ``imap`` which yields the index and response. However, unlike ``imap`` the ``requests`` parameter for ``imap_enumerated`` must be a sequence. Additionally,
failed requests and exception handler results that return None will also be yielded (whereas in ``imap`` they are ignored). Like in ``imap``, the order in which requests are sent and received should be
considered arbitrary.

.. code-block:: python

>>> rs = [grequests.get(f'https://httpbin.org/status/{code}') for code in range(200, 206)]
>>> for index, response in grequests.imap_enumerated(rs, size=5):
... print(index, response)
1 <Response [201]>
0 <Response [200]>
4 <Response [204]>
2 <Response [202]>
5 <Response [205]>
3 <Response [203]>


NOTE: because ``grequests`` leverages ``gevent`` (which in turn uses monkeypatching for enabling concurrency), you will often need to make sure ``grequests`` is imported before other libraries, especially ``requests``, to avoid problems. See `grequests gevent issues <https://github.com/spyoungtech/grequests/issues?q=is%3Aissue+label%3A%22%3Ahear_no_evil%3A%3Asee_no_evil%3A%3Aspeak_no_evil%3A++gevent%22+>`_ for additional information.

Expand Down
48 changes: 48 additions & 0 deletions grequests.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,3 +163,51 @@ def send(r):
yield ex_result

pool.join()


def imap_enumerated(requests, stream=False, size=2, exception_handler=None):
"""
Like imap, but yields tuple of original request index and response object

Unlike imap, failed results and responses from exception handlers that return None are not ignored. Instead, a
tuple of (index, None) is yielded. Additionally, the ``requests`` parameter must be a sequence of Request objects
(generators or other non-sequence iterables are not allowed)

The index is merely the original index of the original request in the requests list and does NOT provide any
indication of the order in which requests or responses are sent or received. Responses are still in arbitrary order.

::
>>> rs = [grequests.get(f'https://httpbin.org/status/{i}') for i in range(200, 206)]
>>> for index, response in grequests.imap_enumerated(rs, size=5):
... print(index, response)
1 <Response [201]>
0 <Response [200]>
4 <Response [204]>
2 <Response [202]>
5 <Response [205]>
3 <Response [203]>


:param requests: a sequence of Request objects.
:param stream: If True, the content will not be downloaded immediately.
:param size: Specifies the number of requests to make at a time. default is 2
:param exception_handler: Callback function, called when exception occurred. Params: Request, Exception
"""

pool = Pool(size)

def send(r):
return r._index, r.send(stream=stream)

requests = list(requests)
for index, req in enumerate(requests):
req._index = index

for index, request in pool.imap_unordered(send, requests):
if request.response is not None:
yield index, request.response
elif exception_handler:
ex_result = exception_handler(request, request.exception)
yield index, ex_result
else:
yield index, None
4 changes: 2 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@

setup(
name='grequests',
version='0.6.0',
url='https://github.com/kennethreitz/grequests',
version='0.7.0',
url='https://github.com/spyoungtech/grequests',
license='BSD',
author='Kenneth Reitz',
author_email='[email protected]',
Expand Down