Merge pull request #8144 from ethereum/pylint

CircleCI: Adds pylint test for all python files in scripts/ directory.
This commit is contained in:
chriseth 2020-02-04 17:03:28 +01:00 committed by GitHub
commit 836938c105
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 156 additions and 5 deletions

View File

@ -257,6 +257,22 @@ jobs:
name: Check for C++ coding style
command: ./scripts/check_style.sh
chk_pylint:
docker:
- image: buildpack-deps:eoan
steps:
- checkout
- run:
name: Install pip
command: apt -q update && apt install -y python3-pip
- run:
name: Install pylint
command: python3 -m pip install pylint z3-solver
# also z3-solver to make sure pylint knows about this module
- run:
name: Linting Python Scripts
command: ./scripts/pylint_all.py
chk_buglist:
docker:
- image: circleci/node
@ -718,6 +734,7 @@ workflows:
# DISABLED FOR 0.6.0 - chk_docs_examples: *workflow_trigger_on_tags
- chk_buglist: *workflow_trigger_on_tags
- chk_proofs: *workflow_trigger_on_tags
- chk_pylint: *workflow_trigger_on_tags
# build-only
- b_docs: *workflow_trigger_on_tags

View File

@ -17,6 +17,8 @@ import sys
import os
import re
from pygments_lexer_solidity import SolidityLexer
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
@ -24,7 +26,6 @@ import re
def setup(sphinx):
thisdir = os.path.dirname(os.path.realpath(__file__))
sys.path.insert(0, thisdir + '/utils')
from pygments_lexer_solidity import SolidityLexer
sphinx.add_lexer('Solidity', SolidityLexer())
sphinx.add_stylesheet('css/custom.css')

View File

@ -33,7 +33,8 @@ for optimize in [False, True]:
for contractName in sorted(result['contracts'][filename].keys()):
contractData = result['contracts'][filename][contractName]
if 'evm' in contractData and 'bytecode' in contractData['evm']:
REPORT_FILE.write(filename + ':' + contractName + ' ' + contractData['evm']['bytecode']['object'] + '\n')
REPORT_FILE.write(filename + ':' + contractName + ' ' +
contractData['evm']['bytecode']['object'] + '\n')
else:
REPORT_FILE.write(filename + ':' + contractName + ' NO BYTECODE\n')
REPORT_FILE.write(filename + ':' + contractName + ' ' + contractData['metadata'] + '\n')

View File

@ -49,7 +49,9 @@ def readDependencies(fname):
for line in o.stdout:
if line[0] == '\t':
library = line.split(' ', 1)[0][1:]
if library.startswith("/usr/local/lib") or library.startswith("/usr/local/opt") or library.startswith("/Users/"):
if (library.startswith("/usr/local/lib") or
library.startswith("/usr/local/opt") or
library.startswith("/Users/")):
if (os.path.basename(library) != os.path.basename(fname)):
command = "install_name_tool -change " + \
library + " @executable_path/./" + \

56
scripts/pylint_all.py Executable file
View File

@ -0,0 +1,56 @@
#! /usr/bin/env python3
"""
Performs pylint on all python files in the project repo's test directory recursively.
This script is meant to be run from the CI but can also be easily in local dev environment,
where you can optionally pass `-d` as command line argument to let this script abort on first error.
"""
from os import path, walk, system
from sys import argv, exit as brexit
PROJECT_ROOT = path.dirname(path.realpath(__file__))
PYLINT_RCFILE = "{}/pylintrc".format(PROJECT_ROOT)
SGR_INFO = "\033[1;32m"
SGR_CLEAR = "\033[0m"
def pylint_all_filenames(dev_mode, rootdirs):
""" Performs pylint on all python files within given root directory (recursively). """
filenames = []
for rootdir in rootdirs:
for rootpath, _, filenames_w in walk(rootdir):
for filename in filenames_w:
if filename.endswith('.py'):
filenames.append(path.join(rootpath, filename))
checked_count = 0
failed = []
for filename in filenames:
checked_count += 1
cmdline = "pylint --rcfile=\"{}\" \"{}\"".format(PYLINT_RCFILE, filename)
print("{}[{}/{}] Running pylint on file: {}{}".format(SGR_INFO, checked_count, len(filenames),
filename, SGR_CLEAR))
exit_code = system(cmdline)
if exit_code != 0:
if dev_mode:
return 1, checked_count
else:
failed.append(filename)
return len(failed), len(filenames)
def main():
"""" Collects all python script root dirs and runs pylint on them. """
dev_mode = len(argv) == 2 and argv[1] == "-d"
failed_count, total_count = pylint_all_filenames(dev_mode, [
path.abspath(path.dirname(__file__) + "/../scripts"),
path.abspath(path.dirname(__file__) + "/../test")])
if failed_count != 0:
brexit("pylint failed on {}/{} files.".format(failed_count, total_count))
else:
print("Successfully tested {} files.".format(total_count))
if __name__ == "__main__":
main()

74
scripts/pylintrc Normal file
View File

@ -0,0 +1,74 @@
# vim:et:ts=4
[MESSAGES CONTROL]
# Disable the message, report, category or checker with the given id(s). You
# can either give multiple identifiers separated by comma (,) or put this
# option multiple times (only on the command line, not in the configuration
# file where it should appear only once).You can also use "--disable=all" to
# disable everything first and then re-enable specific checks. For example, if
# you want to run only the similarities checker, you can use "--disable=all
# --enable=similarities". If you want to run only the classes checker, but have
# no Warning level messages displayed, use"--disable=all --enable=classes
# --disable=W"
# ATTENTION: This list should be extended with care, consider using NOLINT comments inside your
# python files instead, as the goal is actually to reduce the list of globally disabled checks.
#
# TODO: What could be eliminated in future PRs: bad-continuation, invalid-name, redefined-builtin,
# undefined-variable, unused-*, useless-object-inheritance.
disable=
bad-continuation,
bad-indentation,
bad-whitespace,
consider-using-sys-exit,
invalid-name,
missing-docstring,
mixed-indentation,
no-else-return,
no-self-use,
pointless-string-statement,
redefined-builtin,
redefined-outer-name,
singleton-comparison,
superfluous-parens,
too-few-public-methods,
trailing-newlines,
undefined-variable,
ungrouped-imports,
unnecessary-semicolon,
unused-import,
unused-variable,
unused-wildcard-import,
useless-object-inheritance,
wildcard-import
[BASIC]
# Good variable names which should always be accepted, separated by a comma
# added: f, h, x, a, b, p
good-names=
Run,
_,
a,
b,
ex,
f,
f,
h,
h,
i,
j,
k,
l,
m,
n,
p,
x
[FORMAT]
# Expected format of line ending, e.g. empty (any line ending), LF or CRLF.
expected-line-ending-format=LF
# Maximum number of characters on a single line.
max-line-length=110

View File

@ -27,8 +27,8 @@ def extractSourceName(line):
# writes the following source into a file named sourceName
def writeSourceToFile(lines):
filePath, srcName = extractSourceName(lines[0])
# print "sourceName is", srcName
# print "filePath is", filePath
# print("sourceName is ", srcName)
# print("filePath is", filePath)
if filePath != False:
os.system("mkdir -p " + filePath)
f = open(srcName, mode='a+', encoding='utf8')