Skip to content

Commit 36a427e

Browse files
authored
feat: adds support for $WEB3_PROVIDER_URI (#2687)
1 parent 112cf5e commit 36a427e

File tree

4 files changed

+25
-68
lines changed

4 files changed

+25
-68
lines changed

src/ape/managers/config.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from typing import TYPE_CHECKING, Any, Optional, Union
88

99
from ape.api.config import ApeConfig
10+
from ape.logging import logger
1011
from ape.managers.base import BaseManager
1112
from ape.utils.basemodel import (
1213
ExtraAttributesMixin,
@@ -150,7 +151,13 @@ def isolate_data_folder(
150151
continue
151152

152153
dest_path = temp_data_folder / item
153-
shutil.copytree(path_to_keep, dest_path)
154+
try:
155+
shutil.copytree(path_to_keep, dest_path)
156+
except Exception as err:
157+
logger.warning(
158+
f"Problem copying '{dest_path.name}' when making isolated project: {err}"
159+
)
160+
continue
154161

155162
self.DATA_FOLDER = temp_data_folder
156163
yield temp_data_folder

src/ape_ethereum/provider.py

Lines changed: 16 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@
7373
from ape_ethereum.trace import CallTrace, TraceApproach, TransactionTrace
7474
from ape_ethereum.transactions import AccessList, AccessListTransaction, TransactionStatusEnum
7575

76+
WEB3_PROVIDER_URI_ENV_VAR_NAME = "WEB3_PROVIDER_URI"
77+
7678
if TYPE_CHECKING:
7779
from ethpm_types import EventABI
7880

@@ -105,34 +107,6 @@ def _sanitize_web3_url(msg: str) -> str:
105107
return f"{prefix} URI: {sanitized_url} {' '.join(rest[1:])}"
106108

107109

108-
WEB3_PROVIDER_URI_ENV_VAR_NAME = "WEB3_PROVIDER_URI"
109-
110-
111-
def assert_web3_provider_uri_env_var_not_set():
112-
"""
113-
Environment variable $WEB3_PROVIDER_URI causes problems
114-
when used with Ape (ignores Ape's networks). Use
115-
this validator to eliminate the concern.
116-
117-
Raises:
118-
:class:`~ape.exceptions.ProviderError`: If environment variable
119-
WEB3_PROVIDER_URI exists in ``os.environ``.
120-
"""
121-
if WEB3_PROVIDER_URI_ENV_VAR_NAME not in os.environ:
122-
return
123-
124-
# NOTE: This was the source of confusion for user when they noticed
125-
# Ape would only connect to RPC URL set by an environment variable
126-
# named $WEB3_PROVIDER_URI instead of whatever network they were telling Ape.
127-
raise ProviderError(
128-
"Ape does not support Web3.py's environment variable "
129-
f"${WEB3_PROVIDER_URI_ENV_VAR_NAME}. If you are using this environment "
130-
"variable name incidentally, please use a different name. If you are "
131-
"trying to set the network in Web3.py, please use Ape's `ape-config.yaml` "
132-
"or `--network` option instead."
133-
)
134-
135-
136110
def _post_send_transaction(tx: TransactionAPI, receipt: ReceiptAPI):
137111
"""Execute post-transaction ops"""
138112

@@ -171,8 +145,6 @@ class Web3Provider(ProviderAPI, ABC):
171145
_transaction_trace_cache: dict[str, TransactionTrace] = {}
172146

173147
def __new__(cls, *args, **kwargs):
174-
assert_web3_provider_uri_env_var_not_set()
175-
176148
# Post-connection ops
177149
def post_connect_hook(connect):
178150
@wraps(connect)
@@ -384,7 +356,20 @@ def _default_http_uri(self) -> Optional[str]:
384356
# Use a default localhost value.
385357
return DEFAULT_HTTP_URI
386358

387-
elif rpc := self._get_random_rpc():
359+
elif env_var := os.getenv(WEB3_PROVIDER_URI_ENV_VAR_NAME):
360+
# Default Web3 environment variable support that works with web3 out-the-box.
361+
# Eliminates need for random RPCs and allows usage of this feature. **MUST BE**
362+
# for the same chain the user is trying to connect to, which requires a bit of a hack.
363+
# NOTE: We should be able to assume NOT dev here which means chain IDs are hardcoded.
364+
tmp_w3 = Web3(HTTPProvider(endpoint_uri=env_var))
365+
if self.network.chain_id == tmp_w3.eth.chain_id:
366+
return env_var
367+
368+
# NOTE: We **must** remove the environment variable here or else Ape won't work.
369+
os.environ.pop(WEB3_PROVIDER_URI_ENV_VAR_NAME, None)
370+
# Next, drop down and try to use a random RPc from evmchains.
371+
372+
if rpc := self._get_random_rpc():
388373
# This works when the network is in `evmchains`.
389374
return rpc
390375

tests/functional/test_project.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -737,7 +737,7 @@ def test_init(self, with_dependencies_project_path):
737737
project.manifest_path.unlink(missing_ok=True)
738738

739739
# Re-init to show it doesn't create the manifest file.
740-
project = Project(temp_project.path)
740+
_ = Project(temp_project.path)
741741

742742
def test_init_invalid_config(self):
743743
here = os.curdir

tests/functional/test_provider.py

Lines changed: 0 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import os
21
from pathlib import Path
32
from unittest import mock
43

@@ -25,7 +24,6 @@
2524
from ape.types.events import LogFilter
2625
from ape.utils.testing import DEFAULT_TEST_CHAIN_ID
2726
from ape_ethereum.provider import (
28-
WEB3_PROVIDER_URI_ENV_VAR_NAME,
2927
EthereumNodeProvider,
3028
Web3Provider,
3129
_sanitize_web3_url,
@@ -671,39 +669,6 @@ def test_auto_mine(eth_tester_provider, owner):
671669
assert eth_tester_provider.auto_mine
672670

673671

674-
def test_new_when_web3_provider_uri_set():
675-
"""
676-
Tests against a confusing case where having an env var
677-
$WEB3_PROVIDER_URI caused web3.py to only ever use that RPC
678-
URL regardless of what was said in Ape's --network or config.
679-
Now, we raise an error to avoid having users think Ape's
680-
network system is broken.
681-
"""
682-
os.environ[WEB3_PROVIDER_URI_ENV_VAR_NAME] = "TEST"
683-
expected = (
684-
rf"Ape does not support Web3\.py's environment variable "
685-
rf"\${WEB3_PROVIDER_URI_ENV_VAR_NAME}\. If you are using this environment "
686-
r"variable name incidentally, please use a different name\. If you are "
687-
r"trying to set the network in Web3\.py, please use Ape's `ape-config\.yaml` "
688-
r"or `--network` option instead\."
689-
)
690-
691-
class MyProvider(Web3Provider):
692-
def connect(self):
693-
raise NotImplementedError()
694-
695-
def disconnect(self):
696-
raise NotImplementedError()
697-
698-
try:
699-
with pytest.raises(ProviderError, match=expected):
700-
_ = MyProvider(data_folder=None, name=None, network=None)
701-
702-
finally:
703-
if WEB3_PROVIDER_URI_ENV_VAR_NAME in os.environ:
704-
del os.environ[WEB3_PROVIDER_URI_ENV_VAR_NAME]
705-
706-
707672
def test_account_balance_state(project, eth_tester_provider, owner):
708673
amount = convert("100_000 ETH", int)
709674

0 commit comments

Comments
 (0)