Skip to content

Commit 72d154a

Browse files
committed
Merge pull request #1216 from njgheorghita/pm-api-unstable-flag
Disable pm api by default
2 parents 02da228 + 8416c8a commit 72d154a

File tree

7 files changed

+94
-63
lines changed

7 files changed

+94
-63
lines changed

docs/web3.pm.rst

+37-11
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,30 @@ To learn more about the EthPM spec, visit the `documentation <http://ethpm.githu
88
To learn more about the Py-EthPM library used in this module, visit the `documentation <https://py-ethpm.readthedocs.io/en/latest/>`__.
99

1010

11-
Attaching
12-
---------
13-
To use ``web3.pm``, attach it to your ``web3`` instance.
14-
15-
.. code-block:: python
16-
17-
from web3.pm import PM
18-
PM.attach(web3, 'pm')
19-
11+
.. WARNING::
12+
13+
The ``web3.pm`` API is still under development and likely to change quickly.
14+
15+
Now is a great time to get familiar with the API, and test out writing
16+
code that uses some of the great upcoming features.
17+
18+
By default, access to this module has been turned off in the stable version of Web3.py:
19+
20+
.. code-block:: python
21+
22+
>>> from web3.auto import w3
23+
>>> w3.pm
24+
...
25+
AttributeError: The Package Management feature is disabled by default ...
26+
27+
In order to access these features, you can turn it on with...
28+
29+
.. code-block:: python
30+
31+
>>> web3.enable_unstable_package_management_api()
32+
>>> w3.pm
33+
<web3.pm.PM at 0x....>
34+
2035
2136
Methods
2237
-------
@@ -25,8 +40,6 @@ The following methods are available on the ``web3.pm`` namespace.
2540
.. autoclass:: web3.pm.PM
2641
:members:
2742

28-
.. note:: If you want to implement your own registry and use it with ``web3.pm``, you must create a subclass that inherits from ``ERCRegistry``, implements all the methods defined in ``ERCRegistry``, and manually set it as the ```registry`` attribute on ``web3.pm``.
29-
3043
.. autoclass:: web3.pm.ERCRegistry
3144
:members: __init__, _release, _get_package_name, _get_all_package_ids, _get_release_id, _get_all_release_ids, _get_release_data, _generate_release_id, _num_package_ids, _num_release_ids
3245

@@ -36,3 +49,16 @@ The following methods are available on the ``web3.pm`` namespace.
3649
.. autoclass:: web3.pm.SolidityReferenceRegistry
3750
:members:
3851

52+
53+
Creating your own Registry class
54+
--------------------------------
55+
If you want to implement your own registry and use it with ``web3.pm``, you must create a subclass that inherits from ``ERCRegistry``, and implements all the `ERC 1319 standard methods <https://github.com/ethereum/EIPs/issues/1319>`_ prefixed with an underscore in ``ERCRegistry``. Then, you have to manually set it as the ``registry`` attribute on ``web3.pm``.
56+
57+
.. code-block:: python
58+
59+
custom_registry = CustomRegistryClass(address, w3)
60+
w3.pm.registry = custom_registry
61+
62+
One reason a user might want to create their own Registry class is if they build a custom Package Registry smart contract that has features beyond those specified in `ERC 1319 <https://github.com/ethereum/EIPs/issues/1319>`_. For example, the ability to delete a release or some micropayment feature. Rather than accessing those functions directly on the contract instance, they can create a custom ``ERCRegistry`` subclass to easily call both the standard & custom methods.
63+
64+
The ``VyperReferenceRegistry`` class is an example of this, as it contains all of the ``ERC 1319`` defined functions (prefixed with an underscore, eg ``_get_package_name``) but also contains functions that are unique to the Vyper Registry reference implementation (eg ``transfer_owner``).

setup.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
'tester': [
1010
"eth-tester[py-evm]==0.1.0-beta.36",
1111
"py-geth>=2.0.1,<3.0.0",
12+
"pytest-ethereum>=0.1.3a6,<1.0.0",
1213
],
1314
'testrpc': ["eth-testrpc>=1.3.3,<2.0.0"],
1415
'linter': [
@@ -71,10 +72,9 @@
7172
"eth-account>=0.2.1,<0.4.0",
7273
"eth-hash[pycryptodome]>=0.2.0,<1.0.0",
7374
"eth-utils>=1.3.0,<2.0.0",
74-
"ethpm>=0.1.4a10,<1",
75+
"ethpm>=0.1.4a10,<1.0.0",
7576
"hexbytes>=0.1.0,<1.0.0",
7677
"lru-dict>=1.1.6,<2.0.0",
77-
"pytest-ethereum>=0.1.3a6,<1",
7878
"requests>=2.16.0,<3.0.0",
7979
"websockets>=7.0.0,<8.0.0",
8080
"pypiwin32>=223;platform_system=='Windows'",

tests/core/pm-module/conftest.py

+29-34
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
import json
2-
import logging
32
import pytest
4-
import sys
53

64
from eth_tester import (
75
EthereumTester,
86
PyEVMBackend,
97
)
108
from eth_utils import (
119
function_abi_to_4byte_selector,
10+
to_bytes,
1211
to_canonical_address,
1312
)
1413
from ethpm import (
@@ -19,36 +18,32 @@
1918
LinkableContract,
2019
)
2120
from pytest_ethereum import (
22-
linker as l,
21+
linker,
2322
)
2423
from pytest_ethereum.deployer import (
2524
Deployer,
2625
)
2726

2827
from web3 import Web3
2928
from web3.pm import (
30-
PM,
3129
SolidityReferenceRegistry,
3230
VyperReferenceRegistry,
3331
)
3432

35-
VY_PACKAGE_ID_1 = b'\xd0Y\xe8\xa6\xeaZ\x8b\xbf\x8d\xd0\x97\xa7\xb8\x92#\x16\xdc\xb7\xf0$\xe8"\x0bV\xd3\xc9\xe7\x18\x8ajv@' # noqa: E501
36-
VY_PACKAGE_ID_2 = b"m\xf7\t\xa8V\x98\xad\x92\x14b\xb8\x97\x95G\xe3\xa8s\xe2.\x1cs\xb1\xcbi\x1f\x93v\x84\x7f\xb2\xd4\x02" # noqa: E501
37-
VY_PACKAGE_ID_3 = b"\x80\xe4\x1aB\xe3\xb8\xc3\xaf\x0e\xa5\x1c?\xd5\rH\x1e\xef\x13g\xdd\x9d7\x97\xba\x93\xd3]\xcf`f\x08\x82" # noqa: E501
38-
VY_RELEASE_ID_1 = b"Y^&\xf1\xb2${\xac\xc5~2\x80\x7f\x80Y\xe0\xb0\x83}\xd9\xc4~iF\x99A\x96\xbd)\xc9\xca\x97" # noqa: E501
39-
VY_RELEASE_ID_2 = b"\x04Y,\xb9\xce\xd5A>\x1b\t\xe8{\x08\x9b\xf6\x96\xa0^\xfbv\xee\x87\xc8\xc4\x12Yc_\xacm\x93\x8a" # noqa: E501
40-
VY_RELEASE_ID_3 = b'\xa0m\xbcQ\xf8\x89\x18\x94w\x8c\xe0=\xc2=pm"\x8c\x99x\x95\x95u\x8b\xd3\xdc\xac:\x93\xf4\x7f\n' # noqa: E501
41-
VY_RELEASE_ID_4 = b"\x9co\x87\xdd\xa6C[%\x06\xe8\x12\x06\xb3\x9e\xd7\x82\xa4K\x92\xd8&\xc2J\xb0+\xbd\xed2\x1b\x86\xe2\xad" # noqa: E501
42-
SOL_PACKAGE_ID_1 = b"`\xc5\x11+a\x15\x9ekB\xd5M\x94Px9N\x9d_\xc9\xc6\xff\x0f=\xf7\x89w\x00o\x8b\xbc\x06\xd4" # noqa: E501
43-
SOL_PACKAGE_ID_2 = b"\xdb\xcf\xb0\xbdq\x15\xbfe\x93P\xd7{\xb2+\xb8\x89\xca\x82\x94\xf6\x1b\x0c\xa4\x80\xf8\xa4{\xb8\xfc\x90L\xc9" # noqa: E501
44-
SOL_PACKAGE_ID_3 = b"\xf3\xe4\x00,H\xa7\xf8\xf3H]b\x98\x83\x17\x84\x9c\x17S@\xb6e\x17\xc3\xb2\x99?rVC\xeb\xa8K" # noqa: E501
45-
SOL_RELEASE_ID_1 = b"s\x83Vh\xf7\x1cz\xe8\\\xbd\xcd\xbbZ\x99\x05\xfaB\x0f\xfe\x85\xa8G\xd2\x83\xfa\x9b\xee\xfc\xd5l\xac\xc4" # noqa: E501
46-
SOL_RELEASE_ID_2 = b"\xe5\xef\x02\x92\xa3\xb3kj\xc2\xbe\x07\xee\x92\xdfa\xbe\x15\xe0\xb9\xf1\x02\xdf2\xcb\xe3\xf0\xc0\x12\xefi\xd4b" # noqa: E501
47-
SOL_RELEASE_ID_3 = b"\x12\x80\x14\x8e\n\xf5\xc4~\x95\xb4\x1d\xf1W4\xd0rls \xfcL\xf2\x1e\xfe9#\xfb\x04{S\x89\x9d" # noqa: E501
48-
SOL_RELEASE_ID_4 = b"p\x82\xe9T\xe4\xfdj\xdf\x8a%\xc6\xce\xfe!\x8f2\xecf\xd8\xa1\x97\x19\x7f\x1d\x05\xaag\xa6\\\xafQ\x11" # noqa: E501
49-
50-
51-
logging.basicConfig(stream=sys.stdout, level=logging.INFO, format="%(message)s")
33+
VY_PACKAGE_ID_1 = to_bytes(hexstr='0xd059e8a6ea5a8bbf8dd097a7b8922316dcb7f024e8220b56d3c9e7188a6a7640') # noqa: E501
34+
VY_PACKAGE_ID_2 = to_bytes(hexstr='0x6df709a85698ad921462b8979547e3a873e22e1c73b1cb691f9376847fb2d402') # noqa: E501
35+
VY_PACKAGE_ID_3 = to_bytes(hexstr='0x80e41a42e3b8c3af0ea51c3fd50d481eef1367dd9d3797ba93d35dcf60660882') # noqa: E501
36+
VY_RELEASE_ID_1 = to_bytes(hexstr='0x595e26f1b2247bacc57e32807f8059e0b0837dd9c47e6946994196bd29c9ca97') # noqa: E501
37+
VY_RELEASE_ID_2 = to_bytes(hexstr='0x04592cb9ced5413e1b09e87b089bf696a05efb76ee87c8c41259635fac6d938a') # noqa: E501
38+
VY_RELEASE_ID_3 = to_bytes(hexstr='0xa06dbc51f8891894778ce03dc23d706d228c99789595758bd3dcac3a93f47f0a') # noqa: E501
39+
VY_RELEASE_ID_4 = to_bytes(hexstr='0x9c6f87dda6435b2506e81206b39ed782a44b92d826c24ab02bbded321b86e2ad') # noqa: E501
40+
SOL_PACKAGE_ID_1 = to_bytes(hexstr='0x60c5112b61159e6b42d54d945078394e9d5fc9c6ff0f3df78977006f8bbc06d4') # noqa: E501
41+
SOL_PACKAGE_ID_2 = to_bytes(hexstr='0xdbcfb0bd7115bf659350d77bb22bb889ca8294f61b0ca480f8a47bb8fc904cc9') # noqa: E501
42+
SOL_PACKAGE_ID_3 = to_bytes(hexstr='0xf3e4002c48a7f8f3485d62988317849c175340b66517c3b2993f725643eba84b') # noqa: E501
43+
SOL_RELEASE_ID_1 = to_bytes(hexstr='0x73835668f71c7ae85cbdcdbb5a9905fa420ffe85a847d283fa9beefcd56cacc4') # noqa: E501
44+
SOL_RELEASE_ID_2 = to_bytes(hexstr='0xe5ef0292a3b36b6ac2be07ee92df61be15e0b9f102df32cbe3f0c012ef69d462') # noqa: E501
45+
SOL_RELEASE_ID_3 = to_bytes(hexstr='0x1280148e0af5c47e95b41df15734d0726c7320fc4cf21efe3923fb047b53899d') # noqa: E501
46+
SOL_RELEASE_ID_4 = to_bytes(hexstr='0x7082e954e4fd6adf8a25c6cefe218f32ec66d8a197197f1d05aa67a65caf5111') # noqa: E501
5247

5348

5449
def setup_w3():
@@ -61,7 +56,7 @@ def setup_w3():
6156
w3 = Web3(Web3.EthereumTesterProvider(ethereum_tester=t))
6257
w3.eth.defaultAccount = w3.eth.accounts[0]
6358
w3.eth.defaultContractFactory = LinkableContract
64-
PM.attach(w3, 'pm')
59+
w3.enable_unstable_package_management_api()
6560
return w3
6661

6762

@@ -140,18 +135,18 @@ def set_permissions(package):
140135
).transact()
141136
w3.eth.waitForTransactionReceipt(txh_6)
142137

143-
strategy = l.linker(
144-
l.deploy("IndexedOrderedSetLib"),
145-
l.link("PackageDB", "IndexedOrderedSetLib"),
146-
l.link("ReleaseDB", "IndexedOrderedSetLib"),
147-
l.deploy("PackageRegistry"),
148-
l.deploy("WhitelistAuthority"),
149-
l.deploy("PackageDB"),
150-
l.deploy("ReleaseDB"),
151-
l.deploy("ReleaseValidator"),
152-
l.run_python(set_authority),
153-
l.run_python(set_dependencies),
154-
l.run_python(set_permissions),
138+
strategy = linker.linker(
139+
linker.deploy("IndexedOrderedSetLib"),
140+
linker.link("PackageDB", "IndexedOrderedSetLib"),
141+
linker.link("ReleaseDB", "IndexedOrderedSetLib"),
142+
linker.deploy("PackageRegistry"),
143+
linker.deploy("WhitelistAuthority"),
144+
linker.deploy("PackageDB"),
145+
linker.deploy("ReleaseDB"),
146+
linker.deploy("ReleaseValidator"),
147+
linker.run_python(set_authority),
148+
linker.run_python(set_dependencies),
149+
linker.run_python(set_permissions),
155150
)
156151
return strategy
157152

tests/core/pm-module/test_ens_integration.py

+1-3
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
InvalidAddress,
1414
)
1515
from web3.pm import (
16-
PM,
1716
VyperReferenceRegistry,
1817
)
1918

@@ -119,19 +118,18 @@ def ens_setup(deployer):
119118
def ens(ens_setup, mocker):
120119
mocker.patch('web3.middleware.stalecheck._isfresh', return_value=True)
121120
ens_setup.web3.eth.defaultAccount = ens_setup.web3.eth.coinbase
121+
ens_setup.web3.enable_unstable_package_management_api()
122122
return ens_setup
123123

124124

125125
def test_ens_must_be_set_before_ens_methods_can_be_used(ens):
126126
w3 = ens.web3
127-
PM.attach(w3, 'pm')
128127
with pytest.raises(InvalidAddress):
129128
w3.pm.set_registry("tester.eth")
130129

131130

132131
def test_web3_ens(ens):
133132
w3 = ens.web3
134-
PM.attach(w3, 'pm')
135133
ns = ENS.fromWeb3(w3, ens.ens.address)
136134
w3.ens = ns
137135
registry = VyperReferenceRegistry.deploy_new_instance(w3)

tests/core/pm-module/test_registry_integration.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
PMError,
1717
)
1818
from web3.pm import (
19-
PM,
2019
ERCRegistry,
2120
VyperReferenceRegistry,
2221
get_vyper_registry_manifest,
@@ -28,7 +27,7 @@ def fresh_w3():
2827
w3 = Web3(Web3.EthereumTesterProvider())
2928
w3.eth.defaultAccount = w3.eth.accounts[0]
3029
w3.eth.defaultContractFactory = LinkableContract
31-
PM.attach(w3, "pm")
30+
w3.enable_unstable_package_management_api()
3231
return w3
3332

3433

web3/main.py

+15
Original file line numberDiff line numberDiff line change
@@ -206,3 +206,18 @@ def ens(self):
206206
@ens.setter
207207
def ens(self, new_ens):
208208
self._ens = new_ens
209+
210+
@property
211+
def pm(self):
212+
if self._pm is not None:
213+
return self._pm
214+
else:
215+
raise AttributeError(
216+
"The Package Management feature is disabled by default until "
217+
"its API stabilizes. To use these features, please enable them by running "
218+
"`w3.enable_unstable_package_management_api()` and try again."
219+
)
220+
221+
def enable_unstable_package_management_api(self):
222+
from web3.pm import PM
223+
PM.attach(self, '_pm')

web3/pm.py

+9-11
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,6 @@
3636
validate_package_name,
3737
validate_package_version,
3838
)
39-
from pytest_ethereum.deployer import (
40-
Deployer,
41-
)
4239

4340
from web3 import Web3
4441
from web3._utils.ens import (
@@ -66,8 +63,10 @@ class ERCRegistry(ABC):
6663
The ERCRegistry class is a base class for all registry implementations to inherit from. It
6764
defines the methods specified in `ERC 1319 <https://github.com/ethereum/EIPs/issues/1319>`__.
6865
All of these methods are prefixed with an underscore, since they are not intended to be
69-
accessed directly, but rather through the methods on ``web3.pm``.
70-
Any custom methods in a subclass should not be prefixed with an underscore.
66+
accessed directly, but rather through the methods on ``web3.pm``. They are unlikely to change,
67+
but must be implemented in a `ERCRegistry` subclass in order to be compatible with the
68+
`PM` module. Any custom methods (eg. not definied in ERC1319) in a subclass
69+
should *not* be prefixed with an underscore.
7170
7271
All of these methods must be implemented in any subclass in order to work with `web3.pm.PM`.
7372
Any implementation specific logic should be handled in a subclass.
@@ -213,12 +212,11 @@ def deploy_new_instance(cls, w3: Web3) -> "VyperReferenceRegistry":
213212
"""
214213
manifest = get_vyper_registry_manifest()
215214
registry_package = Package(manifest, w3)
216-
registry_deployer = Deployer(registry_package)
217-
deployed_registry_package = registry_deployer.deploy("registry")
218-
registry_address = deployed_registry_package.deployments.get_instance(
219-
"registry"
220-
).address
221-
return cls(to_canonical_address(registry_address), deployed_registry_package.w3)
215+
registry_factory = registry_package.get_contract_factory("registry")
216+
tx_hash = registry_factory.constructor().transact()
217+
tx_receipt = w3.eth.waitForTransactionReceipt(tx_hash)
218+
registry_address = to_canonical_address(tx_receipt.contractAddress)
219+
return cls(registry_address, w3)
222220

223221
def _release(self, package_name: str, version: str, manifest_uri: str) -> bytes:
224222
if len(package_name) > 32 or len(version) > 32:

0 commit comments

Comments
 (0)