From 13360fb47618e0496f3fada720810946eb33bcc7 Mon Sep 17 00:00:00 2001 From: iamdefinitelyahuman Date: Sun, 28 Jul 2019 23:20:05 +0800 Subject: [PATCH 1/6] Improved verbosity when get_available_solc_versions raises --- CHANGELOG | 5 +++++ solcx/install.py | 12 ++++++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index e95483c..3ff6a03 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,8 @@ +0.4.3 (unreleased) +----- + + - Improved verbosity when get_available_solc_versions raises + 0.4.2 ----- diff --git a/solcx/install.py b/solcx/install.py index 1ada5b2..5f57fb2 100644 --- a/solcx/install.py +++ b/solcx/install.py @@ -141,10 +141,18 @@ def install_solc_pragma(pragma_string, install=True): return version -def get_available_solc_versions(headers={}): +def get_available_solc_versions(headers=None): versions = [] pattern = VERSION_REGEX[_get_platform()] - for release in requests.get(ALL_RELEASES, headers=headers).json(): + data = requests.get(ALL_RELEASES, headers=headers) + if data.status_code != 200: + raise ConnectionError( + "{} when getting solc versions from Github: '{}'".format( + data.status_code, + data.json()['message'] + ) + ) + for release in data.json(): asset = next((i for i in release['assets'] if re.match(pattern, i['name'])), False) if asset: versions.append(release['tag_name']) From 49e02bef56f5db04be8723f8eaaa3131f4ace9d4 Mon Sep 17 00:00:00 2001 From: iamdefinitelyahuman Date: Mon, 29 Jul 2019 03:38:34 +0800 Subject: [PATCH 2/6] coverage parallel builds webhook --- .travis.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.travis.yml b/.travis.yml index 94c41ec..b19d627 100644 --- a/.travis.yml +++ b/.travis.yml @@ -37,5 +37,10 @@ matrix: script: python -m pytest tests --cov=solcx after_success: python -m coveralls +env: + global: COVERALLS_PARALLEL=true + + notifications: email: false + webhooks: https://coveralls.io/webhook From a48c4f51e5083716211617b1a62dbdf5908d66bc Mon Sep 17 00:00:00 2001 From: iamdefinitelyahuman Date: Mon, 29 Jul 2019 18:08:08 +0800 Subject: [PATCH 3/6] remove interface flag, raise on clone-bin or formal in 0.5.x --- solcx/main.py | 1 - solcx/wrapper.py | 22 ++++++++++++---------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/solcx/main.py b/solcx/main.py index 2461a8b..97c65ed 100644 --- a/solcx/main.py +++ b/solcx/main.py @@ -82,7 +82,6 @@ def _parse_compiler_output(stdoutdata): "bin-runtime", "clone-bin", "devdoc", - "interface", "opcodes", "userdoc", ) diff --git a/solcx/wrapper.py b/solcx/wrapper.py index 55e430a..342e5b2 100644 --- a/solcx/wrapper.py +++ b/solcx/wrapper.py @@ -38,7 +38,6 @@ def solc_wrapper(solc_binary=None, bin_runtime=None, clone_bin=None, abi=None, - interface=None, hashes=None, userdoc=None, devdoc=None, @@ -58,6 +57,7 @@ def solc_wrapper(solc_binary=None, if version: command.append('--version') + # removed in 0.4.21 and does nothing since <0.4.11, should be removed in the future if add_std: command.append('--add-std') @@ -123,15 +123,9 @@ def solc_wrapper(solc_binary=None, if bin_runtime: command.append('--bin-runtime') - if clone_bin: - command.append('--clone-bin') - if abi: command.append('--abi') - if interface: - command.append('--interface') - if hashes: command.append('--hashes') @@ -141,9 +135,6 @@ def solc_wrapper(solc_binary=None, if devdoc: command.append('--devdoc') - if formal: - command.append('--formal') - if stdin is not None: # solc seems to expects utf-8 from stdin: # see Scanner class in Solidity source @@ -152,6 +143,17 @@ def solc_wrapper(solc_binary=None, if evm_version: command.extend(('--evm-version', evm_version)) + # only supported by 0.4.x versions + if clone_bin: + if "v0.5" in command[0]: + raise AttributeError(f"solc 0.5.x does not support the --clone-bin flag") + command.append('--clone-bin') + + if formal: + if "v0.5" in command[0]: + raise AttributeError(f"solc 0.5.x does not support the --formal flag") + command.append('--formal') + if ( not standard_json and not source_files and From e186f323cc05be3215157c16a7ac7d56daad7551 Mon Sep 17 00:00:00 2001 From: iamdefinitelyahuman Date: Mon, 29 Jul 2019 18:08:27 +0800 Subject: [PATCH 4/6] update tests, changelog --- CHANGELOG | 4 ++- tests/test_install.py | 46 ++++++++++++++++++++++++++ tests/test_wrapper.py | 75 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 124 insertions(+), 1 deletion(-) create mode 100644 tests/test_install.py create mode 100644 tests/test_wrapper.py diff --git a/CHANGELOG b/CHANGELOG index 3ff6a03..061fcf7 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,7 +1,9 @@ -0.4.3 (unreleased) +0.5.0 (unreleased) ----- - Improved verbosity when get_available_solc_versions raises + - Remove interace flag (was removed from solc in 0.4.0) + - Raise on clone-bin and formal flags when using 0.5.x 0.4.2 ----- diff --git a/tests/test_install.py b/tests/test_install.py new file mode 100644 index 0000000..4baa4ec --- /dev/null +++ b/tests/test_install.py @@ -0,0 +1,46 @@ +#!/usr/bin/python3 + +import pytest +import sys + +import solcx +from solcx.exceptions import SolcNotInstalled + + +@pytest.fixture(autouse=True) +def isolation(): + p = sys.platform + v = solcx.install.solc_version + yield + sys.platform = p + solcx.install.solc_version = v + + +def test_not_installed(): + solcx.install.get_executable() + with pytest.raises(SolcNotInstalled): + solcx.install.get_executable('v0.4.0') + solcx.install.solc_version = None + with pytest.raises(SolcNotInstalled): + solcx.install.get_executable() + + +def test_unsupported_version(): + solcx.install._check_version('0.4.11') + with pytest.raises(ValueError): + solcx.install._check_version('0.4.10') + + +def test_unknown_platform(): + sys.platform = "potatoOS" + with pytest.raises(KeyError): + solcx.install_solc('0.5.0') + + +@pytest.mark.skipif("sys.platform == 'win32'") +def test_install_osx(): + sys.platform = "darwin" + with pytest.raises(ValueError): + solcx.install_solc('0.4.25') + solcx.install_solc('0.4.25', allow_osx=True) + solcx.install_solc('0.5.4') diff --git a/tests/test_wrapper.py b/tests/test_wrapper.py new file mode 100644 index 0000000..a21f4f1 --- /dev/null +++ b/tests/test_wrapper.py @@ -0,0 +1,75 @@ +#!/usr/bin/python3 + +import subprocess +import pytest + +import solcx + + +class PopenPatch: + + def __init__(self): + self.proc = subprocess.Popen + self.args = [] + + def __call__(self, cmd, **kwargs): + assert cmd[0] == solcx.install.get_executable() + for i in self.args: + assert i in cmd + return self.proc(cmd, **kwargs) + + def expect(self, *args): + self.args = [f"--{i.replace('_', '-')}" for i in args] + + +@pytest.fixture +def popen(monkeypatch): + p = PopenPatch() + monkeypatch.setattr('subprocess.Popen', p) + yield p + + +@pytest.fixture(autouse=True) +def all_(all_versions): + pass + + +def test_help(popen): + popen.expect('help') + solcx.wrapper.solc_wrapper(help=True, success_return_code=1) + + +def test_boolean_kwargs(popen, foo_source): + kwargs = [ + 'version', 'optimize', 'gas', 'ast', 'ast_json', 'asm', 'asm_json', + 'opcodes', 'bin', 'bin_runtime', 'abi', 'hashes', 'userdoc', 'devdoc', 'standard_json' + ] + for value in kwargs: + popen.expect(value) + solcx.wrapper.solc_wrapper(stdin=foo_source, **{value: True}) + + +def test_solc4_only_kwargs(popen): + kwargs = ['clone_bin', 'formal'] + if "0.5" in solcx.get_solc_version_string(): + for value in kwargs: + popen.expect(value) + with pytest.raises(AttributeError): + solcx.wrapper.solc_wrapper(**{value: True}) + return + for value in kwargs: + popen.expect(value) + solcx.wrapper.solc_wrapper(**{value: True}) + + +def test_value_kwargs(popen, foo_source): + kwargs = [ + ('optimize_runs', 200), + ('libraries', "libraries:0x1234567890123456789012345678901234567890"), + ('output_dir', "."), + ('combined_json', "abi"), + ('allow_paths', ".") + ] + for value in kwargs: + popen.expect(value[0]) + solcx.wrapper.solc_wrapper(stdin=foo_source, **{value[0]: value[1]}) From f61c661f2269fcbff6ab91e8982dae4a5be2127b Mon Sep 17 00:00:00 2001 From: iamdefinitelyahuman Date: Tue, 30 Jul 2019 16:34:34 +0800 Subject: [PATCH 5/6] support github api tokens in get_available_solc_versions --- CHANGELOG | 3 ++- solcx/install.py | 12 +++++++++++- tests/conftest.py | 6 +----- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 061fcf7..9617bd6 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ -0.5.0 (unreleased) +0.5.0 ----- + - Support for github API tokens via environment var GITHUB_TOKEN - Improved verbosity when get_available_solc_versions raises - Remove interace flag (was removed from solc in 0.4.0) - Raise on clone-bin and formal flags when using 0.5.x diff --git a/solcx/install.py b/solcx/install.py index 5f57fb2..0aeb777 100644 --- a/solcx/install.py +++ b/solcx/install.py @@ -1,6 +1,7 @@ """ Install solc """ +from base64 import b64encode from io import BytesIO import os from pathlib import Path @@ -144,14 +145,23 @@ def install_solc_pragma(pragma_string, install=True): def get_available_solc_versions(headers=None): versions = [] pattern = VERSION_REGEX[_get_platform()] + + # Github sometimes blocks CI from calling their API, if you are having issues try + # saving an API token to the environment variable GITHUB_TOKEN in your build environment + # https://github.blog/2013-05-16-personal-api-tokens/ + if not headers and os.getenv('GITHUB_TOKEN'): + auth = b64encode(os.getenv('GITHUB_TOKEN').encode()).decode() + headers = {'Authorization': "Basic {}".format(auth)} + data = requests.get(ALL_RELEASES, headers=headers) if data.status_code != 200: raise ConnectionError( - "{} when getting solc versions from Github: '{}'".format( + "Status {} when getting solc versions from Github: '{}'".format( data.status_code, data.json()['message'] ) ) + for release in data.json(): asset = next((i for i in release['assets'] if re.match(pattern, i['name'])), False) if asset: diff --git a/tests/conftest.py b/tests/conftest.py index 2b5bfad..ab2a78d 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,7 +1,5 @@ #!/usr/bin/python3 -from base64 import b64encode -import os import pytest import sys @@ -10,9 +8,7 @@ if sys.platform == "darwin": VERSIONS = solcx.get_installed_solc_versions() else: - auth = b64encode(os.environ['GITAUTH'].encode()).decode('ascii') - headers = {'Authorization': f"Basic {auth}"} - VERSIONS = solcx.get_available_solc_versions(headers=headers) + VERSIONS = solcx.get_available_solc_versions() # auto-parametrize the all_versions fixture with all target solc versions From 1dc53f98045f9ef02b5494025de6ab15095cbcc0 Mon Sep 17 00:00:00 2001 From: iamdefinitelyahuman Date: Tue, 30 Jul 2019 16:45:26 +0800 Subject: [PATCH 6/6] bump version --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 7e7ec9d..223c63c 100644 --- a/setup.py +++ b/setup.py @@ -8,7 +8,7 @@ setup( name='py-solc-x', - version='0.4.2', + version='0.5.0', description="""Python wrapper around the solc binary with 0.5.x support""", long_description_markdown_filename='README.md', author='Ben Hauser (forked from py-solc by Piper Merriam)',