From 96d23ad5caa0c7a8d0a8dfae81b22280e75b196a Mon Sep 17 00:00:00 2001 From: iamdefinitelyahuman Date: Wed, 19 Feb 2020 13:36:19 +0400 Subject: [PATCH 1/4] update issue/pr templates, contribution guide --- .github/ISSUE_TEMPLATE.md | 14 -------------- .github/ISSUE_TEMPLATE/bug.md | 22 ++++++++++++++++++++++ .github/ISSUE_TEMPLATE/feature.md | 17 +++++++++++++++++ .github/PULL_REQUEST_TEMPLATE.md | 15 +++++++++------ CONTRIBUTING.md | 20 ++++++++++---------- 5 files changed, 58 insertions(+), 30 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE.md create mode 100644 .github/ISSUE_TEMPLATE/bug.md create mode 100644 .github/ISSUE_TEMPLATE/feature.md diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md deleted file mode 100644 index 2fc50b5..0000000 --- a/.github/ISSUE_TEMPLATE.md +++ /dev/null @@ -1,14 +0,0 @@ -# Version Info - -* `py-solc-x` Version: x.x.x -* `solc` Version: x.x.x -* Python Version: x.x.x -* OS: osx/linux/win - -## The Issue - -Please include information like: - -* full output of the error you received -* what command you ran -* the code that caused the failure diff --git a/.github/ISSUE_TEMPLATE/bug.md b/.github/ISSUE_TEMPLATE/bug.md new file mode 100644 index 0000000..875237a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug.md @@ -0,0 +1,22 @@ +--- +name: Bug Report +about: Report an error that you've encountered. +--- +### Environment information + +* `py-solc-x` Version: x.x.x +* `solc` Version: x.x.x +* Python Version: x.x.x +* OS: osx/linux/win + +### What was wrong? + +Please include information like: + +* what command you ran +* the code that caused the failure (see [this link](https://help.github.com/articles/basic-writing-and-formatting-syntax/) for help with formatting code) +* full output of the error you received + +### How can it be fixed? + +Fill this in if you know how the bug could be fixed. diff --git a/.github/ISSUE_TEMPLATE/feature.md b/.github/ISSUE_TEMPLATE/feature.md new file mode 100644 index 0000000..3ce7940 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature.md @@ -0,0 +1,17 @@ +--- +name: Feature Request +about: Request a new feature, or an improvement to existing functionality. +--- +### Overview +Provide a simple overview of what you wish to see added. Please include: + +* What you are trying to do +* Why Brownie's current functionality is inadequate to address your goal + +### Specification +Describe the syntax and semantics of how you would like to see this feature implemented. The more detailed the better! + +Remember, your feature is much more likely to be included if it does not involve any breaking changes. + +### Dependencies +Include links to any open issues that must be resolved before this feature can be implemented. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index f092a86..44d67e1 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,11 +1,14 @@ -### What was wrong / missing? +### What I did +Related issue: # +### How I did it -### How was it fixed / added? +### How to verify it +### Checklist - -#### Cute Animal Picture - -> put a cute animal picture here. +- [ ] I have confirmed that my PR passes all linting checks +- [ ] I have included test cases +- [ ] I have updated the documentation (README.md) +- [ ] I have added an entry to the changelog diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b1c94b7..7f69de7 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -6,20 +6,20 @@ To start development for py-solc-x you should begin by cloning the repo. $ git clone https://github.com/iamdefinitelyahuman/py-solc-x.git ``` -## Cute Animal Pictures +Next, ensure all dev dependencies have been installed: -All pull requests need to have a cute animal picture. This is a very important -part of the development process. +```bash +pip install -r requirements-dev.txt +``` ## Pull Requests -Pull requests are welcomed! Please try to adhere to the following. +Pull requests are welcomed! Please adhere to the following: -- code should conform to PEP8 and as well as the linting done by flake8 -- include any relevant documentation updates and test cases +- Ensure your pull request passes our linting checks (`tox -e lint`) +- Include test cases for any new functionality +- Include any relevant [documentation updates](README.md) -It's a good idea to make pull requests early on. A pull request represents the -start of a discussion, and doesn't necessarily need to be the final, finished -submission. +It's a good idea to make pull requests early on. A pull request represents the start of a discussion, and doesn't necessarily need to be the final, finished submission. -GitHub's documentation for working on pull requests is [available here](https://help.github.com/articles/about-pull-requests/). +If you are opening a work-in-progress pull request to verify that it passes CI tests, please consider [marking it as a draft](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/about-pull-requests#draft-pull-requests). From 8454ff079aa8f6bcabc0528344b45817f9778681 Mon Sep 17 00:00:00 2001 From: iamdefinitelyahuman Date: Wed, 19 Feb 2020 13:48:56 +0400 Subject: [PATCH 2/4] use tox for checks, add black and isort, update requirements and travis --- .travis.yml | 19 ++++++++----------- pyproject.toml | 20 ++++++++++++++++++++ requirements-dev.txt | 8 ++++++-- setup.cfg | 10 ++++++++++ tox.ini | 22 ++++++++++++++++++++++ 5 files changed, 66 insertions(+), 13 deletions(-) create mode 100644 pyproject.toml create mode 100644 setup.cfg create mode 100644 tox.ini diff --git a/.travis.yml b/.travis.yml index 9918d2b..cc8a85c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,9 +7,9 @@ jobs: install: - choco install python --version=3.7.4 - python -m pip install --upgrade pip - - pip3 install -r requirements-dev.txt + - pip3 install tox==3.14.2 env: PATH=/c/Python37:/c/Python37/Scripts:$PATH - script: python -m pytest tests --cov=solcx + script: tox -e tests after_success: python -m coveralls - name: "Python 3.8 on Bionic Linux" language: python @@ -19,8 +19,8 @@ jobs: - sudo add-apt-repository -y ppa:ethereum/ethereum - sudo apt-get update - sudo apt-get install -y solc - - pip install -r requirements-dev.txt - script: python -m pytest tests --cov=solcx + - pip install tox==3.14.2 + script: tox -e tests after_success: python -m coveralls - name: "Python 3.7 on Bionic Linux" language: python @@ -30,11 +30,8 @@ jobs: - sudo add-apt-repository -y ppa:ethereum/ethereum - sudo apt-get update - sudo apt-get install -y solc - - pip install -r requirements-dev.txt - - pip install flake8 - script: - - flake8 solcx/ tests/ --max-line-length=100 - - python -m pytest tests --cov=solcx + - pip install tox==3.14.2 + script: tox -e lint,tests after_success: python -m coveralls - name: "Python 3.6 on Bionic Linux" language: python @@ -44,8 +41,8 @@ jobs: - sudo add-apt-repository -y ppa:ethereum/ethereum - sudo apt-get update - sudo apt-get install -y solc - - pip install -r requirements-dev.txt - script: python -m pytest tests --cov=solcx + - pip install tox==3.14.2 + script: tox -e tests after_success: python -m coveralls env: diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..e4603ae --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,20 @@ +[tool.black] +line-length = 100 +target-version = ['py36', 'py37', 'py38'] +include = '\.pyi?$' +exclude = ''' +/( + \.eggs + | \.git + | \.hg + | \.mypy_cache + | \.tox + | \.venv + | _build + | buck-out + | build + | dist + | env + | venv +)/ +''' diff --git a/requirements-dev.txt b/requirements-dev.txt index f8b26f6..0b07b95 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,7 +1,11 @@ +black==19.10b0 coveralls==1.9.2 -pytest>=5.0.0 -pytest-cov>=2.7.1 +flake8==3.7.9 +isort==4.3.21 +pytest==5.3.2 +pytest-cov==2.8.1 semantic_version>=2.8.1,<3 +tox==3.14.2 tqdm>=4.41.0,<5.0.0 twine==1.13.0 requests>=2.19.0,<3 diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..5fe5328 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,10 @@ +[flake8] +max-line-length = 100 +ignore = E203,W503 + +[tool:isort] +force_grid_wrap = 0 +include_trailing_comma = True +line_length = 100 +multi_line_output = 3 +use_parentheses = True diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000..216f930 --- /dev/null +++ b/tox.ini @@ -0,0 +1,22 @@ +[tox] +envlist = + lint + tests +skipsdist=True + +[testenv] +passenv = + GITHUB_TOKEN +deps = -r{toxinidir}/requirements-dev.txt +basepython=python3 + +[testenv:lint] +extras=linter +commands = + black --check {toxinidir}/solcx {toxinidir}/tests + flake8 {toxinidir}/solcx {toxinidir}/tests + isort --check-only --diff --recursive {toxinidir}/solcx {toxinidir}/tests + +[testenv:tests] +commands = + python -m pytest tests --cov=solcx From 452120f4afdb19822aec0209db2fae89b191aa89 Mon Sep 17 00:00:00 2001 From: iamdefinitelyahuman Date: Wed, 19 Feb 2020 13:50:17 +0400 Subject: [PATCH 3/4] apply linting rules --- solcx/__init__.py | 24 ++--- solcx/exceptions.py | 21 +++-- solcx/install.py | 136 +++++++++++++--------------- solcx/main.py | 108 ++++++++++------------ solcx/utils/lock.py | 11 ++- solcx/utils/string.py | 26 +++--- solcx/wrapper.py | 159 +++++++++++++++------------------ tests/conftest.py | 24 ++--- tests/test_compile.py | 33 +++---- tests/test_compile_standard.py | 31 ++++--- tests/test_install.py | 31 +++---- tests/test_library_linking.py | 15 ++-- tests/test_locks.py | 11 ++- tests/test_solc_version.py | 59 ++++++------ tests/test_wrapper.py | 38 ++++---- 15 files changed, 347 insertions(+), 380 deletions(-) diff --git a/solcx/__init__.py b/solcx/__init__.py index ff267a0..f55f5f7 100644 --- a/solcx/__init__.py +++ b/solcx/__init__.py @@ -1,22 +1,22 @@ from __future__ import absolute_import -from .main import ( # noqa: F401 - get_solc_version_string, - get_solc_version, - compile_files, - compile_source, - compile_standard, - link_code, -) from .install import ( # noqa: F401 - import_installed_solc, - install_solc, - install_solc_pragma, get_available_solc_versions, get_installed_solc_versions, get_solc_folder, + import_installed_solc, + install_solc, + install_solc_pragma, set_solc_version, - set_solc_version_pragma + set_solc_version_pragma, +) +from .main import ( # noqa: F401 + compile_files, + compile_source, + compile_standard, + get_solc_version, + get_solc_version_string, + link_code, ) # check for installed version of solc diff --git a/solcx/exceptions.py b/solcx/exceptions.py index 6eb6ce6..b15e402 100644 --- a/solcx/exceptions.py +++ b/solcx/exceptions.py @@ -3,7 +3,7 @@ from .utils.string import force_text -def force_text_maybe(value, encoding='iso-8859-1'): +def force_text_maybe(value, encoding="iso-8859-1"): if value is not None: return force_text(value) @@ -19,12 +19,14 @@ def __init__(self, command, return_code, stdin_data, stdout_data, stderr_data, m self.message = message self.command = command self.return_code = return_code - self.stdin_data = force_text_maybe(stdin_data, 'utf8') - self.stderr_data = force_text_maybe(stderr_data, 'utf8') - self.stdout_data = force_text_maybe(stdout_data, 'utf8') + self.stdin_data = force_text_maybe(stdin_data, "utf8") + self.stderr_data = force_text_maybe(stderr_data, "utf8") + self.stdout_data = force_text_maybe(stdout_data, "utf8") def __str__(self): - return textwrap.dedent((""" + return textwrap.dedent( + ( + """ {s.message} > command: `{command}` > return code: `{s.return_code}` @@ -32,10 +34,11 @@ def __str__(self): {s.stdout_data} > stdout: {s.stderr_data} - """).format( - s=self, - command=' '.join(self.command), - )).strip() + """ + ).format( + s=self, command=" ".join(self.command), + ) + ).strip() class ContractsNotFound(SolcError): diff --git a/solcx/install.py b/solcx/install.py index 582594c..09577c3 100644 --- a/solcx/install.py +++ b/solcx/install.py @@ -2,13 +2,9 @@ Install solc """ import argparse -from base64 import b64encode -from io import BytesIO +import logging import os -from pathlib import Path import re -import requests -from semantic_version import Version, SimpleSpec import shutil import stat import subprocess @@ -16,15 +12,15 @@ import tarfile import tempfile import zipfile -import logging +from base64 import b64encode +from io import BytesIO +from pathlib import Path + +import requests +from semantic_version import SimpleSpec, Version -from .exceptions import ( - DownloadError, - SolcNotInstalled, -) -from .utils.lock import ( - get_process_lock -) +from .exceptions import DownloadError, SolcNotInstalled +from .utils.lock import get_process_lock try: from tqdm import tqdm @@ -37,9 +33,9 @@ MINIMAL_SOLC_VERSION = "v0.4.11" VERSION_REGEX = { - 'darwin': "solidity_[0-9].[0-9].[0-9]{1,}.tar.gz", - 'linux': "solc-static-linux", - 'win32': "solidity-windows.zip" + "darwin": "solidity_[0-9].[0-9].[0-9]{1,}.tar.gz", + "linux": "solc-static-linux", + "win32": "solidity-windows.zip", } LOGGER = logging.getLogger("solcx") @@ -49,13 +45,12 @@ def _get_platform(): - if sys.platform.startswith('linux'): + if sys.platform.startswith("linux"): return "linux" - if sys.platform in ('darwin', 'win32'): + if sys.platform in ("darwin", "win32"): return sys.platform raise KeyError( - "Unknown platform: '{}' - py-solc-x supports" - " Linux, OSX and Windows".format(sys.platform) + "Unknown platform: '{}' - py-solc-x supports" " Linux, OSX and Windows".format(sys.platform) ) @@ -65,14 +60,14 @@ def get_solc_folder(solcx_binary_path=None): elif solcx_binary_path is not None: return Path(solcx_binary_path) else: - path = Path.home().joinpath('.solcx') + path = Path.home().joinpath(".solcx") path.mkdir(exist_ok=True) return path def _import_version(path): - version = subprocess.check_output([path, '--version']).decode() - return "v" + version[version.index("Version: ")+9:version.index('+')] + version = subprocess.check_output([path, "--version"]).decode() + return "v" + version[version.index("Version: ") + 9 : version.index("+")] def import_installed_solc(solcx_binary_path=None): @@ -82,13 +77,13 @@ def import_installed_solc(solcx_binary_path=None): # copy active version of solc path_list = [] - which = subprocess.run(['which', 'solc'], stdout=subprocess.PIPE).stdout.decode().strip() + which = subprocess.run(["which", "solc"], stdout=subprocess.PIPE).stdout.decode().strip() if which: path_list.append(which) # on OSX, also copy all versions of solc from cellar if platform == "darwin": - path_list = [str(i) for i in Path('/usr/local/Cellar').glob('solidity*/**/solc')] + path_list = [str(i) for i in Path("/usr/local/Cellar").glob("solidity*/**/solc")] for path in path_list: try: @@ -96,8 +91,9 @@ def import_installed_solc(solcx_binary_path=None): assert version not in get_installed_solc_versions() except Exception: continue - copy_path = str(get_solc_folder(solcx_binary_path=solcx_binary_path) - .joinpath("solc-" + version)) + copy_path = str( + get_solc_folder(solcx_binary_path=solcx_binary_path).joinpath("solc-" + version) + ) shutil.copy(path, copy_path) try: # confirm that solc still works after being copied @@ -119,8 +115,8 @@ def get_executable(version=None, solcx_binary_path=None): solc_bin = solc_bin.joinpath("solc.exe") if not solc_bin.exists(): raise SolcNotInstalled( - "solc {} has not been installed. ".format(version) + - "Use solcx.install_solc('{}') to install.".format(version) + "solc {} has not been installed. ".format(version) + + "Use solcx.install_solc('{}') to install.".format(version) ) return str(solc_bin) @@ -136,13 +132,12 @@ def set_solc_version(version, silent=False, solcx_binary_path=None): def set_solc_version_pragma(pragma_string, silent=False, check_new=False): version = _select_pragma_version( - pragma_string, - [Version(i[1:]) for i in get_installed_solc_versions()] + pragma_string, [Version(i[1:]) for i in get_installed_solc_versions()] ) if not version: raise SolcNotInstalled( - "No compatible solc version installed. " + - "Use solcx.install_solc_version_pragma('{}') to install.".format(version) + "No compatible solc version installed. " + + "Use solcx.install_solc_version_pragma('{}') to install.".format(version) ) global solc_version solc_version = version @@ -156,8 +151,7 @@ def set_solc_version_pragma(pragma_string, silent=False, check_new=False): def install_solc_pragma(pragma_string, install=True, show_progress=False, solcx_binary_path=None): version = _select_pragma_version( - pragma_string, - [Version(i[1:]) for i in get_available_solc_versions()] + pragma_string, [Version(i[1:]) for i in get_available_solc_versions()] ) if not version: raise ValueError("Compatible solc version does not exist") @@ -173,30 +167,29 @@ def get_available_solc_versions(headers=None): # 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)} + 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( "Status {} when getting solc versions from Github: '{}'".format( - data.status_code, - data.json()['message'] + 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) + asset = next((i for i in release["assets"] if re.match(pattern, i["name"])), False) if asset: - versions.append(release['tag_name']) - if release['tag_name'] == MINIMAL_SOLC_VERSION: + versions.append(release["tag_name"]) + if release["tag_name"] == MINIMAL_SOLC_VERSION: break return versions def _select_pragma_version(pragma_string, version_list): - comparator_set_range = pragma_string.replace(" ", "").split('||') + comparator_set_range = pragma_string.replace(" ", "").split("||") comparator_regex = re.compile(r"(([<>]?=?|\^)\d+\.\d+\.\d+)+") version = None @@ -210,8 +203,9 @@ def _select_pragma_version(pragma_string, version_list): def get_installed_solc_versions(solcx_binary_path=None): - return sorted(i.name[5:] for i in get_solc_folder(solcx_binary_path=solcx_binary_path) - .glob('solc-v*')) + return sorted( + i.name[5:] for i in get_solc_folder(solcx_binary_path=solcx_binary_path).glob("solc-v*") + ) def install_solc(version, allow_osx=False, show_progress=False, solcx_binary_path=None): @@ -226,16 +220,16 @@ def install_solc(version, allow_osx=False, show_progress=False, solcx_binary_pat return install_solc(version, allow_osx) try: - if platform == 'linux': + if platform == "linux": _install_solc_linux(version, show_progress, solcx_binary_path) - elif platform == 'darwin': + elif platform == "darwin": _install_solc_osx(version, allow_osx, show_progress, solcx_binary_path) - elif platform == 'win32': + elif platform == "win32": _install_solc_windows(version, show_progress, solcx_binary_path) binary_path = get_executable(version, solcx_binary_path) _check_subprocess_call( - [binary_path, '--version'], - message="Checking installed executable version @ {}".format(binary_path) + [binary_path, "--version"], + message="Checking installed executable version @ {}".format(binary_path), ) if not solc_version: set_solc_version(version) @@ -245,8 +239,8 @@ def install_solc(version, allow_osx=False, show_progress=False, solcx_binary_pat def _check_version(version): - version = Version(version.lstrip('v')) - if version not in SimpleSpec('>=0.4.11'): + version = Version(version.lstrip("v")) + if version not in SimpleSpec(">=0.4.11"): raise ValueError("py-solc-x does not support solc versions <0.4.11") return "v" + str(version) @@ -257,9 +251,7 @@ def _check_subprocess_call(command, message=None, verbose=False, **proc_kwargs): LOGGER.info("Executing: {0}".format(" ".join(command))) return subprocess.check_call( - command, - stderr=subprocess.STDOUT if verbose else subprocess.DEVNULL, - **proc_kwargs + command, stderr=subprocess.STDOUT if verbose else subprocess.DEVNULL, **proc_kwargs ) @@ -276,7 +268,7 @@ def _check_for_installed_version(version, solcx_binary_path=None): def _get_temp_folder(): - path = Path(tempfile.gettempdir()).joinpath('solcx-tmp-{}'.format(os.getpid())) + path = Path(tempfile.gettempdir()).joinpath("solcx-tmp-{}".format(os.getpid())) if path.exists(): shutil.rmtree(str(path)) path.mkdir() @@ -289,8 +281,8 @@ def _download_solc(url, show_progress): content = response.content else: response = requests.get(url, stream=True) - total_size = int(response.headers.get('content-length', 0)) - progress_bar = tqdm(total=total_size, unit='iB', unit_scale=True) + total_size = int(response.headers.get("content-length", 0)) + progress_bar = tqdm(total=total_size, unit="iB", unit_scale=True) content = bytes() for data in response.iter_content(1024, decode_unicode=True): @@ -301,8 +293,7 @@ def _download_solc(url, show_progress): if response.status_code != 200: raise DownloadError( "Received status code {} when attempting to download from {}".format( - response.status_code, - url + response.status_code, url ) ) return content @@ -314,7 +305,7 @@ def _install_solc_linux(version, show_progress, solcx_binary_path=None): if binary_path: LOGGER.info("Downloading solc {} from {}".format(version, download)) content = _download_solc(download, show_progress) - with open(binary_path, 'wb') as fp: + with open(binary_path, "wb") as fp: fp.write(content) _chmod_plus_x(binary_path) @@ -327,8 +318,9 @@ def _install_solc_windows(version, show_progress, solcx_binary_path=None): content = _download_solc(download, show_progress) with zipfile.ZipFile(BytesIO(content)) as zf: zf.extractall(str(temp_path)) - install_folder = get_solc_folder(solcx_binary_path=solcx_binary_path)\ - .joinpath("solc-" + version) + install_folder = get_solc_folder(solcx_binary_path=solcx_binary_path).joinpath( + "solc-" + version + ) temp_path.rename(install_folder) @@ -349,23 +341,23 @@ def _install_solc_osx(version, allow_osx, show_progress, solcx_binary_path): content = _download_solc(download, show_progress) with tarfile.open(fileobj=BytesIO(content)) as tar: tar.extractall(temp_path) - temp_path = temp_path.joinpath('solidity_{}'.format(version[1:])) + temp_path = temp_path.joinpath("solidity_{}".format(version[1:])) try: _check_subprocess_call( - ["sh", str(temp_path.joinpath('scripts/install_deps.sh'))], - message="Running dependency installation script `install_deps.sh`" + ["sh", str(temp_path.joinpath("scripts/install_deps.sh"))], + message="Running dependency installation script `install_deps.sh`", ) except subprocess.CalledProcessError as e: LOGGER.warning(e, exc_info=True) original_path = os.getcwd() - temp_path.joinpath('build').mkdir(exist_ok=True) - os.chdir(str(temp_path.joinpath('build').resolve())) + temp_path.joinpath("build").mkdir(exist_ok=True) + os.chdir(str(temp_path.joinpath("build").resolve())) try: for cmd in (["cmake", ".."], ["make"]): _check_subprocess_call(cmd, message="Running {}".format(cmd[0])) - temp_path.joinpath('build/solc/solc').rename(binary_path) + temp_path.joinpath("build/solc/solc").rename(binary_path) except subprocess.CalledProcessError as e: raise OSError( "{} returned non-zero exit status {} while attempting to build solc from the source. " @@ -382,7 +374,7 @@ def _install_solc_osx(version, allow_osx, show_progress, solcx_binary_path): if __name__ == "__main__": argument_parser = argparse.ArgumentParser() - argument_parser.add_argument('version') - argument_parser.add_argument('--solcx-binary-path', default=None) + argument_parser.add_argument("version") + argument_parser.add_argument("--solcx-binary-path", default=None) args = argument_parser.parse_args() install_solc(args.version, solcx_binary_path=args.solcx_binary_path) diff --git a/solcx/main.py b/solcx/main.py index c2739a1..ad21b40 100644 --- a/solcx/main.py +++ b/solcx/main.py @@ -4,24 +4,17 @@ import json import re -from .exceptions import ( - SolcError, - ContractsNotFound, -) - -from .utils.filesystem import ( - is_executable_available, -) -from .wrapper import solc_wrapper - -from .install import get_executable - import semantic_version +from .exceptions import ContractsNotFound, SolcError +from .install import get_executable +from .utils.filesystem import is_executable_available +from .wrapper import solc_wrapper -VERSION_DEV_DATE_MANGLER_RE = re.compile(r'(\d{4})\.0?(\d{1,2})\.0?(\d{1,2})') -strip_zeroes_from_month_and_day = functools.partial(VERSION_DEV_DATE_MANGLER_RE.sub, - r'\g<1>.\g<2>.\g<3>') +VERSION_DEV_DATE_MANGLER_RE = re.compile(r"(\d{4})\.0?(\d{1,2})\.0?(\d{1,2})") +strip_zeroes_from_month_and_day = functools.partial( + VERSION_DEV_DATE_MANGLER_RE.sub, r"\g<1>.\g<2>.\g<3>" +) def is_solc_available(): @@ -30,10 +23,10 @@ def is_solc_available(): def get_solc_version_string(**kwargs): - kwargs['version'] = True + kwargs["version"] = True stdoutdata, stderrdata, command, proc = solc_wrapper(**kwargs) - _, _, version_string = stdoutdata.partition('\n') - if not version_string or not version_string.startswith('Version: '): + _, _, version_string = stdoutdata.partition("\n") + if not version_string or not version_string.startswith("Version: "): raise SolcError( command=command, return_code=proc.returncode, @@ -49,27 +42,27 @@ def get_solc_version(**kwargs): # semantic_version as of 2017-5-5 expects only one + to be used in string return semantic_version.Version( strip_zeroes_from_month_and_day( - get_solc_version_string(**kwargs) - [len('Version: '):] - .replace('++', 'pp'))) + get_solc_version_string(**kwargs)[len("Version: ") :].replace("++", "pp") + ) + ) def solc_supports_standard_json_interface(**kwargs): - return get_solc_version() in semantic_version.SimpleSpec('>=0.4.11') + return get_solc_version() in semantic_version.SimpleSpec(">=0.4.11") def _parse_compiler_output(stdoutdata): output = json.loads(stdoutdata) - contracts = output.get('contracts', {}) - sources = output.get('sources', {}) + contracts = output.get("contracts", {}) + sources = output.get("sources", {}) for path_str, data in contracts.items(): - if 'abi' in data: - data['abi'] = json.loads(data['abi']) - key = path_str.rsplit(':', maxsplit=1)[0] - if 'AST' in sources.get(key, {}): - data['ast'] = sources[key]['AST'] + if "abi" in data: + data["abi"] = json.loads(data["abi"]) + key = path_str.rsplit(":", maxsplit=1)[0] + if "AST" in sources.get(key, {}): + data["ast"] = sources[key]["AST"] return contracts @@ -87,20 +80,15 @@ def _parse_compiler_output(stdoutdata): ) -def compile_source(source, - allow_empty=False, - output_values=ALL_OUTPUT_VALUES, - **kwargs): - if 'stdin' in kwargs: - raise ValueError( - "The `stdin` keyword is not allowed in the `compile_source` function" - ) - if 'combined_json' in kwargs: +def compile_source(source, allow_empty=False, output_values=ALL_OUTPUT_VALUES, **kwargs): + if "stdin" in kwargs: + raise ValueError("The `stdin` keyword is not allowed in the `compile_source` function") + if "combined_json" in kwargs: raise ValueError( "The `combined_json` keyword is not allowed in the `compile_source` function" ) - combined_json = ','.join(output_values) + combined_json = ",".join(output_values) compiler_kwargs = dict(stdin=source, combined_json=combined_json, **kwargs) stdoutdata, stderrdata, command, proc = solc_wrapper(**compiler_kwargs) @@ -118,16 +106,13 @@ def compile_source(source, return contracts -def compile_files(source_files, - allow_empty=False, - output_values=ALL_OUTPUT_VALUES, - **kwargs): - if 'combined_json' in kwargs: +def compile_files(source_files, allow_empty=False, output_values=ALL_OUTPUT_VALUES, **kwargs): + if "combined_json" in kwargs: raise ValueError( "The `combined_json` keyword is not allowed in the `compile_files` function" ) - combined_json = ','.join(output_values) + combined_json = ",".join(output_values) compiler_kwargs = dict(source_files=source_files, combined_json=combined_json, **kwargs) stdoutdata, stderrdata, command, proc = solc_wrapper(**compiler_kwargs) @@ -146,7 +131,7 @@ def compile_files(source_files, def compile_standard(input_data, allow_empty=False, **kwargs): - if not input_data.get('sources') and not allow_empty: + if not input_data.get("sources") and not allow_empty: raise ContractsNotFound( command=None, return_code=None, @@ -156,20 +141,20 @@ def compile_standard(input_data, allow_empty=False, **kwargs): ) stdoutdata, stderrdata, command, proc = solc_wrapper( - stdin=json.dumps(input_data), - standard_json=True, - **kwargs + stdin=json.dumps(input_data), standard_json=True, **kwargs ) compiler_output = json.loads(stdoutdata) - if 'errors' in compiler_output: - has_errors = any(error['severity'] == 'error' for error in compiler_output['errors']) + if "errors" in compiler_output: + has_errors = any(error["severity"] == "error" for error in compiler_output["errors"]) if has_errors: - error_message = "\n".join(tuple( - error['formattedMessage'] - for error in compiler_output['errors'] - if error['severity'] == 'error' - )) + error_message = "\n".join( + tuple( + error["formattedMessage"] + for error in compiler_output["errors"] + if error["severity"] == "error" + ) + ) raise SolcError( command, proc.returncode, @@ -182,14 +167,11 @@ def compile_standard(input_data, allow_empty=False, **kwargs): def link_code(unlinked_bytecode, libraries): - libraries_arg = ','.join(( - ':'.join((lib_name, lib_address)) - for lib_name, lib_address in libraries.items() - )) + libraries_arg = ",".join( + (":".join((lib_name, lib_address)) for lib_name, lib_address in libraries.items()) + ) stdoutdata, stderrdata, _, _ = solc_wrapper( - stdin=unlinked_bytecode, - link=True, - libraries=libraries_arg, + stdin=unlinked_bytecode, link=True, libraries=libraries_arg, ) return stdoutdata.replace("Linking completed.", "").strip() diff --git a/solcx/utils/lock.py b/solcx/utils/lock.py index ad6aa13..d22c5ad 100644 --- a/solcx/utils/lock.py +++ b/solcx/utils/lock.py @@ -1,14 +1,16 @@ import os -from pathlib import Path import sys import tempfile import threading +from pathlib import Path if sys.platform == "win32": import msvcrt + OPEN_MODE = os.O_RDWR | os.O_CREAT | os.O_TRUNC else: import fcntl + NON_BLOCKING = fcntl.LOCK_EX | fcntl.LOCK_NB BLOCKING = fcntl.LOCK_EX @@ -27,11 +29,10 @@ def get_process_lock(lock_id): class _ProcessLock: - def __init__(self, lock_id): self._lock = threading.Lock() - self._lock_path = Path(tempfile.gettempdir()).joinpath(f'.solcx-lock-{lock_id}') - self._lock_file = self._lock_path.open('w') + self._lock_path = Path(tempfile.gettempdir()).joinpath(f".solcx-lock-{lock_id}") + self._lock_file = self._lock_path.open("w") def wait(self): self.acquire(True) @@ -39,7 +40,6 @@ def wait(self): class UnixLock(_ProcessLock): - def acquire(self, blocking): if not self._lock.acquire(blocking): return False @@ -56,7 +56,6 @@ def release(self): class WindowsLock(_ProcessLock): - def acquire(self, blocking): if not self._lock.acquire(blocking): return False diff --git a/solcx/utils/string.py b/solcx/utils/string.py index 857870a..c584835 100644 --- a/solcx/utils/string.py +++ b/solcx/utils/string.py @@ -1,16 +1,10 @@ -import functools import codecs +import functools -from .types import ( - is_bytes, - is_text, - is_string, - is_dict, - is_list_like, -) +from .types import is_bytes, is_dict, is_list_like, is_string, is_text -def force_bytes(value, encoding='iso-8859-1'): +def force_bytes(value, encoding="iso-8859-1"): if is_bytes(value): return bytes(value) elif is_text(value): @@ -19,7 +13,7 @@ def force_bytes(value, encoding='iso-8859-1'): raise TypeError("Unsupported type: {0}".format(type(value))) -def force_text(value, encoding='iso-8859-1'): +def force_text(value, encoding="iso-8859-1"): if is_text(value): return value elif is_bytes(value): @@ -32,9 +26,7 @@ def force_obj_to_bytes(obj): if is_string(obj): return force_bytes(obj) elif is_dict(obj): - return { - k: force_obj_to_bytes(v) for k, v in obj.items() - } + return {k: force_obj_to_bytes(v) for k, v in obj.items()} elif is_list_like(obj): return type(obj)(force_obj_to_bytes(v) for v in obj) else: @@ -45,9 +37,7 @@ def force_obj_to_text(obj): if is_string(obj): return force_text(obj) elif is_dict(obj): - return { - k: force_obj_to_text(v) for k, v in obj.items() - } + return {k: force_obj_to_text(v) for k, v in obj.items()} elif is_list_like(obj): return type(obj)(force_obj_to_text(v) for v in obj) else: @@ -60,6 +50,7 @@ def inner(*args, **kwargs): bytes_args = force_obj_to_bytes(args) bytes_kwargs = force_obj_to_bytes(kwargs) return fn(*bytes_args, **bytes_kwargs) + return inner @@ -69,6 +60,7 @@ def inner(*args, **kwargs): text_args = force_obj_to_text(args) text_kwargs = force_obj_to_text(kwargs) return fn(*text_args, **text_kwargs) + return inner @@ -76,6 +68,7 @@ def coerce_return_to_bytes(fn): @functools.wraps(fn) def inner(*args, **kwargs): return force_obj_to_bytes(fn(*args, **kwargs)) + return inner @@ -83,4 +76,5 @@ def coerce_return_to_text(fn): @functools.wraps(fn) def inner(*args, **kwargs): return force_obj_to_text(fn(*args, **kwargs)) + return inner diff --git a/solcx/wrapper.py b/solcx/wrapper.py index aabb399..8fa49b2 100644 --- a/solcx/wrapper.py +++ b/solcx/wrapper.py @@ -2,102 +2,96 @@ import subprocess -from semantic_version import ( - Version, -) - -from .exceptions import ( - SolcError, -) -from .utils.string import ( - force_bytes, - coerce_return_to_text, -) +from semantic_version import Version +from .exceptions import SolcError from .install import get_executable +from .utils.string import coerce_return_to_text, force_bytes @coerce_return_to_text -def solc_wrapper(solc_binary=None, - stdin=None, - help=None, - version=None, - add_std=None, - combined_json=None, - optimize=None, - optimize_runs=None, - libraries=None, - output_dir=None, - gas=None, - assemble=None, - link=None, - source_files=None, - import_remappings=None, - ast=None, - ast_json=None, - asm=None, - asm_json=None, - opcodes=None, - bin=None, - bin_runtime=None, - clone_bin=None, - abi=None, - hashes=None, - userdoc=None, - devdoc=None, - formal=None, - allow_paths=None, - standard_json=None, - success_return_code=0, - evm_version=None): +def solc_wrapper( + solc_binary=None, + stdin=None, + help=None, + version=None, + add_std=None, + combined_json=None, + optimize=None, + optimize_runs=None, + libraries=None, + output_dir=None, + gas=None, + assemble=None, + link=None, + source_files=None, + import_remappings=None, + ast=None, + ast_json=None, + asm=None, + asm_json=None, + opcodes=None, + bin=None, + bin_runtime=None, + clone_bin=None, + abi=None, + hashes=None, + userdoc=None, + devdoc=None, + formal=None, + allow_paths=None, + standard_json=None, + success_return_code=0, + evm_version=None, +): if solc_binary is None: solc_binary = get_executable() command = [solc_binary] - solc_minor = Version(solc_binary.rsplit('-v')[-1].split("\\")[0]).minor + solc_minor = Version(solc_binary.rsplit("-v")[-1].split("\\")[0]).minor if help: - command.append('--help') + command.append("--help") if version: - command.append('--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') + command.append("--add-std") if optimize: - command.append('--optimize') + command.append("--optimize") if optimize_runs is not None: - command.extend(('--optimize-runs', str(optimize_runs))) + command.extend(("--optimize-runs", str(optimize_runs))) if link: - command.append('--link') + command.append("--link") if libraries is not None: - command.extend(('--libraries', libraries)) + command.extend(("--libraries", libraries)) if output_dir is not None: - command.extend(('--output-dir', output_dir)) + command.extend(("--output-dir", output_dir)) if combined_json: if solc_minor >= 5: - combined_json = combined_json.replace(',clone-bin', '') - command.extend(('--combined-json', combined_json)) + combined_json = combined_json.replace(",clone-bin", "") + command.extend(("--combined-json", combined_json)) if gas: - command.append('--gas') + command.append("--gas") if allow_paths: - command.extend(('--allow-paths', allow_paths)) + command.extend(("--allow-paths", allow_paths)) if standard_json: - command.append('--standard-json') + command.append("--standard-json") if assemble: - command.append('--assemble') + command.append("--assemble") if import_remappings is not None: command.extend(import_remappings) @@ -107,45 +101,43 @@ def solc_wrapper(solc_binary=None, # Output configuration if ast_json: - command.append('--ast-json') + command.append("--ast-json") if asm: - command.append('--asm') + command.append("--asm") if asm_json: - command.append('--asm-json') + command.append("--asm-json") if opcodes: - command.append('--opcodes') + command.append("--opcodes") if bin: - command.append('--bin') + command.append("--bin") if bin_runtime: - command.append('--bin-runtime') + command.append("--bin-runtime") if abi: - command.append('--abi') + command.append("--abi") if hashes: - command.append('--hashes') + command.append("--hashes") if userdoc: - command.append('--userdoc') + command.append("--userdoc") if devdoc: - command.append('--devdoc') + command.append("--devdoc") if evm_version: - command.extend(('--evm-version', evm_version)) + command.extend(("--evm-version", evm_version)) # unsupported by >=0.6.0 if ast: if solc_minor >= 6: - raise AttributeError( - "solc 0.{}.x does not support the --ast flag".format(solc_minor) - ) - command.append('--ast') + raise AttributeError("solc 0.{}.x does not support the --ast flag".format(solc_minor)) + command.append("--ast") # unsupported by >=0.5.0 if clone_bin: @@ -153,31 +145,26 @@ def solc_wrapper(solc_binary=None, raise AttributeError( "solc 0.{}.x does not support the --clone-bin flag".format(solc_minor) ) - command.append('--clone-bin') + command.append("--clone-bin") if formal: if solc_minor >= 5: raise AttributeError( "solc 0.{}.x does not support the --formal flag".format(solc_minor) ) - command.append('--formal') + command.append("--formal") - if ( - not standard_json and - not source_files and - solc_minor >= 5 - ): - command.append('-') + if not standard_json and not source_files and solc_minor >= 5: + command.append("-") if stdin is not None: # solc seems to expects utf-8 from stdin: # see Scanner class in Solidity source - stdin = force_bytes(stdin, 'utf8') + stdin = force_bytes(stdin, "utf8") - proc = subprocess.Popen(command, - stdin=subprocess.PIPE, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) + proc = subprocess.Popen( + command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE + ) stdoutdata, stderrdata = proc.communicate(stdin) diff --git a/tests/conftest.py b/tests/conftest.py index 0016994..fe12a70 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,8 +1,8 @@ #!/usr/bin/python3 -import pytest import shutil +import pytest from requests import ConnectionError import solcx @@ -12,13 +12,13 @@ def pytest_addoption(parser): parser.addoption( "--no-install", action="store_true", - help="Only run solcx tests against already installed solc versions" + help="Only run solcx tests against already installed solc versions", ) def pytest_configure(config): global VERSIONS - if config.getoption('--no-install'): + if config.getoption("--no-install"): VERSIONS = solcx.get_installed_solc_versions() return try: @@ -32,14 +32,16 @@ def pytest_configure(config): # auto-parametrize the all_versions fixture with all target solc versions def pytest_generate_tests(metafunc): - if 'all_versions' in metafunc.fixturenames: - metafunc.parametrize('all_versions', VERSIONS, indirect=True) + if "all_versions" in metafunc.fixturenames: + metafunc.parametrize("all_versions", VERSIONS, indirect=True) # * runs a test against all target solc versions # * the first test using this fixture attempts to install every version # * if an install fails all subsequent tests on that version are skipped _installed = {} + + @pytest.fixture() def all_versions(request): version = request.param @@ -53,14 +55,14 @@ def all_versions(request): if _installed[version]: solcx.set_solc_version(version) else: - request.applymarker('skip') + request.applymarker("skip") # run tests with no installed versions of solc @pytest.fixture def nosolc(): path = solcx.install.get_solc_folder() - temp_path = path.parent.joinpath('.temp') + temp_path = path.parent.joinpath(".temp") path.rename(temp_path) yield if path.exists(): @@ -102,15 +104,15 @@ def invalid_source(): @pytest.fixture() def foo_path(tmp_path, foo_source): - source = tmp_path.joinpath('Foo.sol') - with source.open('w') as fp: + source = tmp_path.joinpath("Foo.sol") + with source.open("w") as fp: fp.write(foo_source) return source.as_posix() @pytest.fixture() def bar_path(tmp_path, bar_source): - source = tmp_path.joinpath('Bar.sol') - with source.open('w') as fp: + source = tmp_path.joinpath("Bar.sol") + with source.open("w") as fp: fp.write(bar_source) return source.as_posix() diff --git a/tests/test_compile.py b/tests/test_compile.py index 56c5e03..f450061 100644 --- a/tests/test_compile.py +++ b/tests/test_compile.py @@ -1,26 +1,27 @@ #!/usr/bin/python3 from pathlib import Path + import pytest import solcx -from solcx.main import ALL_OUTPUT_VALUES from solcx.exceptions import ContractsNotFound +from solcx.main import ALL_OUTPUT_VALUES # interfaces and compact-format do not return anything combined_json_values = ( - 'abi', - 'asm', - 'ast', - 'bin', - 'bin-runtime', - 'devdoc', - 'hashes', - 'metadata', - 'opcodes', - 'srcmap', - 'srcmap-runtime', - 'userdoc', + "abi", + "asm", + "ast", + "bin", + "bin-runtime", + "devdoc", + "hashes", + "metadata", + "opcodes", + "srcmap", + "srcmap-runtime", + "userdoc", ) @@ -42,7 +43,7 @@ def test_compile_source_empty(): solcx.compile_source(" ", allow_empty=True) -@pytest.mark.parametrize('key', combined_json_values) +@pytest.mark.parametrize("key", combined_json_values) def test_compile_source_output_types(foo_source, key): if key == "hashes" and str(solcx.get_solc_version().truncate()) == "0.4.11": return @@ -63,7 +64,7 @@ def test_compile_files_empty(): solcx.compile_files([], allow_empty=True) -@pytest.mark.parametrize('key', combined_json_values) +@pytest.mark.parametrize("key", combined_json_values) def test_compile_files_output_types(foo_path, key): if key == "hashes" and str(solcx.get_solc_version().truncate()) == "0.4.11": return @@ -75,7 +76,7 @@ def test_compile_files_import_remapping(foo_path, bar_path): path = Path(bar_path).parent.as_posix() output = solcx.compile_files([bar_path], import_remappings=[f"contracts={path}"]) assert output - assert f'{bar_path}:Bar' in output + assert f"{bar_path}:Bar" in output def _compile_assertions(output, key): diff --git a/tests/test_compile_standard.py b/tests/test_compile_standard.py index 7bd17b4..4f43b3f 100644 --- a/tests/test_compile_standard.py +++ b/tests/test_compile_standard.py @@ -1,10 +1,11 @@ #!/usr/bin/python3 from pathlib import Path + import pytest import solcx -from solcx.exceptions import SolcError, ContractsNotFound +from solcx.exceptions import ContractsNotFound, SolcError @pytest.fixture(autouse=True) @@ -15,32 +16,30 @@ def setup(all_versions): @pytest.fixture def input_json(): json = { - 'language': 'Solidity', - 'sources': {}, - 'settings': { - 'outputSelection': {"*": {"*": ["evm.bytecode.object"]}} - } + "language": "Solidity", + "sources": {}, + "settings": {"outputSelection": {"*": {"*": ["evm.bytecode.object"]}}}, } yield json def test_compile_standard(input_json, foo_source): - input_json['sources'] = {'contracts/Foo.sol': {'content': foo_source}} + input_json["sources"] = {"contracts/Foo.sol": {"content": foo_source}} result = solcx.compile_standard(input_json) _compile_assertions(result, "Foo") def test_compile_standard_invalid_source(input_json, invalid_source): - input_json['sources'] = {'contracts/Foo.sol': {'content': invalid_source}} + input_json["sources"] = {"contracts/Foo.sol": {"content": invalid_source}} with pytest.raises(SolcError): solcx.compile_standard(input_json) def test_compile_standard_with_dependency(input_json, foo_source, bar_source): - input_json['sources'] = { - 'contracts/Foo.sol': {'content': foo_source}, - 'contracts/Bar.sol': {'content': bar_source}, + input_json["sources"] = { + "contracts/Foo.sol": {"content": foo_source}, + "contracts/Bar.sol": {"content": bar_source}, } result = solcx.compile_standard(input_json) @@ -48,7 +47,7 @@ def test_compile_standard_with_dependency(input_json, foo_source, bar_source): def test_compile_standard_with_file_paths(input_json, foo_path): - input_json['sources'] = {'contracts/Foo.sol': {'urls': [foo_path]}} + input_json["sources"] = {"contracts/Foo.sol": {"urls": [foo_path]}} result = solcx.compile_standard(input_json, allow_paths=Path(foo_path).parent.as_posix()) _compile_assertions(result, "Foo") @@ -56,12 +55,12 @@ def test_compile_standard_with_file_paths(input_json, foo_path): def test_compile_standard_empty(): with pytest.raises(ContractsNotFound): - solcx.compile_standard({'language': 'Solidity', 'sources': {}}) + solcx.compile_standard({"language": "Solidity", "sources": {}}) def _compile_assertions(output_json, *contract_names): assert isinstance(output_json, dict) - assert 'contracts' in output_json - contracts = output_json['contracts'] + assert "contracts" in output_json + contracts = output_json["contracts"] for key in contract_names: - assert int(contracts[f'contracts/{key}.sol'][key]['evm']['bytecode']['object'], 16) + assert int(contracts[f"contracts/{key}.sol"][key]["evm"]["bytecode"]["object"], 16) diff --git a/tests/test_install.py b/tests/test_install.py index 64e3121..1456b87 100644 --- a/tests/test_install.py +++ b/tests/test_install.py @@ -1,8 +1,9 @@ #!/usr/bin/python3 -import pytest import sys +import pytest + import solcx from solcx.exceptions import SolcNotInstalled @@ -19,40 +20,40 @@ def isolation(): def test_not_installed(): solcx.install.get_executable() with pytest.raises(SolcNotInstalled): - solcx.install.get_executable('v0.4.0') + 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') + solcx.install._check_version("0.4.11") with pytest.raises(ValueError): - solcx.install._check_version('0.4.10') + solcx.install._check_version("0.4.10") def test_unknown_platform(): sys.platform = "potatoOS" with pytest.raises(KeyError): - solcx.install_solc('0.5.0') + 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') + solcx.install_solc("0.4.25") + solcx.install_solc("0.4.25", allow_osx=True) + solcx.install_solc("0.5.4") def test_progress_bar(nosolc): - solcx.install_solc('0.6.0', show_progress=True) + solcx.install_solc("0.6.0", show_progress=True) def test_environment_var_path(monkeypatch, tmp_path): install_folder = solcx.get_solc_folder() - monkeypatch.setenv('SOLCX_BINARY_PATH', tmp_path.as_posix()) + monkeypatch.setenv("SOLCX_BINARY_PATH", tmp_path.as_posix()) assert solcx.get_solc_folder() != install_folder monkeypatch.undo() @@ -61,7 +62,7 @@ def test_environment_var_path(monkeypatch, tmp_path): def test_environment_var_versions(monkeypatch, tmp_path): versions = solcx.get_installed_solc_versions() - monkeypatch.setenv('SOLCX_BINARY_PATH', tmp_path.as_posix()) + monkeypatch.setenv("SOLCX_BINARY_PATH", tmp_path.as_posix()) assert solcx.get_installed_solc_versions() != versions monkeypatch.undo() @@ -69,9 +70,9 @@ def test_environment_var_versions(monkeypatch, tmp_path): def test_environment_var_install(monkeypatch, tmp_path): - assert not tmp_path.joinpath('solc-v0.6.0').exists() + assert not tmp_path.joinpath("solc-v0.6.0").exists() - monkeypatch.setenv('SOLCX_BINARY_PATH', tmp_path.as_posix()) + monkeypatch.setenv("SOLCX_BINARY_PATH", tmp_path.as_posix()) - solcx.install_solc('0.6.0') - assert tmp_path.joinpath('solc-v0.6.0').exists() + solcx.install_solc("0.6.0") + assert tmp_path.joinpath("solc-v0.6.0").exists() diff --git a/tests/test_library_linking.py b/tests/test_library_linking.py index 2dd9087..96760b4 100644 --- a/tests/test_library_linking.py +++ b/tests/test_library_linking.py @@ -30,27 +30,26 @@ @pytest.fixture def bytecode(): - yield solcx.compile_source(source)[':LinkTester']['bin'] + yield solcx.compile_source(source)[":LinkTester"]["bin"] def test_partial_link(all_versions, bytecode): - assert '_' in bytecode + assert "_" in bytecode assert addr1[2:] not in bytecode - output = solcx.link_code(bytecode, {':UnlinkedLib': addr1}) + output = solcx.link_code(bytecode, {":UnlinkedLib": addr1}) assert output != bytecode - assert '_' in output + assert "_" in output assert addr1[2:] in output def test_full_link(all_versions, bytecode): - assert '_' in bytecode + assert "_" in bytecode assert addr1[2:] not in bytecode assert addr2[2:] not in bytecode output = solcx.link_code( - bytecode, - {':UnlinkedLib': addr1, ':OtherUnlinkedLib': addr2} + bytecode, {":UnlinkedLib": addr1, ":OtherUnlinkedLib": addr2} ) assert output != bytecode - assert '_' not in output + assert "_" not in output assert addr1[2:] in output assert addr2[2:] in output diff --git a/tests/test_locks.py b/tests/test_locks.py index 8e044f7..fdd5e1f 100644 --- a/tests/test_locks.py +++ b/tests/test_locks.py @@ -7,10 +7,9 @@ class ThreadWrap: - def __init__(self, fn, *args, **kwargs): self.exc = None - self.t = threading.Thread(target=self.wrap, args=(fn,)+args, kwargs=kwargs) + self.t = threading.Thread(target=self.wrap, args=(fn,) + args, kwargs=kwargs) self.t.start() def wrap(self, fn, *args, **kwargs): @@ -26,18 +25,18 @@ def join(self): def test_threadlock(nosolc): - threads = [ThreadWrap(solcx.install_solc, '0.5.0') for i in range(4)] + threads = [ThreadWrap(solcx.install_solc, "0.5.0") for i in range(4)] for t in threads: t.join() def test_processlock(nosolc): # have to use a context here to prevent a conflict with tqdm - ctx = mp.get_context('spawn') - threads = [ctx.Process(target=solcx.install_solc, args=('0.5.0',),) for i in range(4)] + ctx = mp.get_context("spawn") + threads = [ctx.Process(target=solcx.install_solc, args=("0.5.0",),) for i in range(4)] for t in threads: t.start() - solcx.install_solc('0.5.0') + solcx.install_solc("0.5.0") for t in threads: t.join() assert t.exitcode == 0 diff --git a/tests/test_solc_version.py b/tests/test_solc_version.py index a515fc1..7097487 100644 --- a/tests/test_solc_version.py +++ b/tests/test_solc_version.py @@ -1,6 +1,7 @@ #!/usr/bin/python3 import functools + import pytest from semantic_version import Version @@ -11,21 +12,21 @@ @pytest.fixture def pragmapatch(monkeypatch): monkeypatch.setattr( - 'solcx.install.get_installed_solc_versions', - lambda: ['v0.4.2', 'v0.4.11', 'v0.4.25', 'v0.5.0', 'v0.5.4', 'v0.5.7', 'v1.2.3'] + "solcx.install.get_installed_solc_versions", + lambda: ["v0.4.2", "v0.4.11", "v0.4.25", "v0.5.0", "v0.5.4", "v0.5.7", "v1.2.3"], ) monkeypatch.setattr( - 'solcx.install.get_available_solc_versions', - lambda: ['v0.4.11', 'v0.4.24', 'v0.4.26', 'v0.5.3', 'v0.6.0'] + "solcx.install.get_available_solc_versions", + lambda: ["v0.4.11", "v0.4.24", "v0.4.26", "v0.5.3", "v0.6.0"], ) def test_solc_supports_standard_json_interface(monkeypatch): - monkeypatch.setattr('solcx.main.get_solc_version', lambda: Version("0.5.0")) + monkeypatch.setattr("solcx.main.get_solc_version", lambda: Version("0.5.0")) assert solcx.main.solc_supports_standard_json_interface() - monkeypatch.setattr('solcx.main.get_solc_version', lambda: Version("0.4.11")) + monkeypatch.setattr("solcx.main.get_solc_version", lambda: Version("0.4.11")) assert solcx.main.solc_supports_standard_json_interface() - monkeypatch.setattr('solcx.main.get_solc_version', lambda: Version("0.4.10")) + monkeypatch.setattr("solcx.main.get_solc_version", lambda: Version("0.4.10")) assert not solcx.main.solc_supports_standard_json_interface() @@ -41,31 +42,31 @@ def test_get_solc_version_string(all_versions): def test_set_solc_version_pragma(pragmapatch): set_pragma = functools.partial(solcx.set_solc_version_pragma, check_new=True) - set_pragma('pragma solidity 0.4.11;') - assert solcx.install.solc_version == '0.4.11' - set_pragma('pragma solidity ^0.4.11;') - assert solcx.install.solc_version == '0.4.25' - set_pragma('pragma solidity >=0.4.0<0.4.25;') - assert solcx.install.solc_version == '0.4.11' - set_pragma('pragma solidity >=0.4.2;') - assert solcx.install.solc_version == '1.2.3' - set_pragma('pragma solidity >=0.4.2<0.5.5;') - assert solcx.install.solc_version == '0.5.4' - set_pragma('pragma solidity ^0.4.2 || 0.5.5;') - assert solcx.install.solc_version == '0.4.25' - set_pragma('pragma solidity ^0.4.2 || >=0.5.4<0.7.0;') - assert solcx.install.solc_version == '0.5.7' + set_pragma("pragma solidity 0.4.11;") + assert solcx.install.solc_version == "0.4.11" + set_pragma("pragma solidity ^0.4.11;") + assert solcx.install.solc_version == "0.4.25" + set_pragma("pragma solidity >=0.4.0<0.4.25;") + assert solcx.install.solc_version == "0.4.11" + set_pragma("pragma solidity >=0.4.2;") + assert solcx.install.solc_version == "1.2.3" + set_pragma("pragma solidity >=0.4.2<0.5.5;") + assert solcx.install.solc_version == "0.5.4" + set_pragma("pragma solidity ^0.4.2 || 0.5.5;") + assert solcx.install.solc_version == "0.4.25" + set_pragma("pragma solidity ^0.4.2 || >=0.5.4<0.7.0;") + assert solcx.install.solc_version == "0.5.7" with pytest.raises(SolcNotInstalled): - set_pragma('pragma solidity ^0.7.1;') + set_pragma("pragma solidity ^0.7.1;") def test_install_solc_version_pragma(pragmapatch): install_pragma = functools.partial(solcx.install_solc_pragma, install=False) - assert install_pragma('pragma solidity ^0.4.11;') == "0.4.26" - assert install_pragma('pragma solidity >=0.4.0<0.4.25;') == "0.4.24" - assert install_pragma('pragma solidity >=0.4.2;') == "0.6.0" - assert install_pragma('pragma solidity >=0.4.2<0.5.5;') == "0.5.3" - assert install_pragma('pragma solidity ^0.4.2 || 0.5.5;') == "0.4.26" - assert install_pragma('pragma solidity ^0.4.2 || >=0.5.4<0.7.0;') == "0.6.0" + assert install_pragma("pragma solidity ^0.4.11;") == "0.4.26" + assert install_pragma("pragma solidity >=0.4.0<0.4.25;") == "0.4.24" + assert install_pragma("pragma solidity >=0.4.2;") == "0.6.0" + assert install_pragma("pragma solidity >=0.4.2<0.5.5;") == "0.5.3" + assert install_pragma("pragma solidity ^0.4.2 || 0.5.5;") == "0.4.26" + assert install_pragma("pragma solidity ^0.4.2 || >=0.5.4<0.7.0;") == "0.6.0" with pytest.raises(ValueError): - install_pragma('pragma solidity ^0.7.1;') + install_pragma("pragma solidity ^0.7.1;") diff --git a/tests/test_wrapper.py b/tests/test_wrapper.py index 239f71b..252dc5d 100644 --- a/tests/test_wrapper.py +++ b/tests/test_wrapper.py @@ -1,13 +1,13 @@ #!/usr/bin/python3 import subprocess + import pytest import solcx class PopenPatch: - def __init__(self): self.proc = subprocess.Popen self.args = [] @@ -25,7 +25,7 @@ def expect(self, *args): @pytest.fixture def popen(monkeypatch): p = PopenPatch() - monkeypatch.setattr('subprocess.Popen', p) + monkeypatch.setattr("subprocess.Popen", p) yield p @@ -35,14 +35,26 @@ def setup(all_versions): def test_help(popen): - popen.expect('help') + 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_json', 'asm', 'asm_json', 'opcodes', - 'bin', 'bin_runtime', 'abi', 'hashes', 'userdoc', 'devdoc', 'standard_json' + "version", + "optimize", + "gas", + "ast_json", + "asm", + "asm_json", + "opcodes", + "bin", + "bin_runtime", + "abi", + "hashes", + "userdoc", + "devdoc", + "standard_json", ] for value in kwargs: popen.expect(value) @@ -51,11 +63,7 @@ def test_boolean_kwargs(popen, foo_source): def test_removed_kwargs(popen, foo_source): solc_minor_version = solcx.get_solc_version().minor - kwargs = [ - ('ast', 6), - ('clone_bin', 5), - ('formal', 5) - ] + kwargs = [("ast", 6), ("clone_bin", 5), ("formal", 5)] for value, minor in kwargs: popen.expect(value) if solc_minor_version >= minor: @@ -67,11 +75,11 @@ def test_removed_kwargs(popen, foo_source): def test_value_kwargs(popen, foo_source): kwargs = [ - ('optimize_runs', 200), - ('libraries', "libraries:0x1234567890123456789012345678901234567890"), - ('output_dir', "."), - ('combined_json', "abi"), - ('allow_paths', ".") + ("optimize_runs", 200), + ("libraries", "libraries:0x1234567890123456789012345678901234567890"), + ("output_dir", "."), + ("combined_json", "abi"), + ("allow_paths", "."), ] for value in kwargs: popen.expect(value[0]) From 1ca93788795b0ad0cf5916e919524deb7ebbcac9 Mon Sep 17 00:00:00 2001 From: iamdefinitelyahuman Date: Wed, 19 Feb 2020 13:57:52 +0400 Subject: [PATCH 4/4] reword feature request template to not involve brownie (oops) --- .github/ISSUE_TEMPLATE/feature.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/feature.md b/.github/ISSUE_TEMPLATE/feature.md index 3ce7940..ccdfbcb 100644 --- a/.github/ISSUE_TEMPLATE/feature.md +++ b/.github/ISSUE_TEMPLATE/feature.md @@ -6,12 +6,9 @@ about: Request a new feature, or an improvement to existing functionality. Provide a simple overview of what you wish to see added. Please include: * What you are trying to do -* Why Brownie's current functionality is inadequate to address your goal +* Why solcx's current functionality is inadequate to address your goal ### Specification Describe the syntax and semantics of how you would like to see this feature implemented. The more detailed the better! Remember, your feature is much more likely to be included if it does not involve any breaking changes. - -### Dependencies -Include links to any open issues that must be resolved before this feature can be implemented.