Skip to content
This repository has been archived by the owner on Jul 9, 2021. It is now read-only.

Migrate Python libraries to v3 #2284

Merged
merged 30 commits into from
Nov 6, 2019
Merged
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
119cc57
.gitignore migrations/0x_ganache_snapshot
feuGeneA Oct 16, 2019
ed7c6bc
.gitignore new-ish Python contract wrappers
feuGeneA Oct 16, 2019
4206e6d
rm superfluous contract artifact in Python package
feuGeneA Oct 16, 2019
363363a
Eliminate circular dependency
feuGeneA Oct 18, 2019
7b5bf31
Improve output of monorepo-level parallel script
feuGeneA Oct 22, 2019
923edcd
Silence new versions of linters
feuGeneA Oct 23, 2019
1c1fc50
Support Rich Reverts via Web3.py middleware
feuGeneA Oct 28, 2019
66ce2c0
Fix bug in generated wrappers' bytes handling
feuGeneA Oct 28, 2019
606ec21
Migrate to Exchange v3
feuGeneA Oct 28, 2019
76e8f17
Fix typo in DevUtils documentation
feuGeneA Oct 28, 2019
d702890
Include new contracts in docs
feuGeneA Oct 28, 2019
a04cec5
Re-enable Python checks in CI
feuGeneA Oct 28, 2019
4b02dcc
Accept strings for bytes
feuGeneA Oct 19, 2019
3a8d2a6
Fix CircleCI build artifacts for gen'd python
feuGeneA Oct 23, 2019
348a718
Accept a provider OR a Web3 object
feuGeneA Oct 23, 2019
b2fbbe7
wrapper base: don't assume there are accounts
feuGeneA Oct 25, 2019
ea77609
Eliminate some inline linter directives
feuGeneA Oct 27, 2019
6eb5ca0
make CHANGELOGs be REVERSE chronological
feuGeneA Oct 28, 2019
bc354e3
Update CHANGELOG entries and bump version numbers
feuGeneA Oct 29, 2019
4667fc5
Merge branch 'development' into feat/3.0/python
feuGeneA Oct 29, 2019
0ef3435
@0x/contract-addresses: Put addr's in JSON, not TS
feuGeneA Oct 29, 2019
6010a0f
Merge branch 'development' into feat/3.0/python
feuGeneA Nov 2, 2019
5873b56
sra_client.py: incl. docker in `./setup.py clean`
feuGeneA Oct 19, 2019
8941145
sra_client.py: Migrate to protocol v3
feuGeneA Oct 21, 2019
8675663
abi-gen/templates/Py: clarify if/else logic
feuGeneA Nov 5, 2019
e472cee
sra_client.py: Update CHANGELOG and bump version
feuGeneA Nov 5, 2019
8d7f47f
contract_addresses/setup.py: rm unnecessary rm
feuGeneA Nov 5, 2019
6d454d1
json_schemas.py: corrections to dev dependencies
feuGeneA Nov 5, 2019
a14a4d3
In tests against deployment, also run doctests
feuGeneA Oct 29, 2019
19fac92
contract_wrappers example: rm xtra Order attribute
feuGeneA Nov 5, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 36 additions & 14 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -192,14 +192,33 @@ jobs:
working_directory: ~/repo
docker:
- image: nikolaik/python-nodejs:python3.7-nodejs8
- image: 0xorg/ganache-cli:2.2.2
- image: 0xorg/launch-kit-backend:74bcc39
- image: 0xorg/ganache-cli:4.4.0-beta.1
environment:
RPC_URL: http://localhost:8545
VERSION: 4.4.0-beta.1
SNAPSHOT_NAME: 0x_ganache_snapshot-v3-beta
- image: 0xorg/mesh:6.0.0-beta-0xv3
environment:
ETHEREUM_RPC_URL: 'http://localhost:8545'
ETHEREUM_NETWORK_ID: '50'
ETHEREUM_CHAIN_ID: '1337'
USE_BOOTSTRAP_LIST: 'true'
VERBOSITY: 3
PRIVATE_KEY_PATH: ''
BLOCK_POLLING_INTERVAL: '5s'
P2P_LISTEN_PORT: '60557'
command: |
sh -c "waitForGanache () { until printf 'POST /\r\nContent-Length: 26\r\n\r\n{\"method\":\"net_listening\"}' | nc localhost 8545 | grep true; do continue; done }; waitForGanache && ./mesh"
- image: 0xorg/launch-kit-backend:v3
environment:
RPC_URL: 'http://localhost:8545'
NETWORK_ID: 50
WHITELIST_ALL_TOKENS: True
FEE_RECIPIENT: '0x0000000000000000000000000000000000000001'
MAKER_FEE_UNIT_AMOUNT: 0
TAKER_FEE_UNIT_AMOUNT: 0
MESH_ENDPOINT: 'ws://localhost:60557'
command: |
sh -c "until printf 'POST /\r\nContent-Length: 26\r\n\r\n{\"method\":\"net_listening\"}' | nc localhost 8545 | grep true; do continue; done; node_modules/.bin/forever ts/lib/index.js"
sh -c "waitForMesh () { sleep 5; }; waitForMesh && node_modules/.bin/forever ts/lib/index.js"
steps:
- checkout
- restore_cache:
Expand All @@ -221,8 +240,14 @@ jobs:
- run:
command: |
cd python-packages
./parallel_without_sra_client coverage run setup.py test
./parallel coverage run setup.py test
./build_docs
- run:
command: |
# copy generated wrappers into contract_wrappers/build,
# JUST so CircleCI will persist them as build artifacts.
cd python-packages/contract_wrappers/src/zero_ex
for i in contract_wrappers/[^__]*/; do mkdir -p ../../build/$i; cp $i/__init__.py ../../build/$i; done
feuGeneA marked this conversation as resolved.
Show resolved Hide resolved
- save_cache:
key: coverage-python-contract-addresses-{{ .Environment.CIRCLE_SHA1 }}
paths:
Expand All @@ -247,8 +272,6 @@ jobs:
key: coverage-python-sra-client-{{ .Environment.CIRCLE_SHA1 }}
paths:
- ~/repo/python-packages/sra_client/.coverage
- store_artifacts:
path: ~/repo/python-packages/contract_wrappers/src/zero_ex/contract_wrappers/*/__init__.py
- store_artifacts:
path: ~/repo/python-packages/contract_addresses/build
- store_artifacts:
Expand Down Expand Up @@ -426,12 +449,11 @@ workflows:
- test-exchange-ganache-3.0
- test-rest
- static-tests
# - test-python:
# requires:
# - build
# - test-rest
# - static-tests-python:
# requires:
# - test-python
- test-python:
requires:
- build
- static-tests-python:
requires:
- build
# skip python tox run for now, as we don't yet have multiple test environments to support.
# - test-rest-python
10 changes: 9 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ contracts/erc1155/generated-wrappers/
contracts/extensions/generated-wrappers/
contracts/exchange-forwarder/generated-wrappers/
contracts/dev-utils/generated-wrappers/
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/dev_utils/__init__.py
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/erc20_token/__init__.py
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/exchange/__init__.py
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/asset_proxy_owner/__init__.py
Expand All @@ -138,6 +139,8 @@ python-packages/contract_wrappers/src/zero_ex/contract_wrappers/coordinator_regi
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/dummy_erc20_token/__init__.py
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/dummy_erc721_token/__init__.py
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/dutch_auction/__init__.py
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/erc1155_mintable/__init__.py
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/erc1155_proxy/__init__.py
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/erc20_proxy/__init__.py
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/erc721_proxy/__init__.py
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/erc721_token/__init__.py
Expand All @@ -148,6 +151,7 @@ python-packages/contract_wrappers/src/zero_ex/contract_wrappers/i_validator/__in
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/i_wallet/__init__.py
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/multi_asset_proxy/__init__.py
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/order_validator/__init__.py
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/static_call_proxy/__init__.py
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/weth9/__init__.py
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/zrx_token/__init__.py

Expand All @@ -164,10 +168,14 @@ __pycache__
python-packages/*/src/*.egg-info
python-packages/*/.coverage

# python keeps package-local copies of json schemas
# python keeps package-local copies of json schemas and contract addresses
python-packages/json_schemas/src/zero_ex/json_schemas/schemas
python-packages/contract_addresses/src/zero_ex/contract_addresses/addresses.json

# Doc README copy
packages/*/docs/README.md

.DS_Store

# the snapshot that gets built for migrations sure does have a ton of files
packages/migrations/0x_ganache_snapshot*
21 changes: 21 additions & 0 deletions packages/abi-gen/CHANGELOG.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,25 @@
[
{
"version": "4.5.0-beta.0",
"changes": [
{
"note": "In Python wrappers, accept string arguments to bytes parameters",
"pr": 2284
},
{
"note": "In Python wrappers, support module-local, Web3.py-compatible middleware",
"pr": 2284
},
{
"note": "In Python wrappers, allow contracts to be instantiated with EITHER a Web3.py BaseProvider OR a Web3 client object",
"pr": 2284
},
{
"note": "In Python wrappers, fix bug with casting some bytes objects using bytes.fromhex()",
"pr": 2284
}
]
},
{
"version": "4.4.0-beta.0",
"changes": [
Expand Down
2 changes: 1 addition & 1 deletion packages/abi-gen/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ export const utils = {
{ regex: '^address$', pyType: 'str' },
{ regex: '^bool$', pyType: 'bool' },
{ regex: '^u?int\\d*$', pyType: 'int' },
{ regex: '^bytes\\d*$', pyType: 'bytes' },
{ regex: '^bytes\\d*$', pyType: 'Union[bytes, str]' },
];
for (const regexAndTxType of solTypeRegexToPyType) {
const { regex, pyType } = regexAndTxType;
Expand Down
49 changes: 41 additions & 8 deletions packages/abi-gen/templates/Python/contract.handlebars
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,12 @@ except ImportError:
"""No-op input validator."""


try:
from .middleware import MIDDLEWARE # type: ignore
except ImportError:
pass


{{tupleDefinitions ABIString}}

{{#each methods}}
Expand All @@ -59,30 +65,57 @@ class {{contractName}}:

def __init__(
self,
provider: BaseProvider,
web3_or_provider: Union[Web3, BaseProvider],
contract_address: str,
validator: {{contractName}}Validator = None,
):
"""Get an instance of wrapper for smart contract.

:param provider: instance of :class:`web3.providers.base.BaseProvider`
:param web3_or_provider: Either an instance of `web3.Web3`:code: or
`web3.providers.base.BaseProvider`:code:
:param contract_address: where the contract has been deployed
:param validator: for validation of method inputs.
"""
# pylint: disable=too-many-statements

self.contract_address = contract_address

if not validator:
validator = {{contractName}}Validator(provider, contract_address)

self._web3_eth = Web3( # type: ignore # pylint: disable=no-member
provider
).eth
validator = {{contractName}}Validator(web3_or_provider, contract_address)

web3 = None
if isinstance(web3_or_provider, BaseProvider):
web3 = Web3(web3_or_provider)
elif isinstance(web3_or_provider, Web3):
web3 = web3_or_provider
else:
raise TypeError(
"Expected parameter 'web3_or_provider' to be an instance of either"
+ " Web3 or BaseProvider"
)

# if any middleware was imported, inject it
try:
MIDDLEWARE
except NameError:
pass
else:
try:
for middleware in MIDDLEWARE:
web3.middleware_onion.inject(
middleware['function'], layer=middleware['layer'],
)
except ValueError as value_error:
if value_error.args == ("You can't add the same un-named instance twice",):
pass

self._web3_eth = web3.eth

{{#if methods}}
functions = self._web3_eth.contract(address=to_checksum_address(contract_address), abi={{contractName}}.abi()).functions

{{#each methods}}
self.{{toPythonIdentifier this.languageSpecificName}} = {{toPythonClassname this.languageSpecificName}}Method(provider, contract_address, functions.{{this.name}}, validator)
self.{{toPythonIdentifier this.languageSpecificName}} = {{toPythonClassname this.languageSpecificName}}Method(web3_or_provider, contract_address, functions.{{this.name}}, validator)

{{/each}}
{{/if}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
class {{toPythonClassname this.languageSpecificName}}Method(ContractMethod):
"""Various interfaces to the {{this.name}} method."""

def __init__(self, provider: BaseProvider, contract_address: str, contract_function: ContractFunction, validator: Validator=None):
def __init__(self, web3_or_provider: Union[Web3, BaseProvider], contract_address: str, contract_function: ContractFunction, validator: Validator=None):
"""Persist instance data."""
super().__init__(provider, contract_address, validator)
super().__init__(web3_or_provider, contract_address, validator)
self.underlying_method = contract_function

{{#if inputs}}
Expand All @@ -21,13 +21,6 @@ class {{toPythonClassname this.languageSpecificName}}Method(ContractMethod):
{{else if (equal type 'uint256')}}
# safeguard against fractional inputs
{{toPythonIdentifier this.name}} = int({{toPythonIdentifier this.name}})
{{else if (equal type 'bytes')}}
{{toPythonIdentifier this.name}} = bytes.fromhex({{toPythonIdentifier this.name}}.decode("utf-8"))
{{else if (equal type 'bytes[]')}}
{{toPythonIdentifier this.name}} = [
bytes.fromhex({{toPythonIdentifier this.name}}_element.decode("utf-8"))
for {{toPythonIdentifier this.name}}_element in {{toPythonIdentifier this.name}}
]
{{/if}}
{{/each}}
return ({{> params }})
Expand Down
Loading