From 3b5b2eccad05475c029dec58ddcdf274afdb249e Mon Sep 17 00:00:00 2001 From: Piper Merriam Date: Tue, 10 Jan 2017 10:08:41 -0700 Subject: [PATCH] change from async to compat --- conftest.py | 17 +++++--- docs/quickstart.rst | 11 +++++ tests/admin-module/test_admin_setSolc.py | 2 +- .../test_admin_start_stop_methods.py | 2 +- tests/compat-utils/test_spawn.py | 38 ++++++++++++++++ .../test_thread_with_return_value.py} | 9 +++- .../test_timeout_object.py | 2 +- .../test_contract_on_event_filtering.py | 24 +++++------ .../test_contract_past_event_filtering.py | 14 +++--- .../test_filter_against_latest_blocks.py | 9 ++-- ...est_filter_against_pending_transactions.py | 9 ++-- .../test_filter_against_transaction_logs.py | 9 ++-- tests/mining-module/test_miner_setExtra.py | 9 ++-- tests/mining-module/test_miner_setGasPrice.py | 9 ++-- tests/mining-module/test_miner_start.py | 9 ++-- tests/mining-module/test_miner_stop.py | 8 ++-- tests/providers/conftest.py | 6 ++- tests/providers/test_testrpc_provider.py | 2 +- tests/shh-module/test_shh_filter.py | 2 +- tests/txpool-module/test_txpool_content.py | 9 ++-- tests/txpool-module/test_txpool_inspect.py | 9 ++-- tox.ini | 3 +- web3/providers/ipc.py | 14 +++--- web3/providers/manager.py | 6 ++- web3/providers/rpc.py | 6 ++- web3/providers/tester.py | 2 +- web3/utils/async/__init__.py | 21 --------- web3/utils/async/gevent_async.py | 24 ----------- web3/utils/async/http/__init__.py | 11 ----- web3/utils/compat/__init__.py | 43 +++++++++++++++++++ .../compat_gevent.py} | 28 ++++++++++++ .../compat_requests.py} | 0 .../compat_stdlib.py} | 8 +++- web3/utils/filters.py | 2 +- web3/utils/transactions.py | 9 ++-- 35 files changed, 238 insertions(+), 148 deletions(-) create mode 100644 tests/compat-utils/test_spawn.py rename tests/{stdlib-async-utils/test_spawn.py => compat-utils/test_thread_with_return_value.py} (56%) rename tests/{stdlib-async-utils => compat-utils}/test_timeout_object.py (96%) delete mode 100644 web3/utils/async/__init__.py delete mode 100644 web3/utils/async/gevent_async.py delete mode 100644 web3/utils/async/http/__init__.py rename web3/utils/{async/http/gevent_http.py => compat/compat_gevent.py} (70%) rename web3/utils/{async/http/requests_http.py => compat/compat_requests.py} (100%) rename web3/utils/{async/stdlib_async.py => compat/compat_stdlib.py} (94%) diff --git a/conftest.py b/conftest.py index 429782a..4bf1604 100644 --- a/conftest.py +++ b/conftest.py @@ -4,7 +4,10 @@ from web3.providers.tester import ( EthereumTesterProvider, TestRPCProvider, ) -from web3.utils import async +from web3.utils.compat import ( + Timeout, + sleep, +) from web3.main import Web3 @@ -48,9 +51,9 @@ def skip_if_testrpc(): def wait_for_miner_start(): def _wait_for_miner_start(web3, timeout=60): poll_delay_counter = PollDelayCounter() - with async.Timeout(timeout) as timeout: + with Timeout(timeout) as timeout: while not web3.eth.mining or not web3.eth.hashrate: - async.sleep(poll_delay_counter()) + sleep(poll_delay_counter()) timeout.check() return _wait_for_miner_start @@ -59,13 +62,13 @@ def wait_for_miner_start(): def wait_for_block(): def _wait_for_block(web3, block_number=1, timeout=60 * 10): poll_delay_counter = PollDelayCounter() - with async.Timeout(timeout) as timeout: + with Timeout(timeout) as timeout: while True: if web3.eth.blockNumber >= block_number: break if isinstance(web3.currentProvider, (TestRPCProvider, EthereumTesterProvider)): web3._requestManager.request_blocking("evm_mine", []) - async.async.sleep(poll_delay_counter()) + sleep(poll_delay_counter()) timeout.check() return _wait_for_block @@ -74,12 +77,12 @@ def wait_for_block(): def wait_for_transaction(): def _wait_for_transaction(web3, txn_hash, timeout=120): poll_delay_counter = PollDelayCounter() - with async.Timeout(timeout) as timeout: + with Timeout(timeout) as timeout: while True: txn_receipt = web3.eth.getTransactionReceipt(txn_hash) if txn_receipt is not None: break - async.sleep(poll_delay_counter()) + sleep(poll_delay_counter()) timeout.check() return txn_receipt diff --git a/docs/quickstart.rst b/docs/quickstart.rst index b789159..d0680ba 100644 --- a/docs/quickstart.rst +++ b/docs/quickstart.rst @@ -20,6 +20,17 @@ Or to install with support for the ``TestRPCProvider`` and $ pip install web3[tester] + +Or to install with support for gevent based threading: + +.. code-block:: shell + + $ pip install web3[gevent] + + +To enable gevent based threading set the environment variable ``THREADING_BACKEND=gevent`` + + Installation from source can be done from the root of the project with the following command. diff --git a/tests/admin-module/test_admin_setSolc.py b/tests/admin-module/test_admin_setSolc.py index 7da080f..0a28087 100644 --- a/tests/admin-module/test_admin_setSolc.py +++ b/tests/admin-module/test_admin_setSolc.py @@ -1,6 +1,6 @@ import pytest -from web3.utils.async import subprocess +from web3.utils.compat import subprocess from web3.utils.string import force_text diff --git a/tests/admin-module/test_admin_start_stop_methods.py b/tests/admin-module/test_admin_start_stop_methods.py index 6c8b26b..baa07b5 100644 --- a/tests/admin-module/test_admin_start_stop_methods.py +++ b/tests/admin-module/test_admin_start_stop_methods.py @@ -2,7 +2,7 @@ import pytest from flaky import flaky -from web3.utils.async import socket +from web3.utils.compat import socket def get_open_port(): diff --git a/tests/compat-utils/test_spawn.py b/tests/compat-utils/test_spawn.py new file mode 100644 index 0000000..62bcc8a --- /dev/null +++ b/tests/compat-utils/test_spawn.py @@ -0,0 +1,38 @@ +from web3.utils.compat.compat_stdlib import ( + spawn, + ThreadWithReturn, +) + + +class CustomThreadClass(ThreadWithReturn): + pass + + +def test_spawning_simple_thread(): + container = { + 'success': None, + } + + def target_fn(): + container['success'] = True + + thread = spawn(target_fn) + thread.join() + + assert container['success'] is True + + +def test_spawning_specific_thread_class(): + container = { + 'success': None, + } + + def target_fn(): + container['success'] = True + + thread = spawn(target_fn, thread_class=CustomThreadClass) + thread.join() + + assert isinstance(thread, CustomThreadClass) + + assert container['success'] is True diff --git a/tests/stdlib-async-utils/test_spawn.py b/tests/compat-utils/test_thread_with_return_value.py similarity index 56% rename from tests/stdlib-async-utils/test_spawn.py rename to tests/compat-utils/test_thread_with_return_value.py index 3ace658..31a0a5d 100644 --- a/tests/stdlib-async-utils/test_spawn.py +++ b/tests/compat-utils/test_thread_with_return_value.py @@ -1,15 +1,20 @@ -from web3.utils.async.stdlib_async import spawn +from web3.utils.compat.compat_stdlib import ( + spawn, +) -def test_spawning_simple_thread(): +def test_thread_with_return_value(): container = { 'success': None, } def target_fn(): container['success'] = True + return 12345 thread = spawn(target_fn) thread.join() assert container['success'] is True + + assert thread.get() == 12345 diff --git a/tests/stdlib-async-utils/test_timeout_object.py b/tests/compat-utils/test_timeout_object.py similarity index 96% rename from tests/stdlib-async-utils/test_timeout_object.py rename to tests/compat-utils/test_timeout_object.py index e736a87..e9a151a 100644 --- a/tests/stdlib-async-utils/test_timeout_object.py +++ b/tests/compat-utils/test_timeout_object.py @@ -2,7 +2,7 @@ import pytest import time -from web3.utils.async.stdlib_async import ( +from web3.utils.compat.compat_stdlib import ( Timeout, ) diff --git a/tests/filtering/test_contract_on_event_filtering.py b/tests/filtering/test_contract_on_event_filtering.py index e7298a7..94f455e 100644 --- a/tests/filtering/test_contract_on_event_filtering.py +++ b/tests/filtering/test_contract_on_event_filtering.py @@ -1,7 +1,9 @@ import pytest from flaky import flaky -from web3.utils import async +from web3.utils.compat import ( + Timeout, +) @flaky(max_runs=3) @@ -22,10 +24,9 @@ def test_on_filter_using_get_interface(web3, txn_hash = emitter.transact().logNoArgs(emitter_event_ids.LogNoArguments) txn_receipt = wait_for_transaction(web3, txn_hash) - with async.Timeout(30) as timeout: + with Timeout(30) as timeout: while not filter.get(False): - async.sleep(sleep_interval()) - timeout.check() + timeout.sleep(sleep_interval()) log_entries = filter.get() @@ -53,10 +54,9 @@ def test_on_filter_with_only_event_name(web3, txn_hash = emitter.transact().logNoArgs(emitter_event_ids.LogNoArguments) txn_receipt = wait_for_transaction(web3, txn_hash) - with async.Timeout(30) as timeout: + with Timeout(30) as timeout: while not seen_logs: - async.sleep(sleep_interval()) - timeout.check() + timeout.sleep(sleep_interval()) filter.stop_watching(30) @@ -98,10 +98,9 @@ def test_on_filter_with_event_name_and_single_argument(web3, for txn_hash in txn_hashes: wait_for_transaction(web3, txn_hash) - with async.Timeout(30) as timeout: + with Timeout(30) as timeout: while len(seen_logs) < 2: - async.sleep(sleep_interval()) - timeout.check() + timeout.sleep(sleep_interval()) filter.stop_watching(30) @@ -143,10 +142,9 @@ def test_on_filter_with_event_name_and_non_indexed_argument(web3, for txn_hash in txn_hashes: wait_for_transaction(web3, txn_hash) - with async.Timeout(30) as timeout: + with Timeout(30) as timeout: while not seen_logs: - async.sleep(sleep_interval()) - timeout.check() + timeout.sleep(sleep_interval()) filter.stop_watching(30) diff --git a/tests/filtering/test_contract_past_event_filtering.py b/tests/filtering/test_contract_past_event_filtering.py index 7839ba6..eed63a4 100644 --- a/tests/filtering/test_contract_past_event_filtering.py +++ b/tests/filtering/test_contract_past_event_filtering.py @@ -2,7 +2,9 @@ import pytest import random from flaky import flaky -from web3.utils import async +from web3.utils.compat import ( + Timeout, +) @flaky(max_runs=3) @@ -26,10 +28,9 @@ def test_past_events_filter_with_callback(web3, else: filter = Emitter.pastEvents('LogNoArguments', {}, seen_logs.append) - with async.Timeout(30) as timeout: + with Timeout(30) as timeout: while not seen_logs: - async.sleep(sleep_interval()) - timeout.check() + timeout.sleep(sleep_interval()) filter.stop_watching(30) @@ -62,10 +63,9 @@ def test_past_events_filter_using_get_api(web3, else: filter = Emitter.pastEvents('LogNoArguments') - with async.Timeout(30) as timeout: + with Timeout(30) as timeout: while not filter.get(False): - async.sleep(sleep_interval()) - timeout.check() + timeout.sleep(sleep_interval()) log_entries = filter.get(False) diff --git a/tests/filtering/test_filter_against_latest_blocks.py b/tests/filtering/test_filter_against_latest_blocks.py index efaa988..bf029d9 100644 --- a/tests/filtering/test_filter_against_latest_blocks.py +++ b/tests/filtering/test_filter_against_latest_blocks.py @@ -1,7 +1,9 @@ import random from flaky import flaky -from web3.utils import async +from web3.utils.compat import ( + Timeout, +) @flaky(max_runs=3) @@ -16,10 +18,9 @@ def test_filter_against_latest_blocks(web3, sleep_interval, wait_for_block, skip wait_for_block(web3, current_block + 3) - with async.Timeout(5) as timeout: + with Timeout(5) as timeout: while len(seen_blocks) < 2: - async.sleep(sleep_interval()) - timeout.check() + timeout.sleep(sleep_interval()) txn_filter.stop_watching(3) diff --git a/tests/filtering/test_filter_against_pending_transactions.py b/tests/filtering/test_filter_against_pending_transactions.py index 66f9276..5b265ea 100644 --- a/tests/filtering/test_filter_against_pending_transactions.py +++ b/tests/filtering/test_filter_against_pending_transactions.py @@ -1,7 +1,9 @@ import random from flaky import flaky -from web3.utils import async +from web3.utils.compat import ( + Timeout, +) @flaky(max_runs=3) @@ -29,10 +31,9 @@ def test_filter_against_pending_transactions(web3_empty, wait_for_transaction(web3, txn_1_hash) wait_for_transaction(web3, txn_2_hash) - with async.Timeout(5) as timeout: + with Timeout(5) as timeout: while not seen_txns: - async.sleep(random.random()) - timeout.check() + timeout.sleep(random.random()) txn_filter.stop_watching(30) diff --git a/tests/filtering/test_filter_against_transaction_logs.py b/tests/filtering/test_filter_against_transaction_logs.py index 5ce3966..6bad180 100644 --- a/tests/filtering/test_filter_against_transaction_logs.py +++ b/tests/filtering/test_filter_against_transaction_logs.py @@ -1,7 +1,9 @@ import random from flaky import flaky -from web3.utils import async +from web3.utils.compat import ( + Timeout, +) @flaky(max_runs=3) @@ -23,10 +25,9 @@ def test_filter_against_log_events(web3_empty, for txn_hash in txn_hashes: wait_for_transaction(web3, txn_hash) - with async.Timeout(5) as timeout: + with Timeout(5) as timeout: while not seen_logs: - async.sleep(random.random()) - timeout.check() + timeout.sleep(random.random()) txn_filter.stop_watching(30) diff --git a/tests/mining-module/test_miner_setExtra.py b/tests/mining-module/test_miner_setExtra.py index 5a25679..bc8f245 100644 --- a/tests/mining-module/test_miner_setExtra.py +++ b/tests/mining-module/test_miner_setExtra.py @@ -3,7 +3,9 @@ import random from flaky import flaky from web3.utils.encoding import decode_hex -from web3.utils import async +from web3.utils.compat import ( + Timeout, +) @flaky(max_runs=3) @@ -19,13 +21,12 @@ def test_miner_setExtra(web3_empty, wait_for_block): web3.miner.setExtra(new_extra_data) - with async.Timeout(60) as timeout: + with Timeout(60) as timeout: while True: extra_data = decode_hex(web3.eth.getBlock(web3.eth.blockNumber)['extraData']) if extra_data == new_extra_data: break - async.sleep(random.random()) - timeout.check() + timeout.sleep(random.random()) after_extra = decode_hex(web3.eth.getBlock(web3.eth.blockNumber)['extraData']) diff --git a/tests/mining-module/test_miner_setGasPrice.py b/tests/mining-module/test_miner_setGasPrice.py index 8346d44..e306860 100644 --- a/tests/mining-module/test_miner_setGasPrice.py +++ b/tests/mining-module/test_miner_setGasPrice.py @@ -2,7 +2,9 @@ import random from flaky import flaky -from web3.utils import async +from web3.utils.compat import ( + Timeout, +) @flaky(max_runs=3) @@ -16,10 +18,9 @@ def test_miner_setGasPrice(web3_empty, wait_for_block): web3.miner.setGasPrice(initial_gas_price // 2) - with async.Timeout(60) as timeout: + with Timeout(60) as timeout: while web3.eth.gasPrice == initial_gas_price: - async.sleep(random.random()) - timeout.check() + timeout.sleep(random.random()) after_gas_price = web3.eth.gasPrice assert after_gas_price < initial_gas_price diff --git a/tests/mining-module/test_miner_start.py b/tests/mining-module/test_miner_start.py index 38cb279..9ee7072 100644 --- a/tests/mining-module/test_miner_start.py +++ b/tests/mining-module/test_miner_start.py @@ -2,7 +2,9 @@ import random from flaky import flaky -from web3.utils import async +from web3.utils.compat import ( + Timeout, +) @flaky(max_runs=3) @@ -15,10 +17,9 @@ def test_miner_start(web3_empty, wait_for_miner_start): web3.miner.stop() - with async.Timeout(60) as timeout: + with Timeout(60) as timeout: while web3.eth.mining or web3.eth.hashrate: - async.sleep(random.random()) - timeout.check() + timeout.sleep(random.random()) assert not web3.eth.mining assert not web3.miner.hashrate diff --git a/tests/mining-module/test_miner_stop.py b/tests/mining-module/test_miner_stop.py index 3847c6f..0654824 100644 --- a/tests/mining-module/test_miner_stop.py +++ b/tests/mining-module/test_miner_stop.py @@ -2,7 +2,9 @@ import random from flaky import flaky -from web3.utils import async +from web3.utils.compat import ( + Timeout, +) @flaky(max_runs=3) @@ -14,9 +16,9 @@ def test_miner_stop(web3_empty): web3.miner.stop() - with async.Timeout(60) as timeout: + with Timeout(60) as timeout: while web3.eth.mining or web3.eth.hashrate: - async.sleep(random.random()) + timeout.sleep(random.random()) timeout.check() assert not web3.eth.mining diff --git a/tests/providers/conftest.py b/tests/providers/conftest.py index 536fe00..32c960a 100644 --- a/tests/providers/conftest.py +++ b/tests/providers/conftest.py @@ -9,11 +9,13 @@ from web3.providers.rpc import ( from web3.providers.tester import ( TestRPCProvider, ) -from web3.utils import async +from web3.utils.compat import ( + socket, +) def get_open_port(): - s = async.socket.socket(socket.AF_INET, socket.SOCK_STREAM) + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.bind(("", 0)) s.listen(1) port = s.getsockname()[1] diff --git a/tests/providers/test_testrpc_provider.py b/tests/providers/test_testrpc_provider.py index 8efec76..a8569e1 100644 --- a/tests/providers/test_testrpc_provider.py +++ b/tests/providers/test_testrpc_provider.py @@ -5,7 +5,7 @@ from web3.providers.tester import ( TestRPCProvider, is_testrpc_available, ) -from web3.utils.async import socket +from web3.utils.compat import socket def get_open_port(): diff --git a/tests/shh-module/test_shh_filter.py b/tests/shh-module/test_shh_filter.py index 75dd8ab..58e40b3 100644 --- a/tests/shh-module/test_shh_filter.py +++ b/tests/shh-module/test_shh_filter.py @@ -1,4 +1,4 @@ -from web3.utils.async import sleep +from web3.utils.compat import sleep def test_shh_filter(web3, skip_if_testrpc): diff --git a/tests/txpool-module/test_txpool_content.py b/tests/txpool-module/test_txpool_content.py index 7daa887..1b9b9b7 100644 --- a/tests/txpool-module/test_txpool_content.py +++ b/tests/txpool-module/test_txpool_content.py @@ -1,6 +1,8 @@ import random -from web3.utils import async +from web3.utils.compat import ( + Timeout, +) def test_txpool_content(web3_empty): @@ -8,10 +10,9 @@ def test_txpool_content(web3_empty): web3.miner.stop() - with async.Timeout(60) as timeout: + with Timeout(60) as timeout: while web3.miner.hashrate or web3.eth.mining: - async.sleep(random.random()) - timeout.check() + timeout.sleep(random.random()) txn_1_hash = web3.eth.sendTransaction({ 'from': web3.eth.coinbase, diff --git a/tests/txpool-module/test_txpool_inspect.py b/tests/txpool-module/test_txpool_inspect.py index 1475b95..3a883c3 100644 --- a/tests/txpool-module/test_txpool_inspect.py +++ b/tests/txpool-module/test_txpool_inspect.py @@ -1,6 +1,8 @@ import random -from web3.utils import async +from web3.utils.compat import ( + Timeout, +) def test_txpool_inspect(web3_empty): @@ -8,10 +10,9 @@ def test_txpool_inspect(web3_empty): web3.miner.stop() - with async.Timeout(60) as timeout: + with Timeout(60) as timeout: while web3.miner.hashrate or web3.eth.mining: - async.sleep(random.random()) - timeout.check() + timeout.sleep(random.random()) txn_1_hash = web3.eth.sendTransaction({ 'from': web3.eth.coinbase, diff --git a/tox.ini b/tox.ini index 3c01223..e8b494e 100644 --- a/tox.ini +++ b/tox.ini @@ -30,8 +30,7 @@ deps = stdlib: -r{toxinidir}/requirements-dev.txt gevent: -r{toxinidir}/requirements-gevent.txt setenv = - gevent: WEB3_ASYNC_GEVENT=True - TESTRPC_ASYNC_GEVENT=True + gevent: THREADING_BACKEND=gevent basepython = py27: python2.7 py34: python3.4 diff --git a/web3/providers/ipc.py b/web3/providers/ipc.py index 139889d..cccb797 100644 --- a/web3/providers/ipc.py +++ b/web3/providers/ipc.py @@ -10,8 +10,8 @@ try: except ImportError: JSONDecodeError = ValueError -from web3.utils import async -from web3.utils.async import ( +from web3.utils.compat import ( + Timeout, threading, socket, ) @@ -86,24 +86,24 @@ class IPCProvider(JSONBaseProvider): try: with get_ipc_socket(self.ipc_path) as sock: sock.sendall(request) + # TODO: use a BytesIO object here response_raw = b"" - with async.Timeout(10) as timeout: + with Timeout(10) as timeout: while True: - timeout.check() try: response_raw += sock.recv(4096) except socket.timeout: - async.sleep(0) + timeout.sleep(0) continue if response_raw == b"": - async.sleep(0) + timeout.sleep(0) else: try: json.loads(force_text(response_raw)) except JSONDecodeError: - async.sleep(0) + timeout.sleep(0) continue else: break diff --git a/web3/providers/manager.py b/web3/providers/manager.py index 769a051..21a5f96 100644 --- a/web3/providers/manager.py +++ b/web3/providers/manager.py @@ -22,7 +22,9 @@ from web3.utils.transactions import ( serialize_transaction, add_signature_to_transaction, ) -from web3.utils import async +from web3.utils.compat import ( + spawn, +) class RequestManager(object): @@ -51,7 +53,7 @@ class RequestManager(object): def request_async(self, method, params): request_id = uuid.uuid4() - self.pending_requests[request_id] = async.spawn( + self.pending_requests[request_id] = spawn( self.request_blocking, method, params, diff --git a/web3/providers/rpc.py b/web3/providers/rpc.py index 0b925d8..e0a3187 100644 --- a/web3/providers/rpc.py +++ b/web3/providers/rpc.py @@ -2,10 +2,12 @@ import logging from .base import JSONBaseProvider # noqa: E402 -from web3.utils.compat import urlunparse +from web3.utils.compat import ( + urlunparse, + make_post_request, +) from web3.utils.http import construct_user_agent from web3.utils.functional import cast_return_to_dict -from web3.utils.async.http import make_post_request logger = logging.getLogger(__name__) diff --git a/web3/providers/tester.py b/web3/providers/tester.py index 4837165..bc881b6 100644 --- a/web3/providers/tester.py +++ b/web3/providers/tester.py @@ -1,6 +1,6 @@ import logging -from web3.utils.async import ( +from web3.utils.compat import ( make_server, spawn, ) diff --git a/web3/utils/async/__init__.py b/web3/utils/async/__init__.py deleted file mode 100644 index 217fd09..0000000 --- a/web3/utils/async/__init__.py +++ /dev/null @@ -1,21 +0,0 @@ -import os - - -if 'WEB3_ASYNC_GEVENT' in os.environ: - from .gevent_async import ( # noqa - Timeout, - sleep, - socket, - threading, - make_server, - GreenletThread, - ) -else: - from .stdlib_async import ( # noqa - Timeout, - sleep, - socket, - threading, - make_server, - GreenletThread, - ) diff --git a/web3/utils/async/gevent_async.py b/web3/utils/async/gevent_async.py deleted file mode 100644 index 3a5023d..0000000 --- a/web3/utils/async/gevent_async.py +++ /dev/null @@ -1,24 +0,0 @@ -import gevent -from gevent.pywsgi import ( # noqa: F401 - WSGIServer, -) -from gevent import ( # noqa: F401 - subprocess, - socket, - threading, -) - - -sleep = gevent.sleep -spawn = gevent.spawn -GreenletThread = gevent.Greenlet - - -class Timeout(gevent.Timeout): - def check(self): - pass - - -def make_server(host, port, application, *args, **kwargs): - server = WSGIServer((host, port), application, *args, **kwargs) - return server diff --git a/web3/utils/async/http/__init__.py b/web3/utils/async/http/__init__.py deleted file mode 100644 index 49107ba..0000000 --- a/web3/utils/async/http/__init__.py +++ /dev/null @@ -1,11 +0,0 @@ -import os - - -if 'WEB3_ASYNC_GEVENT' in os.environ: - from .gevent_http import ( # noqa: F401 - make_post_request, - ) -else: - from .requests_http import ( # noqa: F401 - make_post_request, - ) diff --git a/web3/utils/compat/__init__.py b/web3/utils/compat/__init__.py index 76cc6ef..2ae6664 100644 --- a/web3/utils/compat/__init__.py +++ b/web3/utils/compat/__init__.py @@ -1,4 +1,5 @@ import sys +import os if sys.version_info.major == 2: @@ -11,3 +12,45 @@ else: urlparse, urlunparse, ) + + +def get_threading_backend(): + if 'WEB3_THREADING_BACKEND' in os.environ: + return os.environ['WEB3_THREADING_BACKEND'] + elif 'THREADING_BACKEND' in os.environ: + return os.environ['THREADING_BACKEND'] + else: + return 'stdlib' + + +THREADING_BACKEND = get_threading_backend() + + +if THREADING_BACKEND == 'stdlib': + from .compat_stdlib import ( + Timeout, + sleep, + socket, + threading, + make_server, + GreenletThread, + spawn, + subprocess, + ) + from .compat_requests import ( + make_post_request, + ) +elif THREADING_BACKEND == 'gevent': + from .compat_gevent import ( # noqa: F401 + Timeout, + sleep, + socket, + threading, + make_server, + GreenletThread, + spawn, + subprocess, + make_post_request, + ) +else: + raise ValueError("Unsupported threading backend. Must be one of 'gevent' or 'stdlib'") diff --git a/web3/utils/async/http/gevent_http.py b/web3/utils/compat/compat_gevent.py similarity index 70% rename from web3/utils/async/http/gevent_http.py rename to web3/utils/compat/compat_gevent.py index 6ed1b9b..56bab10 100644 --- a/web3/utils/async/http/gevent_http.py +++ b/web3/utils/compat/compat_gevent.py @@ -1,5 +1,15 @@ import collections +import gevent +from gevent.pywsgi import ( # noqa: F401 + WSGIServer, +) +from gevent import ( # noqa: F401 + subprocess, + socket, + threading, +) + import pylru from geventhttpclient import HTTPClient @@ -10,6 +20,24 @@ from web3.utils.compat import urlparse _client_cache = pylru.lrucache(8) +sleep = gevent.sleep +spawn = gevent.spawn +GreenletThread = gevent.Greenlet + + +class Timeout(gevent.Timeout): + def check(self): + pass + + def sleep(self, seconds): + gevent.sleep(seconds) + + +def make_server(host, port, application, *args, **kwargs): + server = WSGIServer((host, port), application, *args, **kwargs) + return server + + def _get_client(host, port, **kwargs): ordered_kwargs = collections.OrderedDict(sorted(kwargs.items())) cache_key = '{0}:{1}:{2}'.format( diff --git a/web3/utils/async/http/requests_http.py b/web3/utils/compat/compat_requests.py similarity index 100% rename from web3/utils/async/http/requests_http.py rename to web3/utils/compat/compat_requests.py diff --git a/web3/utils/async/stdlib_async.py b/web3/utils/compat/compat_stdlib.py similarity index 94% rename from web3/utils/async/stdlib_async.py rename to web3/utils/compat/compat_stdlib.py index e256e84..01f727c 100644 --- a/web3/utils/async/stdlib_async.py +++ b/web3/utils/compat/compat_stdlib.py @@ -69,6 +69,10 @@ class Timeout(Exception): def cancel(self): self.is_running = False + def sleep(self, seconds): + time.sleep(seconds) + self.check() + class empty(object): pass @@ -92,8 +96,8 @@ class ThreadWithReturn(threading.Thread): raise RuntimeError("Something went wrong. No `_return` property was set") -def spawn(target, *args, **kwargs): - thread = ThreadWithReturn( +def spawn(target, thread_class=ThreadWithReturn, *args, **kwargs): + thread = thread_class( target=target, args=args, kwargs=kwargs, diff --git a/web3/utils/filters.py b/web3/utils/filters.py index f4efdf0..4cf6645 100644 --- a/web3/utils/filters.py +++ b/web3/utils/filters.py @@ -9,7 +9,7 @@ from .events import ( construct_event_topic_set, construct_event_data_set, ) -from .async import ( +from .compat import ( sleep, GreenletThread, ) diff --git a/web3/utils/transactions.py b/web3/utils/transactions.py index 5319bad..02d762b 100644 --- a/web3/utils/transactions.py +++ b/web3/utils/transactions.py @@ -25,17 +25,18 @@ from .address import ( from .formatting import ( pad_left, ) -from . import async +from .compat import ( + Timeout, +) def wait_for_transaction_receipt(web3, txn_hash, timeout=120): - with async.Timeout(timeout) as _timeout: + with Timeout(timeout) as _timeout: while True: txn_receipt = web3.eth.getTransactionReceipt(txn_hash) if txn_receipt is not None: break - async.sleep(random.random()) - _timeout.check() + _timeout.sleep(random.random()) return txn_receipt