From b625e9211bdc1f436a876ca62fa1ca0f5acc8123 Mon Sep 17 00:00:00 2001 From: Josselin Date: Wed, 22 Apr 2020 09:25:04 +0200 Subject: [PATCH] Create MyPrettyTable: wrapper around PrettyTable to allow json seralization --- scripts/travis_test_printers.sh | 2 +- slither/printers/functions/authorization.py | 4 +-- slither/printers/summary/data_depenency.py | 7 +++-- slither/printers/summary/function.py | 28 +++++++++---------- slither/printers/summary/function_ids.py | 6 ++-- slither/printers/summary/modifier_calls.py | 6 ++-- slither/printers/summary/require_calls.py | 6 ++-- slither/printers/summary/variable_order.py | 4 +-- slither/tools/properties/__main__.py | 6 ++-- .../upgradeability/utils/command_line.py | 15 +++++----- slither/utils/command_line.py | 18 ++++++------ slither/utils/myprettytable.py | 28 +++++++++++++++++++ slither/utils/output.py | 6 ++-- 13 files changed, 82 insertions(+), 54 deletions(-) create mode 100644 slither/utils/myprettytable.py diff --git a/scripts/travis_test_printers.sh b/scripts/travis_test_printers.sh index bad5631f9..c47b96288 100755 --- a/scripts/travis_test_printers.sh +++ b/scripts/travis_test_printers.sh @@ -5,7 +5,7 @@ # Needed for evm printer pip install evm-cfg-builder -slither "tests/*.json" --print all +slither "tests/*.json" --print all --json - if [ $? -ne 0 ]; then echo "Printer tests failed" diff --git a/slither/printers/functions/authorization.py b/slither/printers/functions/authorization.py index 24f606f1a..00dd08b72 100644 --- a/slither/printers/functions/authorization.py +++ b/slither/printers/functions/authorization.py @@ -2,9 +2,9 @@ Module printing summary of the contract """ -from prettytable import PrettyTable from slither.printers.abstract_printer import AbstractPrinter from slither.core.declarations.function import Function +from slither.utils.myprettytable import MyPrettyTable class PrinterWrittenVariablesAndAuthorization(AbstractPrinter): @@ -38,7 +38,7 @@ class PrinterWrittenVariablesAndAuthorization(AbstractPrinter): all_tables = [] for contract in self.contracts: txt += "\nContract %s\n"%contract.name - table = PrettyTable(["Function", "State variables written", "Conditions on msg.sender"]) + table = MyPrettyTable(["Function", "State variables written", "Conditions on msg.sender"]) for function in contract.functions: state_variables_written = [v.name for v in function.all_state_variables_written()] diff --git a/slither/printers/summary/data_depenency.py b/slither/printers/summary/data_depenency.py index 7e657ca0b..1211a914f 100644 --- a/slither/printers/summary/data_depenency.py +++ b/slither/printers/summary/data_depenency.py @@ -2,10 +2,11 @@ Module printing summary of the contract """ -from prettytable import PrettyTable from slither.printers.abstract_printer import AbstractPrinter from slither.analyses.data_dependency.data_dependency import get_dependencies from slither.slithir.variables import TemporaryVariable, ReferenceVariable +from slither.utils.myprettytable import MyPrettyTable + def _get(v, c): return list(set([d.name for d in get_dependencies(v, c) if not isinstance(d, (TemporaryVariable, @@ -31,7 +32,7 @@ class DataDependency(AbstractPrinter): txt = '' for c in self.contracts: txt += "\nContract %s\n"%c.name - table = PrettyTable(['Variable', 'Dependencies']) + table = MyPrettyTable(['Variable', 'Dependencies']) for v in c.state_variables: table.add_row([v.name, _get(v, c)]) @@ -40,7 +41,7 @@ class DataDependency(AbstractPrinter): txt += "\n" for f in c.functions_and_modifiers_declared: txt += "\nFunction %s\n"%f.full_name - table = PrettyTable(['Variable', 'Dependencies']) + table = MyPrettyTable(['Variable', 'Dependencies']) for v in f.variables: table.add_row([v.name, _get(v, f)]) for v in c.state_variables: diff --git a/slither/printers/summary/function.py b/slither/printers/summary/function.py index f144c9736..e81b11183 100644 --- a/slither/printers/summary/function.py +++ b/slither/printers/summary/function.py @@ -2,8 +2,8 @@ Module printing summary of the contract """ -from prettytable import PrettyTable from slither.printers.abstract_printer import AbstractPrinter +from slither.utils.myprettytable import MyPrettyTable class FunctionSummary(AbstractPrinter): @@ -37,13 +37,13 @@ class FunctionSummary(AbstractPrinter): txt = "\nContract %s"%name txt += '\nContract vars: '+str(var) txt += '\nInheritance:: '+str(inheritance) - table = PrettyTable(["Function", - "Visibility", - "Modifiers", - "Read", - "Write", - "Internal Calls", - "External Calls"]) + table = MyPrettyTable(["Function", + "Visibility", + "Modifiers", + "Read", + "Write", + "Internal Calls", + "External Calls"]) for (_c_name, f_name, visi, modifiers, read, write, internal_calls, external_calls) in func_summaries: read = self._convert(read) write = self._convert(write) @@ -51,12 +51,12 @@ class FunctionSummary(AbstractPrinter): external_calls = self._convert(external_calls) table.add_row([f_name, visi, modifiers, read, write, internal_calls, external_calls]) txt += "\n \n"+str(table) - table = PrettyTable(["Modifiers", - "Visibility", - "Read", - "Write", - "Internal Calls", - "External Calls"]) + table = MyPrettyTable(["Modifiers", + "Visibility", + "Read", + "Write", + "Internal Calls", + "External Calls"]) for (_c_name, f_name, visi, _, read, write, internal_calls, external_calls) in modif_summaries: read = self._convert(read) write = self._convert(write) diff --git a/slither/printers/summary/function_ids.py b/slither/printers/summary/function_ids.py index 9fc5e1a77..75c3e046a 100644 --- a/slither/printers/summary/function_ids.py +++ b/slither/printers/summary/function_ids.py @@ -1,10 +1,10 @@ """ Module printing summary of the contract """ -from prettytable import PrettyTable - from slither.printers.abstract_printer import AbstractPrinter from slither.utils.function import get_function_id +from slither.utils.myprettytable import MyPrettyTable + class FunctionIds(AbstractPrinter): @@ -24,7 +24,7 @@ class FunctionIds(AbstractPrinter): all_tables = [] for contract in self.slither.contracts_derived: txt += '\n{}:\n'.format(contract.name) - table = PrettyTable(['Name', 'ID']) + table = MyPrettyTable(['Name', 'ID']) for function in contract.functions: if function.visibility in ['public', 'external']: table.add_row([function.solidity_signature, hex(get_function_id(function.solidity_signature))]) diff --git a/slither/printers/summary/modifier_calls.py b/slither/printers/summary/modifier_calls.py index 4d3cb7182..242b9dac9 100644 --- a/slither/printers/summary/modifier_calls.py +++ b/slither/printers/summary/modifier_calls.py @@ -2,9 +2,9 @@ Module printing summary of the contract """ -from prettytable import PrettyTable from slither.core.declarations import Function from slither.printers.abstract_printer import AbstractPrinter +from slither.utils.myprettytable import MyPrettyTable class Modifiers(AbstractPrinter): @@ -26,8 +26,8 @@ class Modifiers(AbstractPrinter): for contract in self.slither.contracts_derived: txt = "\nContract %s"%contract.name - table = PrettyTable(["Function", - "Modifiers"]) + table = MyPrettyTable(["Function", + "Modifiers"]) for function in contract.functions: modifiers = function.modifiers for call in function.all_internal_calls(): diff --git a/slither/printers/summary/require_calls.py b/slither/printers/summary/require_calls.py index 25ae4af74..e51670ca2 100644 --- a/slither/printers/summary/require_calls.py +++ b/slither/printers/summary/require_calls.py @@ -2,10 +2,10 @@ Module printing summary of the contract """ -from prettytable import PrettyTable from slither.core.declarations import SolidityFunction from slither.printers.abstract_printer import AbstractPrinter from slither.slithir.operations import SolidityCall +from slither.utils.myprettytable import MyPrettyTable require_or_assert = [SolidityFunction("assert(bool)"), SolidityFunction("require(bool)"), @@ -33,8 +33,8 @@ class RequireOrAssert(AbstractPrinter): all_txt = '' for contract in self.slither.contracts_derived: txt = "\nContract %s"%contract.name - table = PrettyTable(["Function", - "require or assert"]) + table = MyPrettyTable(["Function", + "require or assert"]) for function in contract.functions: require = function.all_slithir_operations() require = [ir for ir in require if isinstance(ir, SolidityCall) and ir.function in require_or_assert] diff --git a/slither/printers/summary/variable_order.py b/slither/printers/summary/variable_order.py index 1e78cf1df..93c04fe49 100644 --- a/slither/printers/summary/variable_order.py +++ b/slither/printers/summary/variable_order.py @@ -2,8 +2,8 @@ Module printing summary of the contract """ -from prettytable import PrettyTable from slither.printers.abstract_printer import AbstractPrinter +from slither.utils.myprettytable import MyPrettyTable class VariableOrder(AbstractPrinter): @@ -26,7 +26,7 @@ class VariableOrder(AbstractPrinter): for contract in self.slither.contracts_derived: txt += '\n{}:\n'.format(contract.name) - table = PrettyTable(['Name', 'Type']) + table = MyPrettyTable(['Name', 'Type']) for variable in contract.state_variables_ordered: if not variable.is_constant: table.add_row([variable.canonical_name, str(variable.type)]) diff --git a/slither/tools/properties/__main__.py b/slither/tools/properties/__main__.py index 301ff42da..664d5c35a 100644 --- a/slither/tools/properties/__main__.py +++ b/slither/tools/properties/__main__.py @@ -1,16 +1,14 @@ -import os import argparse import logging import sys -from prettytable import PrettyTable - from slither import Slither from crytic_compile import cryticparser from slither.tools.properties.addresses.address import Addresses from slither.tools.properties.properties.erc20 import generate_erc20, ERC20_PROPERTIES from slither.tools.properties.addresses.address import OWNER_ADDRESS, USER_ADDRESS, ATTACKER_ADDRESS +from slither.utils.myprettytable import MyPrettyTable logging.basicConfig() logging.getLogger("Slither").setLevel(logging.INFO) @@ -33,7 +31,7 @@ def _all_scenarios(): return txt def _all_properties(): - table = PrettyTable(["Num", "Description", "Scenario"]) + table = MyPrettyTable(["Num", "Description", "Scenario"]) idx = 0 for scenario, value in ERC20_PROPERTIES.items(): for prop in value.properties: diff --git a/slither/tools/upgradeability/utils/command_line.py b/slither/tools/upgradeability/utils/command_line.py index 27fc77770..2af6daa54 100644 --- a/slither/tools/upgradeability/utils/command_line.py +++ b/slither/tools/upgradeability/utils/command_line.py @@ -1,6 +1,5 @@ -from prettytable import PrettyTable - from slither.tools.upgradeability.checks.abstract_checks import classification_txt +from slither.utils.myprettytable import MyPrettyTable def output_wiki(detector_classes, filter_wiki): @@ -39,12 +38,12 @@ def output_detectors(detector_classes): require_proxy = detector.REQUIRE_PROXY require_v2 = detector.REQUIRE_CONTRACT_V2 detectors_list.append((argument, help_info, impact, require_proxy, require_v2)) - table = PrettyTable(["Num", - "Check", - "What it Detects", - "Impact", - "Proxy", - "Contract V2"]) + table = MyPrettyTable(["Num", + "Check", + "What it Detects", + "Impact", + "Proxy", + "Contract V2"]) # Sort by impact, confidence, and name detectors_list = sorted(detectors_list, key=lambda element: (element[2], element[0])) diff --git a/slither/utils/command_line.py b/slither/utils/command_line.py index 590f23edb..8527f911f 100644 --- a/slither/utils/command_line.py +++ b/slither/utils/command_line.py @@ -2,11 +2,11 @@ import json import os import logging from collections import defaultdict -from prettytable import PrettyTable from crytic_compile.cryticparser.defaults import DEFAULTS_FLAG_IN_CONFIG as DEFAULTS_FLAG_IN_CONFIG_CRYTIC_COMPILE from slither.detectors.abstract_detector import classification_txt from .colors import yellow, red +from .myprettytable import MyPrettyTable logger = logging.getLogger("Slither") @@ -192,11 +192,11 @@ def output_detectors(detector_classes): impact = detector.IMPACT confidence = classification_txt[detector.CONFIDENCE] detectors_list.append((argument, help_info, impact, confidence)) - table = PrettyTable(["Num", - "Check", - "What it Detects", - "Impact", - "Confidence"]) + table = MyPrettyTable(["Num", + "Check", + "What it Detects", + "Impact", + "Confidence"]) # Sort by impact, confidence, and name detectors_list = sorted(detectors_list, key=lambda element: (element[2], element[3], element[0])) @@ -254,9 +254,9 @@ def output_printers(printer_classes): argument = printer.ARGUMENT help_info = printer.HELP printers_list.append((argument, help_info)) - table = PrettyTable(["Num", - "Printer", - "What it Does"]) + table = MyPrettyTable(["Num", + "Printer", + "What it Does"]) # Sort by impact, confidence, and name printers_list = sorted(printers_list, key=lambda element: (element[0])) diff --git a/slither/utils/myprettytable.py b/slither/utils/myprettytable.py new file mode 100644 index 000000000..e80386912 --- /dev/null +++ b/slither/utils/myprettytable.py @@ -0,0 +1,28 @@ +from typing import List, Dict + +from prettytable import PrettyTable + + +class MyPrettyTable: + + def __init__(self, field_names: List[str]): + self._field_names = field_names + self._rows: List = [] + + def add_row(self, row): + self._rows.append(row) + + def to_pretty_table(self): + table = PrettyTable(self._field_names) + for row in self._rows: + table.add_row(row) + return table + + def to_json(self) -> Dict: + return { + 'fields_names': self._field_names, + 'rows': self._rows + } + + def __str__(self): + return str(self.to_pretty_table()) \ No newline at end of file diff --git a/slither/utils/output.py b/slither/utils/output.py index d67fc8d4a..3faadaba0 100644 --- a/slither/utils/output.py +++ b/slither/utils/output.py @@ -13,6 +13,7 @@ from slither.core.source_mapping.source_mapping import SourceMapping from slither.core.variables.variable import Variable from slither.exceptions import SlitherError from slither.utils.colors import yellow +from slither.utils.myprettytable import MyPrettyTable logger = logging.getLogger("Slither") @@ -23,6 +24,7 @@ logger = logging.getLogger("Slither") ################################################################################### ################################################################################### + def output_to_json(filename, error, results): """ @@ -467,11 +469,11 @@ class Output: ################################################################################### ################################################################################### - def add_pretty_table(self, content, name, additional_fields=None): + def add_pretty_table(self, content: MyPrettyTable, name, additional_fields=None): if additional_fields is None: additional_fields = {} type_specific_fields = { - 'content': content, + 'content': content.to_json(), 'name': name } element = _create_base_element('pretty_table',