mirror of
https://github.com/FlipsideCrypto/web3.py.git
synced 2026-02-06 10:56:47 +00:00
Merge pull request #155 from pipermerriam/piper/fancier-contract-objects
Add additional compiler fields to Contract object.
This commit is contained in:
commit
95c824044e
@ -8,7 +8,7 @@ Contracts
|
||||
Contract Factories
|
||||
------------------
|
||||
|
||||
.. py:class:: Contract(abi, address=None, code=None, code_runtime=None, source=None)
|
||||
.. py:class:: Contract(address)
|
||||
|
||||
The ``Contract`` class is not intended to be used or instantiated directly.
|
||||
Instead you should use the ``web3.eth.contract(...)`` method to generate
|
||||
@ -35,19 +35,19 @@ Each Contract Factory exposes the following properties.
|
||||
The contract ABI array.
|
||||
|
||||
|
||||
.. py:attribute:: Contract.code
|
||||
.. py:attribute:: Contract.bytecode
|
||||
|
||||
The contract bytecode string. May be ``None`` if not provided during
|
||||
factory creation.
|
||||
|
||||
|
||||
.. py:attribute:: Contract.code_runtime
|
||||
.. py:attribute:: Contract.bytecode_runtime
|
||||
|
||||
The runtime part of the contract bytecode string. May be ``None`` if not
|
||||
provided during factory creation.
|
||||
|
||||
|
||||
.. py:attribute:: Contract.code_runtime
|
||||
.. py:attribute:: Contract.bytecode_runtime
|
||||
|
||||
The runtime part of the contract bytecode string. May be ``None`` if not
|
||||
provided during factory creation.
|
||||
|
||||
@ -579,22 +579,31 @@ with the filtering API.
|
||||
Contracts
|
||||
---------
|
||||
|
||||
.. py:method:: Eth.contract(abi, address=None, code=None, code_runtime=None, source=None)
|
||||
.. py:method:: Eth.contract(address=None, contract_name=None, ContractFactoryClass=Contract, **contract_factory_kwargs)
|
||||
|
||||
If ``address`` is provided then this method will return an instance of the
|
||||
contract defined by ``abi``.
|
||||
contract defined by ``abi``. Otherwise the newly created contract class
|
||||
will be returned.
|
||||
|
||||
If ``address`` is ``None`` then this method will return a Contract Factory,
|
||||
which can be though of as the python class that represents your contract.
|
||||
``contract_name`` will be used as the name of the contract class. If
|
||||
``None`` then the name of the ``ContractFactoryClass`` will be used.
|
||||
|
||||
The ``abi`` parameter should be an array containing the ABI definition of
|
||||
the contract functions and events.
|
||||
``ContractFactoryClass`` will be used as the base Contract class.
|
||||
|
||||
The ``code`` parameter should be the full contract bytecode.
|
||||
The following arguments are accepted for contract class creation.
|
||||
|
||||
The ``code_runtime`` parameter should be the runtime part of the contract bytecode.
|
||||
|
||||
The ``source`` parameter should be a string containing the full source code
|
||||
of the contract.
|
||||
- ``abi``
|
||||
- ``asm``
|
||||
- ``ast``
|
||||
- ``bytecode``
|
||||
- ``bytecode_runtime``
|
||||
- ``clone_bin``
|
||||
- ``dev_doc``
|
||||
- ``interface``
|
||||
- ``metadata``
|
||||
- ``opcodes``
|
||||
- ``src_map``
|
||||
- ``src_map_runtime``
|
||||
- ``user_doc``
|
||||
|
||||
See :doc:`./contracts` for more information about how to use contracts.
|
||||
|
||||
@ -74,8 +74,8 @@ def MATH_ABI():
|
||||
def MathContract(web3, MATH_ABI, MATH_CODE, MATH_RUNTIME, MATH_SOURCE):
|
||||
return web3.eth.contract(
|
||||
abi=MATH_ABI,
|
||||
code=MATH_CODE,
|
||||
code_runtime=MATH_RUNTIME,
|
||||
bytecode=MATH_CODE,
|
||||
bytecode_runtime=MATH_RUNTIME,
|
||||
source=MATH_SOURCE,
|
||||
)
|
||||
|
||||
@ -114,8 +114,8 @@ def SimpleConstructorContract(web3,
|
||||
SIMPLE_CONSTRUCTOR_ABI):
|
||||
return web3.eth.contract(
|
||||
abi=SIMPLE_CONSTRUCTOR_ABI,
|
||||
code=SIMPLE_CONSTRUCTOR_CODE,
|
||||
code_runtime=SIMPLE_CONSTRUCTOR_RUNTIME,
|
||||
bytecode=SIMPLE_CONSTRUCTOR_CODE,
|
||||
bytecode_runtime=SIMPLE_CONSTRUCTOR_RUNTIME,
|
||||
source=SIMPLE_CONSTRUCTOR_SOURCE,
|
||||
)
|
||||
|
||||
@ -155,8 +155,8 @@ def WithConstructorArgumentsContract(web3,
|
||||
WITH_CONSTRUCTOR_ARGUMENTS_ABI):
|
||||
return web3.eth.contract(
|
||||
abi=WITH_CONSTRUCTOR_ARGUMENTS_ABI,
|
||||
code=WITH_CONSTRUCTOR_ARGUMENTS_CODE,
|
||||
code_runtime=WITH_CONSTRUCTOR_ARGUMENTS_RUNTIME,
|
||||
bytecode=WITH_CONSTRUCTOR_ARGUMENTS_CODE,
|
||||
bytecode_runtime=WITH_CONSTRUCTOR_ARGUMENTS_RUNTIME,
|
||||
source=WITH_CONSTRUCTOR_ARGUMENTS_SOURCE,
|
||||
)
|
||||
|
||||
@ -195,8 +195,8 @@ def WithConstructorAddressArgumentsContract(web3,
|
||||
WITH_CONSTRUCTOR_ADDRESS_ABI):
|
||||
return web3.eth.contract(
|
||||
abi=WITH_CONSTRUCTOR_ADDRESS_ABI,
|
||||
code=WITH_CONSTRUCTOR_ADDRESS_CODE,
|
||||
code_runtime=WITH_CONSTRUCTOR_ADDRESS_RUNTIME,
|
||||
bytecode=WITH_CONSTRUCTOR_ADDRESS_CODE,
|
||||
bytecode_runtime=WITH_CONSTRUCTOR_ADDRESS_RUNTIME,
|
||||
source=WITH_CONSTRUCTOR_ADDRESS_SOURCE,
|
||||
)
|
||||
|
||||
@ -255,8 +255,8 @@ def STRING_ABI():
|
||||
@pytest.fixture()
|
||||
def STRING_CONTRACT(STRING_SOURCE, STRING_CODE, STRING_RUNTIME, STRING_ABI):
|
||||
return {
|
||||
'code': STRING_CODE,
|
||||
'code_runtime': STRING_RUNTIME,
|
||||
'bytecode': STRING_CODE,
|
||||
'bytecode_runtime': STRING_RUNTIME,
|
||||
'abi': STRING_ABI,
|
||||
'source': STRING_SOURCE,
|
||||
}
|
||||
@ -382,8 +382,8 @@ def EMITTER(EMITTER_CODE,
|
||||
EMITTER_ABI,
|
||||
EMITTER_SOURCE):
|
||||
return {
|
||||
'code': EMITTER_CODE,
|
||||
'code_runtime': EMITTER_RUNTIME,
|
||||
'bytecode': EMITTER_CODE,
|
||||
'bytecode_runtime': EMITTER_RUNTIME,
|
||||
'source': EMITTER_SOURCE,
|
||||
'abi': EMITTER_ABI,
|
||||
}
|
||||
@ -404,8 +404,8 @@ def emitter(web3_empty, Emitter, wait_for_transaction, wait_for_block):
|
||||
deploy_receipt = wait_for_transaction(web3, deploy_txn_hash)
|
||||
contract_address = deploy_receipt['contractAddress']
|
||||
|
||||
code = web3.eth.getCode(contract_address)
|
||||
assert code == Emitter.code_runtime
|
||||
bytecode = web3.eth.getCode(contract_address)
|
||||
assert bytecode == Emitter.bytecode_runtime
|
||||
return Emitter(address=contract_address)
|
||||
|
||||
|
||||
|
||||
@ -7,14 +7,14 @@ def test_class_construction_sets_class_vars(web3, MATH_ABI, MATH_CODE,
|
||||
MATH_RUNTIME, MATH_SOURCE):
|
||||
MathContract = web3.eth.contract(
|
||||
abi=MATH_ABI,
|
||||
code=MATH_CODE,
|
||||
code_runtime=MATH_RUNTIME,
|
||||
bytecode=MATH_CODE,
|
||||
bytecode_runtime=MATH_RUNTIME,
|
||||
source=MATH_SOURCE,
|
||||
)
|
||||
|
||||
assert MathContract.web3 == web3
|
||||
assert MathContract.code == MATH_CODE
|
||||
assert MathContract.code_runtime == MATH_RUNTIME
|
||||
assert MathContract.bytecode == MATH_CODE
|
||||
assert MathContract.bytecode_runtime == MATH_RUNTIME
|
||||
assert MathContract.source == MATH_SOURCE
|
||||
|
||||
|
||||
|
||||
@ -15,8 +15,8 @@ def math_contract(web3, MATH_ABI, MATH_CODE, MATH_RUNTIME, MATH_SOURCE,
|
||||
wait_for_transaction):
|
||||
MathContract = web3.eth.contract(
|
||||
abi=MATH_ABI,
|
||||
code=MATH_CODE,
|
||||
code_runtime=MATH_RUNTIME,
|
||||
bytecode=MATH_CODE,
|
||||
bytecode_runtime=MATH_RUNTIME,
|
||||
source=MATH_SOURCE,
|
||||
)
|
||||
deploy_txn = MathContract.deploy({'from': web3.eth.coinbase})
|
||||
|
||||
@ -23,8 +23,8 @@ def emitter(web3, Emitter, wait_for_transaction, wait_for_block):
|
||||
deploy_receipt = wait_for_transaction(web3, deploy_txn_hash)
|
||||
contract_address = deploy_receipt['contractAddress']
|
||||
|
||||
code = web3.eth.getCode(contract_address)
|
||||
assert code == Emitter.code_runtime
|
||||
bytecode = web3.eth.getCode(contract_address)
|
||||
assert bytecode == Emitter.bytecode_runtime
|
||||
return Emitter(address=contract_address)
|
||||
|
||||
|
||||
|
||||
97
tests/contracts/test_legacy_constructor_adapter.py
Normal file
97
tests/contracts/test_legacy_constructor_adapter.py
Normal file
@ -0,0 +1,97 @@
|
||||
import pytest
|
||||
import warnings
|
||||
import sys
|
||||
|
||||
from web3.contract import (
|
||||
Contract,
|
||||
)
|
||||
|
||||
|
||||
ABI = [
|
||||
{
|
||||
"constant": False,
|
||||
"inputs": [],
|
||||
"name": "func_1",
|
||||
"outputs": [],
|
||||
"type": "function",
|
||||
},
|
||||
]
|
||||
|
||||
ADDRESS = '0x0000000000000000000000000000000000000000'
|
||||
|
||||
|
||||
class ContactClassForTest(Contract):
|
||||
web3 = True
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'args,kwargs,expected',
|
||||
(
|
||||
((ABI,), {}, {'abi': ABI}),
|
||||
((ABI,), {'abi': ABI}, TypeError),
|
||||
((ABI, ADDRESS), {}, {'abi': ABI, 'address': ADDRESS}),
|
||||
(
|
||||
(ABI, ADDRESS),
|
||||
{'code': '0x1', 'code_runtime': '0x2'},
|
||||
{'abi': ABI, 'address': ADDRESS, 'bytecode': '0x1', 'bytecode_runtime': '0x2'}),
|
||||
(
|
||||
(ABI, ADDRESS, '0x1', '0x2', '0x3'),
|
||||
{},
|
||||
{'abi': ABI, 'address': ADDRESS, 'bytecode': '0x1', 'bytecode_runtime': '0x2', 'source': '0x3'},
|
||||
),
|
||||
(
|
||||
tuple(),
|
||||
{'abi': ABI, 'address': ADDRESS, 'code': '0x1', 'code_runtime': '0x2', 'source': '0x3'},
|
||||
{'abi': ABI, 'address': ADDRESS, 'bytecode': '0x1', 'bytecode_runtime': '0x2', 'source': '0x3'},
|
||||
),
|
||||
((ABI, ADDRESS), {'abi': ABI}, TypeError),
|
||||
((ABI, ADDRESS), {'address': ADDRESS}, TypeError),
|
||||
((ADDRESS,), {}, {'address': ADDRESS}),
|
||||
)
|
||||
)
|
||||
def test_process_legacy_constructor_signature(args, kwargs, expected):
|
||||
|
||||
if isinstance(expected, type) and issubclass(expected, Exception):
|
||||
with pytest.raises(expected):
|
||||
ContactClassForTest(*args, **kwargs)
|
||||
return
|
||||
|
||||
actual = ContactClassForTest(*args, **kwargs)
|
||||
for key, value in expected.items():
|
||||
assert getattr(actual, key) == value
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.version_info.major == 2, reason="Python2 fails weirdly on this test")
|
||||
def test_deprecated_properties():
|
||||
instance = ContactClassForTest(ABI, ADDRESS, '0x1', '0x2', source='0x3')
|
||||
|
||||
with pytest.warns(DeprecationWarning):
|
||||
instance.source
|
||||
|
||||
with pytest.warns(DeprecationWarning):
|
||||
instance.code
|
||||
|
||||
with pytest.warns(DeprecationWarning):
|
||||
instance.code_runtime
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.version_info.major == 2, reason="Python2 fails weirdly on this test")
|
||||
def test_deprecated_instantiation():
|
||||
with pytest.warns(Warning) as record:
|
||||
ContactClassForTest(ADDRESS)
|
||||
ContactClassForTest(address=ADDRESS)
|
||||
warnings.warn(Warning('test'))
|
||||
|
||||
assert len(record) == 1
|
||||
|
||||
with pytest.warns(DeprecationWarning):
|
||||
ContactClassForTest() # no address
|
||||
|
||||
with pytest.warns(DeprecationWarning):
|
||||
ContactClassForTest(ABI, ADDRESS) # no address
|
||||
|
||||
with pytest.warns(DeprecationWarning):
|
||||
ContactClassForTest(ABI) # no address
|
||||
|
||||
with pytest.warns(DeprecationWarning):
|
||||
ContactClassForTest(code='0x1') # no address
|
||||
8
tests/empty-object/test_empty_object_is_falsy.py
Normal file
8
tests/empty-object/test_empty_object_is_falsy.py
Normal file
@ -0,0 +1,8 @@
|
||||
from web3.utils.empty import (
|
||||
empty,
|
||||
)
|
||||
|
||||
|
||||
def test_empty_object_is_falsy():
|
||||
assert bool(empty) is False
|
||||
assert not empty
|
||||
@ -15,8 +15,8 @@ def math_contract(web3, MATH_ABI, MATH_CODE, MATH_RUNTIME, MATH_SOURCE,
|
||||
wait_for_transaction):
|
||||
MathContract = web3.eth.contract(
|
||||
abi=MATH_ABI,
|
||||
code=MATH_CODE,
|
||||
code_runtime=MATH_RUNTIME,
|
||||
bytecode=MATH_CODE,
|
||||
bytecode_runtime=MATH_RUNTIME,
|
||||
source=MATH_SOURCE,
|
||||
)
|
||||
deploy_txn = MathContract.deploy({'from': web3.eth.coinbase})
|
||||
|
||||
@ -123,8 +123,8 @@ def EMITTER(EMITTER_CODE,
|
||||
EMITTER_ABI,
|
||||
EMITTER_SOURCE):
|
||||
return {
|
||||
'code': EMITTER_CODE,
|
||||
'code_runtime': EMITTER_RUNTIME,
|
||||
'bytecode': EMITTER_CODE,
|
||||
'bytecode_runtime': EMITTER_RUNTIME,
|
||||
'source': EMITTER_SOURCE,
|
||||
'abi': EMITTER_ABI,
|
||||
}
|
||||
@ -142,8 +142,8 @@ def emitter(web3, Emitter, wait_for_transaction, wait_for_block):
|
||||
deploy_receipt = wait_for_transaction(web3, deploy_txn_hash)
|
||||
contract_address = deploy_receipt['contractAddress']
|
||||
|
||||
code = web3.eth.getCode(contract_address)
|
||||
assert code == Emitter.code_runtime
|
||||
bytecode = web3.eth.getCode(contract_address)
|
||||
assert bytecode == Emitter.bytecode_runtime
|
||||
return Emitter(address=contract_address)
|
||||
|
||||
|
||||
|
||||
230
web3/contract.py
230
web3/contract.py
@ -2,6 +2,8 @@
|
||||
|
||||
"""
|
||||
import functools
|
||||
import warnings
|
||||
import itertools
|
||||
|
||||
from eth_abi import (
|
||||
encode_abi,
|
||||
@ -16,23 +18,8 @@ from web3.exceptions import (
|
||||
BadFunctionCallOutput,
|
||||
)
|
||||
|
||||
from web3.utils.encoding import (
|
||||
encode_hex,
|
||||
)
|
||||
from web3.utils.exception import (
|
||||
raise_from,
|
||||
)
|
||||
from web3.utils.formatting import (
|
||||
add_0x_prefix,
|
||||
remove_0x_prefix,
|
||||
)
|
||||
from web3.utils.string import (
|
||||
force_bytes,
|
||||
coerce_return_to_text,
|
||||
force_obj_to_bytes,
|
||||
)
|
||||
from web3.utils.functional import (
|
||||
compose,
|
||||
from web3.utils.address import (
|
||||
is_address,
|
||||
)
|
||||
from web3.utils.abi import (
|
||||
filter_by_type,
|
||||
@ -51,13 +38,45 @@ from web3.utils.abi import (
|
||||
from web3.utils.decorators import (
|
||||
combomethod,
|
||||
)
|
||||
from web3.utils.empty import (
|
||||
empty,
|
||||
)
|
||||
from web3.utils.encoding import (
|
||||
encode_hex,
|
||||
)
|
||||
from web3.utils.events import (
|
||||
get_event_data,
|
||||
)
|
||||
from web3.utils.exception import (
|
||||
raise_from,
|
||||
)
|
||||
from web3.utils.filters import (
|
||||
construct_event_filter_params,
|
||||
PastLogFilter,
|
||||
)
|
||||
from web3.utils.formatting import (
|
||||
add_0x_prefix,
|
||||
remove_0x_prefix,
|
||||
)
|
||||
from web3.utils.functional import (
|
||||
compose,
|
||||
)
|
||||
from web3.utils.string import (
|
||||
force_bytes,
|
||||
coerce_return_to_text,
|
||||
force_obj_to_bytes,
|
||||
)
|
||||
from web3.utils.types import (
|
||||
is_array,
|
||||
)
|
||||
|
||||
|
||||
DEPRECATED_SIGNATURE_MESSAGE = (
|
||||
"The constructor signature for the `Contract` object has changed. "
|
||||
"Please update your code to reflect the updated function signature: "
|
||||
"'Contract(address)'. To construct contract classes use the "
|
||||
"'Contract.factory(...)' class methog."
|
||||
)
|
||||
|
||||
|
||||
class Contract(object):
|
||||
@ -80,74 +99,160 @@ class Contract(object):
|
||||
# set during class construction
|
||||
web3 = None
|
||||
|
||||
# class properties (overridable at instance level)
|
||||
_abi = None
|
||||
_code = None
|
||||
_code_runtime = None
|
||||
_source = None
|
||||
|
||||
# instance level properties
|
||||
address = None
|
||||
|
||||
# class properties (overridable at instance level)
|
||||
abi = None
|
||||
asm = None
|
||||
ast = None
|
||||
|
||||
bytecode = None
|
||||
bytecode_runtime = None
|
||||
clone_bin = None
|
||||
|
||||
dev_doc = None
|
||||
interface = None
|
||||
metadata = None
|
||||
opcodes = None
|
||||
src_map = None
|
||||
src_map_runtime = None
|
||||
user_doc = None
|
||||
|
||||
def __init__(self,
|
||||
abi=None,
|
||||
address=None,
|
||||
code=None,
|
||||
code_runtime=None,
|
||||
source=None):
|
||||
*args,
|
||||
**kwargs):
|
||||
"""Create a new smart contract proxy object.
|
||||
|
||||
:param address: Contract address as 0x hex string
|
||||
:param abi: Override class level definition
|
||||
:param code: Override class level definition
|
||||
:param code_runtime: Override class level definition
|
||||
:param source: Override class level definition
|
||||
"""
|
||||
code = kwargs.pop('code', empty)
|
||||
code_runtime = kwargs.pop('code_runtime', empty)
|
||||
source = kwargs.pop('source', empty)
|
||||
abi = kwargs.pop('abi', empty)
|
||||
address = kwargs.pop('address', empty)
|
||||
|
||||
if self.web3 is None:
|
||||
raise AttributeError(
|
||||
'The `Contract` class has not been initialized. Please use the '
|
||||
'`web3.contract` interface to create your contract class.'
|
||||
)
|
||||
if abi is not None:
|
||||
self._abi = abi
|
||||
if code is not None:
|
||||
self._code = code
|
||||
if code_runtime is not None:
|
||||
self._code_runtime = code_runtime
|
||||
if source is not None:
|
||||
|
||||
arg_0, arg_1, arg_2, arg_3, arg_4 = tuple(itertools.chain(
|
||||
args,
|
||||
itertools.repeat(empty, 5),
|
||||
))[:5]
|
||||
|
||||
if is_array(arg_0):
|
||||
if abi:
|
||||
raise TypeError("The 'abi' argument was found twice")
|
||||
abi = arg_0
|
||||
elif is_address(arg_0):
|
||||
if address:
|
||||
raise TypeError("The 'address' argument was found twice")
|
||||
address = arg_0
|
||||
|
||||
if is_address(arg_1):
|
||||
if address:
|
||||
raise TypeError("The 'address' argument was found twice")
|
||||
address = arg_1
|
||||
|
||||
if arg_2 is not empty:
|
||||
if code:
|
||||
raise TypeError("The 'code' argument was found twice")
|
||||
code = arg_2
|
||||
|
||||
if arg_3 is not empty:
|
||||
if code_runtime:
|
||||
raise TypeError("The 'code_runtime' argument was found twice")
|
||||
code_runtime = arg_3
|
||||
|
||||
if arg_4 is not empty:
|
||||
if source:
|
||||
raise TypeError("The 'source' argument was found twice")
|
||||
source = arg_4
|
||||
|
||||
if any((abi, code, code_runtime, source)):
|
||||
warnings.warn(DeprecationWarning(
|
||||
"The arguments abi, code, code_runtime, and source have been "
|
||||
"deprecated and will be removed from the Contract class "
|
||||
"constructor in future releases. Update your code to use the "
|
||||
"Contract.factory method."
|
||||
))
|
||||
|
||||
if abi is not empty:
|
||||
self.abi = abi
|
||||
if code is not empty:
|
||||
self.bytecode = code
|
||||
if code_runtime is not empty:
|
||||
self.bytecode_runtime = code_runtime
|
||||
if source is not empty:
|
||||
self._source = source
|
||||
|
||||
self.address = address
|
||||
if address is not empty:
|
||||
self.address = address
|
||||
else:
|
||||
warnings.warn(DeprecationWarning(
|
||||
"The address argument is now required for contract class "
|
||||
"instantiation. Please update your code to reflect this change"
|
||||
))
|
||||
|
||||
@property
|
||||
def abi(self):
|
||||
if self._abi is not None:
|
||||
return self._abi
|
||||
# TODO: abi can be derived from the contract source.
|
||||
raise AttributeError("No contract abi was specified for thes contract")
|
||||
@classmethod
|
||||
def factory(cls, web3, contract_name=None, **kwargs):
|
||||
if contract_name is None:
|
||||
contract_name = cls.__name__
|
||||
|
||||
kwargs['web3'] = web3
|
||||
|
||||
for key in kwargs:
|
||||
if not hasattr(cls, key):
|
||||
raise AttributeError(
|
||||
"Property {0} not found on contract class. "
|
||||
"`Contract.factory` only accepts keyword arguments which are "
|
||||
"present on the contract class"
|
||||
)
|
||||
return type(contract_name, (cls,), kwargs)
|
||||
|
||||
#
|
||||
# deprecated properties
|
||||
#
|
||||
_source = None
|
||||
|
||||
@property
|
||||
def code(self):
|
||||
if self._code is not None:
|
||||
return self._code
|
||||
# TODO: code can be derived from the contract source.
|
||||
warnings.warn(DeprecationWarning(
|
||||
"The `code` property has been deprecated. You should update your "
|
||||
"code to access this value through `contract.bytecode`. The `code` "
|
||||
"property will be removed in future releases"
|
||||
))
|
||||
if self.bytecode is not None:
|
||||
return self.bytecode
|
||||
raise AttributeError("No contract code was specified for thes contract")
|
||||
|
||||
@property
|
||||
def code_runtime(self):
|
||||
if self._code_runtime is not None:
|
||||
return self._code_runtime
|
||||
# TODO: runtime can be derived from the contract source.
|
||||
raise AttributeError(
|
||||
"No contract code_runtime was specified for thes contract"
|
||||
)
|
||||
warnings.warn(DeprecationWarning(
|
||||
"The `code_runtime` property has been deprecated. You should update your "
|
||||
"code to access this value through `contract.bytecode_runtime`. The `code_runtime` "
|
||||
"property will be removed in future releases"
|
||||
))
|
||||
if self.bytecode_runtime is not None:
|
||||
return self.bytecode_runtime
|
||||
raise AttributeError("No contract code_runtime was specified for thes contract")
|
||||
|
||||
@property
|
||||
def source(self):
|
||||
warnings.warn(DeprecationWarning(
|
||||
"The `source` property has been deprecated and will be removed in "
|
||||
"future releases"
|
||||
))
|
||||
if self._source is not None:
|
||||
return self._source
|
||||
raise AttributeError("No contract source was specified for thes contract")
|
||||
|
||||
#
|
||||
# Contract Methods
|
||||
#
|
||||
@classmethod
|
||||
def deploy(cls, transaction=None, args=None, kwargs=None):
|
||||
"""
|
||||
@ -180,9 +285,9 @@ class Contract(object):
|
||||
else:
|
||||
deploy_transaction = dict(**transaction)
|
||||
|
||||
if not cls.code:
|
||||
if not cls.bytecode:
|
||||
raise ValueError(
|
||||
"Cannot deploy a contract that does not have 'code' associated "
|
||||
"Cannot deploy a contract that does not have 'bytecode' associated "
|
||||
"with it"
|
||||
)
|
||||
|
||||
@ -559,6 +664,8 @@ class Contract(object):
|
||||
transaction=None):
|
||||
"""
|
||||
Returns a dictionary of the transaction that could be used to call this
|
||||
TODO: make this a public API
|
||||
TODO: add new prepare_deploy_transaction API
|
||||
"""
|
||||
if transaction is None:
|
||||
prepared_transaction = {}
|
||||
@ -631,10 +738,10 @@ class Contract(object):
|
||||
arguments = merge_args_and_kwargs(constructor_abi, args, kwargs)
|
||||
|
||||
deploy_data = add_0x_prefix(
|
||||
cls._encode_abi(constructor_abi, arguments, data=cls.code)
|
||||
cls._encode_abi(constructor_abi, arguments, data=cls.bytecode)
|
||||
)
|
||||
else:
|
||||
deploy_data = add_0x_prefix(cls.code)
|
||||
deploy_data = add_0x_prefix(cls.bytecode)
|
||||
|
||||
return deploy_data
|
||||
|
||||
@ -787,6 +894,11 @@ def construct_contract_factory(web3,
|
||||
:param source: As given by solc compiler
|
||||
:return: Contract class (not instance)
|
||||
"""
|
||||
warnings.warn(DeprecationWarning(
|
||||
"This function has been deprecated. Please use the `Contract.factory` "
|
||||
"method as this function will be removed in future releases"
|
||||
))
|
||||
|
||||
_dict = {
|
||||
'web3': web3,
|
||||
'abi': abi,
|
||||
|
||||
70
web3/eth.py
70
web3/eth.py
@ -1,32 +1,38 @@
|
||||
from web3 import formatters
|
||||
from web3.iban import Iban
|
||||
|
||||
from web3.contract import (
|
||||
Contract,
|
||||
)
|
||||
|
||||
from web3.utils.blocks import (
|
||||
is_predefined_block_number,
|
||||
)
|
||||
from web3.utils.address import (
|
||||
is_address,
|
||||
)
|
||||
from web3.utils.encoding import (
|
||||
to_decimal,
|
||||
encode_hex,
|
||||
)
|
||||
from web3.utils.types import (
|
||||
is_integer,
|
||||
is_string,
|
||||
)
|
||||
from web3.utils.string import (
|
||||
coerce_return_to_text,
|
||||
)
|
||||
from web3.utils.functional import (
|
||||
apply_formatters_to_return,
|
||||
)
|
||||
from web3.utils.transactions import (
|
||||
get_buffered_gas_estimate,
|
||||
)
|
||||
from web3.utils.filters import (
|
||||
BlockFilter,
|
||||
TransactionFilter,
|
||||
LogFilter,
|
||||
)
|
||||
from web3.utils.blocks import (
|
||||
is_predefined_block_number,
|
||||
from web3.utils.functional import (
|
||||
apply_formatters_to_return,
|
||||
)
|
||||
from web3.utils.string import (
|
||||
coerce_return_to_text,
|
||||
)
|
||||
from web3.utils.transactions import (
|
||||
get_buffered_gas_estimate,
|
||||
)
|
||||
from web3.utils.types import (
|
||||
is_integer,
|
||||
is_string,
|
||||
)
|
||||
from web3.contract import construct_contract_factory
|
||||
|
||||
|
||||
class Eth(object):
|
||||
@ -42,6 +48,7 @@ class Eth(object):
|
||||
def defaultAccount(self):
|
||||
if self._defaultAccount is not None:
|
||||
return self._defaultAccount
|
||||
# TODO: deprecate defaulting to the coinbase for the from address.
|
||||
return self.coinbase
|
||||
|
||||
@defaultAccount.setter
|
||||
@ -332,13 +339,34 @@ class Eth(object):
|
||||
"eth_uninstallFilter", [filter_id],
|
||||
)
|
||||
|
||||
def contract(self, abi, address=None, **kwargs):
|
||||
contract_class = construct_contract_factory(self.web3, abi, **kwargs)
|
||||
def contract(self,
|
||||
*args,
|
||||
**kwargs):
|
||||
ContractFactoryClass = kwargs.pop('ContractFactoryClass', Contract)
|
||||
contract_name = kwargs.pop('contract_name', None)
|
||||
|
||||
if address is None:
|
||||
return contract_class
|
||||
has_address = any((
|
||||
'address' in kwargs,
|
||||
len(args) >= 1 and is_address(args[0]),
|
||||
len(args) >= 2 and is_address(args[1]),
|
||||
))
|
||||
|
||||
if has_address:
|
||||
if 'address' in kwargs:
|
||||
address = kwargs.pop('address')
|
||||
elif is_address(args[0]):
|
||||
address = args[0]
|
||||
elif is_address(args[1]):
|
||||
address = args[1]
|
||||
kwargs['abi'] = args[0]
|
||||
|
||||
return ContractFactoryClass.factory(self.web3, contract_name, **kwargs)(address)
|
||||
else:
|
||||
return contract_class(address=address)
|
||||
try:
|
||||
kwargs['abi'] = args[0]
|
||||
except IndexError:
|
||||
pass
|
||||
return ContractFactoryClass.factory(self.web3, contract_name, **kwargs)
|
||||
|
||||
def getCompilers(self):
|
||||
return self.web3._requestManager.request_blocking("eth_getCompilers", [])
|
||||
|
||||
24
web3/main.py
24
web3/main.py
@ -31,12 +31,14 @@ from web3.providers.manager import (
|
||||
PrivateKeySigningManager,
|
||||
)
|
||||
|
||||
from web3.utils.functional import (
|
||||
compose,
|
||||
from web3.utils.address import (
|
||||
is_address,
|
||||
is_checksum_address,
|
||||
to_checksum_address,
|
||||
)
|
||||
from web3.utils.string import (
|
||||
force_text,
|
||||
coerce_return_to_text,
|
||||
from web3.utils.currency import (
|
||||
to_wei,
|
||||
from_wei,
|
||||
)
|
||||
from web3.utils.encoding import (
|
||||
to_hex,
|
||||
@ -45,14 +47,12 @@ from web3.utils.encoding import (
|
||||
to_decimal,
|
||||
from_decimal,
|
||||
)
|
||||
from web3.utils.currency import (
|
||||
to_wei,
|
||||
from_wei,
|
||||
from web3.utils.functional import (
|
||||
compose,
|
||||
)
|
||||
from web3.utils.address import (
|
||||
is_address,
|
||||
is_checksum_address,
|
||||
to_checksum_address,
|
||||
from web3.utils.string import (
|
||||
force_text,
|
||||
coerce_return_to_text,
|
||||
)
|
||||
|
||||
|
||||
|
||||
9
web3/utils/empty.py
Normal file
9
web3/utils/empty.py
Normal file
@ -0,0 +1,9 @@
|
||||
class Empty(object):
|
||||
def __bool__(self):
|
||||
return False
|
||||
|
||||
def __nonzero__(self):
|
||||
return False
|
||||
|
||||
|
||||
empty = Empty()
|
||||
Loading…
Reference in New Issue
Block a user