From 3d28ba53f51ca38ce7962f4fe2632c611c92a532 Mon Sep 17 00:00:00 2001 From: ape364 Date: Sun, 9 Jun 2024 02:00:14 +0500 Subject: [PATCH] dont fetch current block --- .../modules/extra/generators/blocks_range.py | 4 +- .../extra/generators/generator_utils.py | 38 +++++----- poetry.lock | 38 +++------- requirements.dev.txt | 7 +- tests/extra/generators/test_blocks_range.py | 3 +- .../extra/generators/test_generator_utils.py | 37 +--------- tests/extra/generators/test_helpers.py | 8 ++- tests/extra/test_contract_utils.py | 71 ++++++++++--------- 8 files changed, 79 insertions(+), 127 deletions(-) diff --git a/aioetherscan/modules/extra/generators/blocks_range.py b/aioetherscan/modules/extra/generators/blocks_range.py index 5ac29a4..e25ec1c 100644 --- a/aioetherscan/modules/extra/generators/blocks_range.py +++ b/aioetherscan/modules/extra/generators/blocks_range.py @@ -26,7 +26,9 @@ def restore(self) -> None: class BlocksRange: - def __init__(self, start_block: int, end_block: int, blocks_limit: int, blocks_limit_divider: int) -> None: + def __init__( + self, start_block: int, end_block: int, blocks_limit: int, blocks_limit_divider: int + ) -> None: self.start_block = start_block self.end_block = end_block diff --git a/aioetherscan/modules/extra/generators/generator_utils.py b/aioetherscan/modules/extra/generators/generator_utils.py index 8a52310..421ea8a 100644 --- a/aioetherscan/modules/extra/generators/generator_utils.py +++ b/aioetherscan/modules/extra/generators/generator_utils.py @@ -1,4 +1,5 @@ import inspect +import sys from itertools import count from typing import Callable, Any, Optional, TYPE_CHECKING, AsyncIterator @@ -10,9 +11,10 @@ class GeneratorUtils: - DEFAULT_START_BLOCK: int = 0 - DEFAULT_BLOCKS_LIMIT: int = 2048 - DEFAULT_BLOCKS_LIMIT_DIVIDER: int = 2 + _DEFAULT_START_BLOCK: int = 0 + _DEFAULT_END_BLOCK: int = sys.maxsize + _DEFAULT_BLOCKS_LIMIT: int = 2048 + _DEFAULT_BLOCKS_LIMIT_DIVIDER: int = 2 def __init__(self, client: 'Client') -> None: self._client = client @@ -21,10 +23,10 @@ async def token_transfers( self, contract_address: str = None, address: str = None, - start_block: int = DEFAULT_START_BLOCK, - end_block: Optional[int] = None, - blocks_limit: int = DEFAULT_BLOCKS_LIMIT, - blocks_limit_divider: int = DEFAULT_BLOCKS_LIMIT_DIVIDER, + start_block: int = _DEFAULT_START_BLOCK, + end_block: int = _DEFAULT_END_BLOCK, + blocks_limit: int = _DEFAULT_BLOCKS_LIMIT, + blocks_limit_divider: int = _DEFAULT_BLOCKS_LIMIT_DIVIDER, ) -> AsyncIterator[Transfer]: parser_params = self._get_parser_params(self._client.account.token_transfers, locals()) async for transfer in self._parse_by_blocks(**parser_params): @@ -33,10 +35,10 @@ async def token_transfers( async def normal_txs( self, address: str, - start_block: int = DEFAULT_START_BLOCK, - end_block: Optional[int] = None, - blocks_limit: int = DEFAULT_BLOCKS_LIMIT, - blocks_limit_divider: int = DEFAULT_BLOCKS_LIMIT_DIVIDER, + start_block: int = _DEFAULT_START_BLOCK, + end_block: int = _DEFAULT_END_BLOCK, + blocks_limit: int = _DEFAULT_BLOCKS_LIMIT, + blocks_limit_divider: int = _DEFAULT_BLOCKS_LIMIT_DIVIDER, ) -> AsyncIterator[Transfer]: parser_params = self._get_parser_params(self._client.account.normal_txs, locals()) async for transfer in self._parse_by_blocks(**parser_params): @@ -45,10 +47,10 @@ async def normal_txs( async def internal_txs( self, address: str, - start_block: int = DEFAULT_START_BLOCK, - end_block: Optional[int] = None, - blocks_limit: int = DEFAULT_BLOCKS_LIMIT, - blocks_limit_divider: int = DEFAULT_BLOCKS_LIMIT_DIVIDER, + start_block: int = _DEFAULT_START_BLOCK, + end_block: int = _DEFAULT_END_BLOCK, + blocks_limit: int = _DEFAULT_BLOCKS_LIMIT, + blocks_limit_divider: int = _DEFAULT_BLOCKS_LIMIT_DIVIDER, txhash: Optional[str] = None, ) -> AsyncIterator[Transfer]: parser_params = self._get_parser_params(self._client.account.internal_txs, locals()) @@ -71,9 +73,6 @@ async def _parse_by_blocks( blocks_limit: int, blocks_limit_divider: int, ) -> AsyncIterator[Transfer]: - if end_block is None: - end_block = await self._get_current_block() - blocks_parser = self._get_blocks_parser( api_method, request_params, start_block, end_block, blocks_limit, blocks_limit_divider ) @@ -97,9 +96,6 @@ async def _parse_by_pages( for row in result: yield row - async def _get_current_block(self) -> int: - return int(await self._client.proxy.block_number(), 16) - @staticmethod def _without_keys(params: dict, excluded_keys: tuple[str, ...] = ('self',)) -> dict: return {k: v for k, v in params.items() if k not in excluded_keys} diff --git a/poetry.lock b/poetry.lock index 00ea84c..bccfc91 100644 --- a/poetry.lock +++ b/poetry.lock @@ -167,13 +167,13 @@ tests-no-zope = ["attrs[tests-mypy]", "cloudpickle", "hypothesis", "pympler", "p [[package]] name = "certifi" -version = "2024.2.2" +version = "2024.6.2" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2024.2.2-py3-none-any.whl", hash = "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1"}, - {file = "certifi-2024.2.2.tar.gz", hash = "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f"}, + {file = "certifi-2024.6.2-py3-none-any.whl", hash = "sha256:ddc6c8ce995e6987e7faf5e3f1b02b302836a0e5d98ece18392cb1a36c72ad56"}, + {file = "certifi-2024.6.2.tar.gz", hash = "sha256:3cd43f1c6fa7dedc5899d69d3ad0398fd018ad1a17fba83ddaf78aa46c747516"}, ] [[package]] @@ -652,18 +652,15 @@ files = [ [[package]] name = "nodeenv" -version = "1.8.0" +version = "1.9.1" description = "Node.js virtual environment builder" optional = false -python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" files = [ - {file = "nodeenv-1.8.0-py2.py3-none-any.whl", hash = "sha256:df865724bb3c3adc86b3876fa209771517b0cfe596beff01a92700e0e8be4cec"}, - {file = "nodeenv-1.8.0.tar.gz", hash = "sha256:d51e0c37e64fbf47d017feac3145cdbb58836d7eee8c6f6d3b6880c5456227d2"}, + {file = "nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9"}, + {file = "nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f"}, ] -[package.dependencies] -setuptools = "*" - [[package]] name = "packaging" version = "24.0" @@ -826,13 +823,13 @@ files = [ [[package]] name = "requests" -version = "2.32.2" +version = "2.32.3" description = "Python HTTP for Humans." optional = false python-versions = ">=3.8" files = [ - {file = "requests-2.32.2-py3-none-any.whl", hash = "sha256:fc06670dd0ed212426dfeb94fc1b983d917c4f9847c863f313c9dfaaffb7c23c"}, - {file = "requests-2.32.2.tar.gz", hash = "sha256:dd951ff5ecf3e3b3aa26b40703ba77495dab41da839ae72ef3c8e5d8e2433289"}, + {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, + {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, ] [package.dependencies] @@ -845,21 +842,6 @@ urllib3 = ">=1.21.1,<3" socks = ["PySocks (>=1.5.6,!=1.5.7)"] use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] -[[package]] -name = "setuptools" -version = "70.0.0" -description = "Easily download, build, install, upgrade, and uninstall Python packages" -optional = false -python-versions = ">=3.8" -files = [ - {file = "setuptools-70.0.0-py3-none-any.whl", hash = "sha256:54faa7f2e8d2d11bcd2c07bed282eef1046b5c080d1c32add737d7b5817b1ad4"}, - {file = "setuptools-70.0.0.tar.gz", hash = "sha256:f211a66637b8fa059bb28183da127d4e86396c991a942b028c6650d4319c3fd0"}, -] - -[package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -testing = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "mypy (==1.9)", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.1)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy", "pytest-perf", "pytest-ruff (>=0.2.1)", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] - [[package]] name = "tomli" version = "2.0.1" diff --git a/requirements.dev.txt b/requirements.dev.txt index 289a9fb..27ee474 100644 --- a/requirements.dev.txt +++ b/requirements.dev.txt @@ -4,7 +4,7 @@ aiosignal==1.3.1 ; python_version >= "3.9" and python_version < "4.0" async-timeout==4.0.3 ; python_version >= "3.9" and python_version < "3.11" asyncio-throttle==1.0.2 ; python_version >= "3.9" and python_version < "4.0" attrs==23.2.0 ; python_version >= "3.9" and python_version < "4.0" -certifi==2024.2.2 ; python_version >= "3.9" and python_version < "4.0" +certifi==2024.6.2 ; python_version >= "3.9" and python_version < "4.0" cfgv==3.4.0 ; python_version >= "3.9" and python_version < "4.0" charset-normalizer==3.3.2 ; python_version >= "3.9" and python_version < "4.0" colorama==0.4.6 ; python_version >= "3.9" and python_version < "4.0" and sys_platform == "win32" @@ -19,7 +19,7 @@ identify==2.5.36 ; python_version >= "3.9" and python_version < "4.0" idna==3.7 ; python_version >= "3.9" and python_version < "4.0" iniconfig==2.0.0 ; python_version >= "3.9" and python_version < "4.0" multidict==6.0.5 ; python_version >= "3.9" and python_version < "4.0" -nodeenv==1.8.0 ; python_version >= "3.9" and python_version < "4.0" +nodeenv==1.9.1 ; python_version >= "3.9" and python_version < "4.0" packaging==24.0 ; python_version >= "3.9" and python_version < "4.0" platformdirs==4.2.2 ; python_version >= "3.9" and python_version < "4.0" pluggy==1.5.0 ; python_version >= "3.9" and python_version < "4.0" @@ -27,8 +27,7 @@ pre-commit==3.7.1 ; python_version >= "3.9" and python_version < "4.0" pytest-asyncio==0.21.2 ; python_version >= "3.9" and python_version < "4.0" pytest==7.4.4 ; python_version >= "3.9" and python_version < "4.0" pyyaml==6.0.1 ; python_version >= "3.9" and python_version < "4.0" -requests==2.32.2 ; python_version >= "3.9" and python_version < "4.0" -setuptools==70.0.0 ; python_version >= "3.9" and python_version < "4.0" +requests==2.32.3 ; python_version >= "3.9" and python_version < "4.0" tomli==2.0.1 ; python_version >= "3.9" and python_version < "3.11" urllib3==2.2.1 ; python_version >= "3.9" and python_version < "4.0" virtualenv==20.26.2 ; python_version >= "3.9" and python_version < "4.0" diff --git a/tests/extra/generators/test_blocks_range.py b/tests/extra/generators/test_blocks_range.py index b025e0b..f7bf258 100644 --- a/tests/extra/generators/test_blocks_range.py +++ b/tests/extra/generators/test_blocks_range.py @@ -4,7 +4,7 @@ from aioetherscan.modules.extra.generators.blocks_range import Limit, BlocksRange -INITIAL_LIMIT = 2 ** 4 +INITIAL_LIMIT = 2**4 BLOCKS_RANGE_DIVIDER = 2 START_BLOCK = 1000 @@ -65,6 +65,7 @@ def test_limit_get(limit: Limit): # ############################### blocks range ################################ + def test_br_init(br: BlocksRange): assert br.start_block == START_BLOCK assert br.end_block == END_BLOCK diff --git a/tests/extra/generators/test_generator_utils.py b/tests/extra/generators/test_generator_utils.py index d9824c1..5fff82a 100644 --- a/tests/extra/generators/test_generator_utils.py +++ b/tests/extra/generators/test_generator_utils.py @@ -177,26 +177,19 @@ async def test_parse_by_blocks_end_block_is_none(generator_utils): blocks_parser_mock.return_value.txs_generator = MagicMock(side_effect=transfers_mock) generator_utils._get_blocks_parser = blocks_parser_mock - current_block = 200 - get_current_block_mock = AsyncMock(return_value=current_block) - generator_utils._get_current_block = get_current_block_mock - transfers = [] async for transfer in generator_utils._parse_by_blocks( api_method=None, request_params={'param': 'value'}, start_block=100, - end_block=None, + end_block=200, blocks_limit=1000, blocks_limit_divider=2, ): transfers.append(transfer) assert transfers == transfers_for_test() - get_current_block_mock.assert_awaited_once() - blocks_parser_mock.assert_called_once_with( - None, {'param': 'value'}, 100, current_block, 1000, 2 - ) + blocks_parser_mock.assert_called_once_with(None, {'param': 'value'}, 100, 200, 1000, 2) async def test_parse_by_pages_ok(generator_utils): @@ -224,32 +217,6 @@ async def test_parse_by_pages_error(generator_utils): assert e.value.args[0] == 'test error' -async def test_get_current_block(generator_utils): - generator_utils._client = Mock() - generator_utils._client.proxy.block_number = AsyncMock(return_value='0x2d0') - - result = await generator_utils._get_current_block() - - generator_utils._client.proxy.block_number.assert_awaited_once() - assert isinstance(result, int) - assert result == int('0x2d0', 16) - - -async def test_get_current_block_error(generator_utils): - generator_utils._client = Mock() - generator_utils._client.proxy.block_number = AsyncMock( - side_effect=EtherscanClientApiError('message', 'code') - ) - - with pytest.raises(EtherscanClientApiError) as e: - await generator_utils._get_current_block() - - generator_utils._client.proxy.block_number.assert_awaited_once() - - assert e.value.message == 'message' - assert e.value.result == 'code' - - @pytest.mark.parametrize( 'params, excluded, expected', [ diff --git a/tests/extra/generators/test_helpers.py b/tests/extra/generators/test_helpers.py index 4051cb1..37fcdee 100644 --- a/tests/extra/generators/test_helpers.py +++ b/tests/extra/generators/test_helpers.py @@ -1,4 +1,8 @@ -from aioetherscan.modules.extra.generators.helpers import tx_block_number, drop_block, get_max_block_number +from aioetherscan.modules.extra.generators.helpers import ( + tx_block_number, + drop_block, + get_max_block_number, +) def test_tx_block_number(): @@ -28,7 +32,7 @@ def test_drop_block(): def test_get_max_block_number(): - max_block_number = 2 ** 16 + max_block_number = 2**16 transfers = [ dict(blockNumber=123), dict(blockNumber=max_block_number), diff --git a/tests/extra/test_contract_utils.py b/tests/extra/test_contract_utils.py index bd4ecf9..d1b784f 100644 --- a/tests/extra/test_contract_utils.py +++ b/tests/extra/test_contract_utils.py @@ -17,7 +17,10 @@ async def contract_utils(): @pytest.mark.asyncio async def test_is_contract_ok(contract_utils): return_value = {'some': 'data'} - with patch('aioetherscan.modules.contract.Contract.contract_abi', new=AsyncMock(return_value=return_value)) as mock: + with patch( + 'aioetherscan.modules.contract.Contract.contract_abi', + new=AsyncMock(return_value=return_value), + ) as mock: result = await contract_utils.is_contract(address='addr') mock.assert_called_once_with(address='addr') assert result is True @@ -26,7 +29,9 @@ async def test_is_contract_ok(contract_utils): @pytest.mark.asyncio async def test_is_contract_negative(contract_utils): exc = EtherscanClientApiError(message='NOTOK', result='contract source code not verified') - with patch('aioetherscan.modules.contract.Contract.contract_abi', new=AsyncMock(side_effect=exc)) as mock: + with patch( + 'aioetherscan.modules.contract.Contract.contract_abi', new=AsyncMock(side_effect=exc) + ): result = await contract_utils.is_contract(address='addr') assert result is False @@ -34,7 +39,9 @@ async def test_is_contract_negative(contract_utils): @pytest.mark.asyncio async def test_is_contract_exception(contract_utils): exc = EtherscanClientApiError(message='some_msg', result='some_result') - with patch('aioetherscan.modules.contract.Contract.contract_abi', new=AsyncMock(side_effect=exc)) as mock: + with patch( + 'aioetherscan.modules.contract.Contract.contract_abi', new=AsyncMock(side_effect=exc) + ): with pytest.raises(EtherscanClientApiError): await contract_utils.is_contract(address='addr') @@ -42,15 +49,14 @@ async def test_is_contract_exception(contract_utils): @pytest.mark.asyncio async def test_get_contract_creator_internal_ok(contract_utils): creator = '0x123' - internal_txs_mock = AsyncMock(return_value=[{'from': creator}, ]) + internal_txs_mock = AsyncMock( + return_value=[ + {'from': creator}, + ] + ) with patch('aioetherscan.modules.account.Account.internal_txs', new=internal_txs_mock) as mock: result = await contract_utils.get_contract_creator(contract_address='addr') - mock.assert_called_once_with( - address='addr', - start_block=1, - page=1, - offset=1 - ) + mock.assert_called_once_with(address='addr', start_block=1, page=1, offset=1) assert result == creator @@ -58,7 +64,7 @@ async def test_get_contract_creator_internal_ok(contract_utils): async def test_get_contract_creator_internal_raise(contract_utils): exc = EtherscanClientApiError(message='No transactions found', result='') internal_txs_mock = AsyncMock(side_effect=exc) - with patch('aioetherscan.modules.account.Account.internal_txs', new=internal_txs_mock) as mock: + with patch('aioetherscan.modules.account.Account.internal_txs', new=internal_txs_mock): with pytest.raises(EtherscanClientApiError): await contract_utils.get_contract_creator(contract_address='addr') @@ -69,22 +75,20 @@ async def test_get_contract_creator_internal_raise_none(contract_utils): internal_txs_mock = AsyncMock(side_effect=exc) creator = '0x123' - normal_txs_mock = AsyncMock(return_value=[{'from': creator}, ]) - with patch('aioetherscan.modules.account.Account.internal_txs', new=internal_txs_mock) as internal_mock: - with patch('aioetherscan.modules.account.Account.normal_txs', new=normal_txs_mock) as normal_mock: + normal_txs_mock = AsyncMock( + return_value=[ + {'from': creator}, + ] + ) + with patch( + 'aioetherscan.modules.account.Account.internal_txs', new=internal_txs_mock + ) as internal_mock: + with patch( + 'aioetherscan.modules.account.Account.normal_txs', new=normal_txs_mock + ) as normal_mock: result = await contract_utils.get_contract_creator(contract_address='addr') - internal_mock.assert_called_once_with( - address='addr', - start_block=1, - page=1, - offset=1 - ) - normal_mock.assert_called_once_with( - address='addr', - start_block=1, - page=1, - offset=1 - ) + internal_mock.assert_called_once_with(address='addr', start_block=1, page=1, offset=1) + normal_mock.assert_called_once_with(address='addr', start_block=1, page=1, offset=1) assert result == creator @@ -96,8 +100,8 @@ async def test_get_contract_creator_internal_raise_normal(contract_utils): normal_exc = EtherscanClientApiError(message='No transactions found', result='') normal_txs_mock = AsyncMock(side_effect=normal_exc) - with patch('aioetherscan.modules.account.Account.internal_txs', new=internal_txs_mock) as internal_mock: - with patch('aioetherscan.modules.account.Account.normal_txs', new=normal_txs_mock) as normal_mock: + with patch('aioetherscan.modules.account.Account.internal_txs', new=internal_txs_mock): + with patch('aioetherscan.modules.account.Account.normal_txs', new=normal_txs_mock): with pytest.raises(EtherscanClientApiError): await contract_utils.get_contract_creator(contract_address='addr') @@ -107,13 +111,10 @@ async def test_get_contract_creator_internal_none(contract_utils): empty_result_mock_int = AsyncMock(return_value=[]) empty_result_mock_norm = AsyncMock(return_value=[]) - with patch('aioetherscan.modules.account.Account.internal_txs', new=empty_result_mock_int) as mock: + with patch( + 'aioetherscan.modules.account.Account.internal_txs', new=empty_result_mock_int + ) as mock: with patch('aioetherscan.modules.account.Account.normal_txs', new=empty_result_mock_norm): result = await contract_utils.get_contract_creator(contract_address='addr') - mock.assert_called_once_with( - address='addr', - start_block=1, - page=1, - offset=1 - ) + mock.assert_called_once_with(address='addr', start_block=1, page=1, offset=1) assert result is None