-
Notifications
You must be signed in to change notification settings - Fork 233
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1 from pipermerriam/piper/initial-implementation
Initial implementation
- Loading branch information
Showing
19 changed files
with
623 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import pytest | ||
|
||
|
||
@pytest.fixture() | ||
def contracts_dir(tmpdir): | ||
return str(tmpdir.mkdir("contracts")) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
pytest>=2.9.2 | ||
tox>=2.3.1 |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
from __future__ import absolute_import | ||
|
||
from .main import ( # NOQA | ||
get_solc_version, | ||
compile_files, | ||
compile_source, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
class SolcError(Exception): | ||
pass | ||
|
||
|
||
class CompileError(Exception): | ||
pass |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
from __future__ import absolute_import | ||
|
||
import functools | ||
import json | ||
import re | ||
|
||
from .exceptions import ( | ||
SolcError, | ||
) | ||
|
||
from .utils.formatting import ( | ||
add_0x_prefix, | ||
) | ||
from .utils.filesystem import ( | ||
is_executable_available, | ||
) | ||
from .wrapper import ( | ||
SOLC_BINARY, | ||
solc_wrapper, | ||
) | ||
|
||
|
||
version_regex = re.compile('Version: ([0-9]+\.[0-9]+\.[0-9]+(-[a-f0-9]+)?)') | ||
|
||
|
||
is_solc_available = functools.partial(is_executable_available, SOLC_BINARY) | ||
|
||
|
||
def get_solc_version(): | ||
stdoutdata, stderrdata = solc_wrapper(version=True) | ||
version_match = version_regex.search(stdoutdata) | ||
if version_match is None: | ||
raise SolcError( | ||
"Unable to extract version string from command output: `{0}`".format( | ||
stdoutdata, | ||
) | ||
) | ||
return version_match.groups()[0] | ||
|
||
|
||
def _parse_compiler_output(stdoutdata): | ||
contracts = json.loads(stdoutdata)['contracts'] | ||
|
||
for _, data in contracts.items(): | ||
data['abi'] = json.loads(data['abi']) | ||
|
||
sorted_contracts = sorted(contracts.items(), key=lambda c: c[0]) | ||
|
||
compiler_version = get_solc_version() | ||
|
||
return { | ||
contract_name: { | ||
'abi': contract_data['abi'], | ||
'code': add_0x_prefix(contract_data['bin']), | ||
'code_runtime': add_0x_prefix(contract_data['bin-runtime']), | ||
'source': None, | ||
'meta': { | ||
'compilerVersion': compiler_version, | ||
'language': 'Solidity', | ||
'languageVersion': '0', | ||
}, | ||
} | ||
for contract_name, contract_data | ||
in sorted_contracts | ||
} | ||
|
||
|
||
ALL_OUTPUT_VALUES = [ | ||
"abi", | ||
"asm", | ||
"ast", | ||
"bin", | ||
"bin-runtime", | ||
"clone-bin", | ||
"devdoc", | ||
"interface", | ||
"opcodes", | ||
"userdoc", | ||
] | ||
|
||
|
||
def compile_source(source, output_values=ALL_OUTPUT_VALUES, **kwargs): | ||
if 'stdin_bytes' in kwargs: | ||
raise ValueError( | ||
"The `stdin_bytes` 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) | ||
|
||
stdoutdata, stderrdata = solc_wrapper( | ||
stdin_bytes=source, | ||
combined_json=combined_json, | ||
**kwargs | ||
) | ||
|
||
contracts = _parse_compiler_output(stdoutdata) | ||
return contracts | ||
|
||
|
||
def compile_files(source_files, output_values=ALL_OUTPUT_VALUES, **kwargs): | ||
if 'source_files' in kwargs: | ||
raise ValueError( | ||
"The `source_files` keyword is not allowed in the `compile_files` function" | ||
) | ||
if 'combined_json' in kwargs: | ||
raise ValueError( | ||
"The `combined_json` keyword is not allowed in the `compile_files` function" | ||
) | ||
|
||
combined_json = ','.join(output_values) | ||
|
||
stdoutdata, stderrdata = solc_wrapper( | ||
source_files=source_files, | ||
combined_json=combined_json, | ||
**kwargs | ||
) | ||
|
||
contracts = _parse_compiler_output(stdoutdata) | ||
return contracts |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import os | ||
|
||
|
||
def is_executable_available(program): | ||
def is_exe(fpath): | ||
return os.path.isfile(fpath) and os.access(fpath, os.X_OK) | ||
|
||
fpath = os.path.dirname(program) | ||
if fpath: | ||
if is_exe(program): | ||
return True | ||
else: | ||
for path in os.environ["PATH"].split(os.pathsep): | ||
path = path.strip('"') | ||
exe_file = os.path.join(path, program) | ||
if is_exe(exe_file): | ||
return True | ||
|
||
return False |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
from __future__ import absolute_import | ||
|
||
from .string import ( | ||
force_bytes, | ||
force_text, | ||
) | ||
from .types import ( | ||
is_bytes, | ||
) | ||
|
||
|
||
def is_prefixed(value, prefix): | ||
return value.startswith( | ||
force_bytes(prefix) if is_bytes(value) else force_text(prefix) | ||
) | ||
|
||
|
||
def is_0x_prefixed(value): | ||
return is_prefixed(value, '0x') | ||
|
||
|
||
def remove_0x_prefix(value): | ||
if is_0x_prefixed(value): | ||
return value[2:] | ||
return value | ||
|
||
|
||
def add_0x_prefix(value): | ||
if is_0x_prefixed(value): | ||
return value | ||
|
||
prefix = b'0x' if is_bytes(value) else '0x' | ||
return prefix + value |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
from __future__ import absolute_import | ||
|
||
import sys | ||
import functools | ||
|
||
from .types import ( | ||
is_bytes, | ||
is_text, | ||
is_string, | ||
) | ||
|
||
if sys.version_info.major == 2: | ||
def force_bytes(value): | ||
if is_bytes(value): | ||
return str(value) | ||
elif is_text(value): | ||
return value.encode('latin1') | ||
else: | ||
raise TypeError("Unsupported type: {0}".format(type(value))) | ||
|
||
def force_text(value): | ||
if is_text(value): | ||
return value | ||
elif is_bytes(value): | ||
return unicode(force_bytes(value), 'latin1') # NOQA | ||
else: | ||
raise TypeError("Unsupported type: {0}".format(type(value))) | ||
else: | ||
def force_bytes(value): | ||
if is_bytes(value): | ||
return bytes(value) | ||
elif is_text(value): | ||
return bytes(value, 'latin1') | ||
else: | ||
raise TypeError("Unsupported type: {0}".format(type(value))) | ||
|
||
def force_text(value): | ||
if is_text(value): | ||
return value | ||
elif is_bytes(value): | ||
return str(value, 'latin1') | ||
else: | ||
raise TypeError("Unsupported type: {0}".format(type(value))) | ||
|
||
|
||
def force_obj_to_bytes(obj): | ||
if is_string(obj): | ||
return force_bytes(obj) | ||
elif isinstance(obj, dict): | ||
return { | ||
k: force_obj_to_bytes(v) for k, v in obj.items() | ||
} | ||
elif isinstance(obj, (list, tuple)): | ||
return type(obj)(force_obj_to_bytes(v) for v in obj) | ||
else: | ||
return obj | ||
|
||
|
||
def force_obj_to_text(obj): | ||
if is_string(obj): | ||
return force_text(obj) | ||
elif isinstance(obj, dict): | ||
return { | ||
k: force_obj_to_text(v) for k, v in obj.items() | ||
} | ||
elif isinstance(obj, (list, tuple)): | ||
return type(obj)(force_obj_to_text(v) for v in obj) | ||
else: | ||
return obj | ||
|
||
|
||
def coerce_args_to_bytes(fn): | ||
@functools.wraps(fn) | ||
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 | ||
|
||
|
||
def coerce_return_to_bytes(fn): | ||
@functools.wraps(fn) | ||
def inner(*args, **kwargs): | ||
return force_obj_to_bytes(fn(*args, **kwargs)) | ||
return inner | ||
|
||
|
||
def coerce_return_to_text(fn): | ||
@functools.wraps(fn) | ||
def inner(*args, **kwargs): | ||
return force_obj_to_text(fn(*args, **kwargs)) | ||
return inner |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import sys | ||
|
||
|
||
if sys.version_info.major == 2: | ||
integer_types = (int, long) # NOQA | ||
bytes_types = (bytes, bytearray) | ||
text_types = (unicode,) # NOQA | ||
string_types = (basestring, bytearray) # NOQA | ||
else: | ||
integer_types = (int,) | ||
bytes_types = (bytes, bytearray) | ||
text_types = (str,) | ||
string_types = (bytes, str, bytearray) | ||
|
||
|
||
def is_integer(value): | ||
return isinstance(value, integer_types) and not isinstance(value, bool) | ||
|
||
|
||
def is_bytes(value): | ||
return isinstance(value, bytes_types) | ||
|
||
|
||
def is_text(value): | ||
return isinstance(value, text_types) | ||
|
||
|
||
def is_string(value): | ||
return isinstance(value, string_types) | ||
|
||
|
||
def is_boolean(value): | ||
return isinstance(value, bool) | ||
|
||
|
||
def is_object(obj): | ||
return isinstance(obj, dict) | ||
|
||
|
||
def is_array(obj): | ||
return isinstance(obj, list) |
Oops, something went wrong.