Install & Compatibility
Where this runs
tested against v0.7.0 · pip install
no network on importno background threads
Install × environment matrix
Each cell = how many times install + import succeeded across repeated harness runs. Partial = flaky.
glibc = Debian/Ubuntu slim · musl = Alpine Linux
py 3.9
✕ build_error
✕ build_error
35MB installed
● package 35MB
Code
Verified usage
Verified import paths — ran on the pinned version, not inferred.
grequests
✓ import grequests
✗ import requests; import grequests
Due to gevent's monkey-patching, `grequests` (which imports `gevent`) should generally be imported before other networking libraries like `requests` to ensure proper asynchronous behavior.
grequests.map
✓ responses = grequests.map(requests_list)
Used to send a collection of Request objects concurrently and retrieve responses.
grequests.imap
✓ for response in grequests.imap(requests_list):
Returns a generator of responses, which can offer performance gains. Responses are not guaranteed to be in the order of the original requests.
grequests.imap_enumerated
✓ for index, response in grequests.imap_enumerated(requests_list):
Returns a generator yielding (index, response) tuples. Unlike `imap`, it yields `None` for failed requests. Introduced in v0.7.0.
This quickstart demonstrates how to use `grequests.map` and `grequests.imap_enumerated` to send multiple GET requests concurrently. It includes a custom exception handler and sets a timeout for individual requests. `grequests.map` returns a list of responses (or `None` for failed requests) in the order of the initial requests, while `grequests.imap_enumerated` yields (index, response) tuples as responses become available, not necessarily in the original request order.
import grequests
import time
urls = [
'http://httpbin.org/delay/1',
'http://httpbin.org/status/200',
'http://httpbin.org/delay/3',
'http://httpbin.org/status/500'
]
def exception_handler(request, exception):
print(f"Request to {request.url} failed: {exception}")
start_time = time.time()
# Create a list of unsent Request objects
reqs = (
grequests.get(u, timeout=2) for u in urls
)
# Send all requests concurrently using map
# Responses will be in the same order as requests, with None for failed ones
responses = grequests.map(reqs, exception_handler=exception_handler, size=5)
print(f"\n--- Responses (using map, took {time.time() - start_time:.2f}s) ---")
for response in responses:
if response:
print(f"URL: {response.url}, Status: {response.status_code}")
else:
print("Request failed or timed out.")
print("\n--- Responses (using imap_enumerated) ---")
# imap_enumerated yields (index, response) and includes Nones for failures
reqs_for_imap_enumerated = (
grequests.get(u, timeout=2) for u in urls
)
for index, response in grequests.imap_enumerated(reqs_for_imap_enumerated, exception_handler=exception_handler, size=5):
if response:
print(f"Index: {index}, URL: {response.url}, Status: {response.status_code}")
else:
print(f"Index: {index}, Request failed or timed out.")
Debug
Known issues
gotchaImport `grequests` (and thus `gevent`) before `requests` or other networking libraries that might conflict with `gevent`'s monkey-patching. Incorrect import order can lead to unexpected blocking behavior or errors.fixEnsure `import grequests` is placed at the very beginning of your script or module, before any other imports that perform I/O operations.
affects: All versions
gotchaWhen using `grequests.map()`, failed requests (e.g., due to timeouts or connection errors) will result in `None` being present in the returned list of responses. You must explicitly handle these `None` values.fixIterate through the results and check if each `response` object is `None` before attempting to access its attributes (e.g., `if response: print(response.status_code)`). Consider using an `exception_handler` with `grequests.map` for more granular error reporting.
affects: All versions
gotcha`grequests.imap()` returns a generator of responses, and the order in which responses are yielded is arbitrary; it does not correspond to the order of the input requests. This differs from `grequests.map()` which maintains order.fixIf response order is critical, use `grequests.map()`. If processing responses as they arrive is sufficient and order is not important, `grequests.imap()` can be more performant. If you need the original index with `imap`-like behavior, use `grequests.imap_enumerated` (v0.7.0+), but note its `None` handling.
affects: All versions
gotchaMaking a large number of concurrent requests without controlling the pool size (`size` parameter) can lead to 'Too many open files' errors, rate limiting by target servers, or servers closing connections prematurely.fixUse the `size` parameter in `grequests.map()` or `grequests.imap()` to limit the number of concurrent requests being made (e.g., `grequests.map(reqs, size=10)`). Adjust this value based on your system's capabilities and the target server's limitations.
affects: All versions
breakingThe behavior of `grequests.imap` changed in version 0.4.0. While not explicitly detailed as a breaking change in releases, 'behavior changes' suggest that code relying on previous `imap` functionality might need adjustments.fixReview code using `grequests.imap` and test its behavior against version 0.4.0 or later to ensure it functions as expected. Refer to GitHub issue #111 if possible for specifics.
affects: 0.4.0 and later
deprecatedThe underlying `gevent` library has deprecated and removed support for older Python versions (e.g., Python 2.7, 3.6, and soon 3.9). While `grequests` itself doesn't always specify Python requirements, its compatibility is bound by `gevent`'s support.fixUpgrade to Python 3.7+ and ensure your `gevent` installation is compatible with your Python version. Consult `gevent`'s documentation for its specific Python compatibility matrix.
affects: May affect users on older Python environments, especially with newer `grequests`/`gevent` versions.
Errors
Common errors & fixes
ModuleNotFoundError: No module named 'grequests'
The `grequests` library is not installed in the Python environment where the code is being run, or the incorrect Python interpreter is being used.
fixInstall the library using pip: `pip install grequests` or `python -m pip install grequests`. Ensure you are running your code with the Python interpreter where `grequests` was installed.
AttributeError: 'AsyncRequest' object has no attribute 'text'
This error occurs when attempting to access attributes like `.text`, `.status_code`, or `.json()` on the `AsyncRequest` object returned by `grequests.get()` or `grequests.post()` *before* the requests have actually been sent and processed by `grequests.map()` or `grequests.imap()`. The `AsyncRequest` object is a placeholder for a request that has not yet completed.
fixCall `grequests.map()` or `grequests.imap()` on the list of `AsyncRequest` objects to send them and get a list of actual `Response` objects. Then iterate over the results of `map`/`imap` to access response attributes.
```python
import grequests
urls = [
'http://httpbin.org/status/200',
'http://httpbin.org/status/201'
]
rs = (grequests.get(u) for u in urls)
responses = grequests.map(rs) # Send the requests and get Response objects
for response in responses:
if response:
print(response.status_code)
print(response.text)
else:
print("Request failed or returned None")
``` TypeError: object of type 'NoneType' has no len()
This typically happens when `grequests.map()` or `grequests.imap()` returns `None` for a request that failed (e.g., due to a timeout or connection error), and the code attempts to call `len()` or access attributes on that `None` object without prior checking.
fixAlways check if the `response` object is not `None` after `grequests.map()` or `grequests.imap()` returns the results, especially when iterating or accessing attributes.
```python
import grequests
urls = [
'http://httpbin.org/status/200',
'http://nonexistent-domain-xyz.com' # This might fail
]
rs = (grequests.get(u) for u in urls)
responses = grequests.map(rs, exception_handler=lambda request, exception: None) # Handle exceptions by returning None
for response in responses:
if response is not None: # Crucial check for NoneType
print(f"Status: {response.status_code}")
else:
print("Request failed.")
``` MonkeyPatchWarning: Monkey-patching ssl after ssl has already been imported may lead to errors
`grequests` relies on `gevent` for monkey patching standard library modules like `ssl` and `socket` to enable asynchronous operations. This warning occurs when `gevent.monkey.patch_all()` is called *after* another module that uses the unpatched `ssl` (or other) module has already been imported, leading to potential inconsistencies or errors like `RecursionError`.
fixEnsure that `gevent.monkey.patch_all()` is called as early as possible in your application's entry point, preferably before any other modules that might use blocking I/O (including `requests` if imported directly before `grequests`).
```python
from gevent import monkey
monkey.patch_all() # Should be at the very top of your script
import grequests
# ... rest of your code
```
gevent.hub.LoopExit: This operation would block forever
This error from `gevent` indicates that the event loop has no other 'greenlets' (lightweight threads) to switch to when a greenlet attempts a blocking operation (like waiting for I/O) that hasn't been properly monkey-patched. This often happens if `gevent.monkey.patch_all()` wasn't called or wasn't comprehensive enough, or if the program's logic leads to all active greenlets blocking indefinitely without another to take over.
fixEnsure `gevent.monkey.patch_all()` is called at the very beginning of your application. If specific modules are causing issues, you might need to explicitly patch them (e.g., `monkey.patch_all(ssl=True, socket=True, select=True)`). Also, verify that all I/O operations are indeed non-blocking or handled by `gevent`-compatible libraries, and avoid infinite blocking loops in your greenlets without yielding control. For `grequests.map`, increasing the `size` parameter (pool size) can sometimes help by providing more workers.
Upgrade
Version history
0.7.0latest on PyPI · released Jun 8, 2023
Audit
Dependencies
requestsrequiredCore HTTP client functionality that grequests extends.
geventrequiredProvides the coroutine-based concurrency model (greenlets) for asynchronous operations.