From fba87a0789a3269648f9d497fed05cc0fa531cf1 Mon Sep 17 00:00:00 2001 From: Holger Nahrstaedt <holger@nahrstaedt.de> Date: Sat, 3 Mar 2018 14:14:01 +0100 Subject: [PATCH] Code Improvements part1 Tox.ini improved --- .bandit.yml | 84 +++++++ .coveragerc | 20 +- .pylintrc | 378 +++++++++++++++++++++++++++++ beem/comment.py | 2 - beem/memo.py | 1 - beem/steem.py | 2 - beem/vote.py | 2 +- beem/witness.py | 2 +- beemapi/steemnoderpc.py | 1 - beembase/bip38.py | 2 +- beembase/memo.py | 40 +-- beembase/operations.py | 2 +- beembase/signedtransactions.py | 2 +- beembase/transactions.py | 1 - beemgrapheneapi/graphenewsrpc.py | 3 +- beemgraphenebase/account.py | 1 - beemgraphenebase/base58.py | 2 - beemgraphenebase/ecdsasig.py | 1 - beemgraphenebase/objects.py | 2 - beemgraphenebase/transactions.py | 2 - pytest.ini | 3 + setup.cfg | 5 + setup.py | 45 ++-- tests/beemgraphene/test_account.py | 1 - tests/test_cli.py | 1 - tests/test_txbuffers.py | 1 - tests/test_witness.py | 1 - tox.ini | 91 ++++++- 28 files changed, 627 insertions(+), 71 deletions(-) create mode 100644 .bandit.yml create mode 100644 .pylintrc create mode 100644 pytest.ini diff --git a/.bandit.yml b/.bandit.yml new file mode 100644 index 00000000..ea868e29 --- /dev/null +++ b/.bandit.yml @@ -0,0 +1,84 @@ +tests: +skips: +- B404 # Ignore warnings about importing subprocess +- B603 # Ignore warnings about calling subprocess.Popen without shell=True +- B607 # Ignore warnings about calling subprocess.Popen without a full path to executable + +### (optional) plugin settings - some test plugins require configuration data +### that may be given here, per-plugin. All bandit test plugins have a built in +### set of sensible defaults and these will be used if no configuration is +### provided. It is not necessary to provide settings for every (or any) plugin +### if the defaults are acceptable. + +any_other_function_with_shell_equals_true: + no_shell: [os.execl, os.execle, os.execlp, os.execlpe, os.execv, os.execve, os.execvp, + os.execvpe, os.spawnl, os.spawnle, os.spawnlp, os.spawnlpe, os.spawnv, os.spawnve, + os.spawnvp, os.spawnvpe, os.startfile] + shell: [os.system, os.popen, os.popen2, os.popen3, os.popen4, popen2.popen2, popen2.popen3, + popen2.popen4, popen2.Popen3, popen2.Popen4, commands.getoutput, commands.getstatusoutput] + subprocess: [subprocess.Popen, subprocess.call, subprocess.check_call, subprocess.check_output, + utils.execute, utils.execute_with_timeout] +execute_with_run_as_root_equals_true: + function_names: [ceilometer.utils.execute, cinder.utils.execute, neutron.agent.linux.utils.execute, + nova.utils.execute, nova.utils.trycmd] +hardcoded_tmp_directory: + tmp_dirs: [/tmp, /var/tmp, /dev/shm] +linux_commands_wildcard_injection: + no_shell: [os.execl, os.execle, os.execlp, os.execlpe, os.execv, os.execve, os.execvp, + os.execvpe, os.spawnl, os.spawnle, os.spawnlp, os.spawnlpe, os.spawnv, os.spawnve, + os.spawnvp, os.spawnvpe, os.startfile] + shell: [os.system, os.popen, os.popen2, os.popen3, os.popen4, popen2.popen2, popen2.popen3, + popen2.popen4, popen2.Popen3, popen2.Popen4, commands.getoutput, commands.getstatusoutput] + subprocess: [subprocess.Popen, subprocess.call, subprocess.check_call, subprocess.check_output, + utils.execute, utils.execute_with_timeout] +password_config_option_not_marked_secret: + function_names: [oslo.config.cfg.StrOpt, oslo_config.cfg.StrOpt] +ssl_with_bad_defaults: + bad_protocol_versions: [PROTOCOL_SSLv2, SSLv2_METHOD, SSLv23_METHOD, PROTOCOL_SSLv3, + PROTOCOL_TLSv1, SSLv3_METHOD, TLSv1_METHOD] +ssl_with_bad_version: + bad_protocol_versions: [PROTOCOL_SSLv2, SSLv2_METHOD, SSLv23_METHOD, PROTOCOL_SSLv3, + PROTOCOL_TLSv1, SSLv3_METHOD, TLSv1_METHOD] +start_process_with_a_shell: + no_shell: [os.execl, os.execle, os.execlp, os.execlpe, os.execv, os.execve, os.execvp, + os.execvpe, os.spawnl, os.spawnle, os.spawnlp, os.spawnlpe, os.spawnv, os.spawnve, + os.spawnvp, os.spawnvpe, os.startfile] + shell: [os.system, os.popen, os.popen2, os.popen3, os.popen4, popen2.popen2, popen2.popen3, + popen2.popen4, popen2.Popen3, popen2.Popen4, commands.getoutput, commands.getstatusoutput] + subprocess: [subprocess.Popen, subprocess.call, subprocess.check_call, subprocess.check_output, + utils.execute, utils.execute_with_timeout] +start_process_with_no_shell: + no_shell: [os.execl, os.execle, os.execlp, os.execlpe, os.execv, os.execve, os.execvp, + os.execvpe, os.spawnl, os.spawnle, os.spawnlp, os.spawnlpe, os.spawnv, os.spawnve, + os.spawnvp, os.spawnvpe, os.startfile] + shell: [os.system, os.popen, os.popen2, os.popen3, os.popen4, popen2.popen2, popen2.popen3, + popen2.popen4, popen2.Popen3, popen2.Popen4, commands.getoutput, commands.getstatusoutput] + subprocess: [subprocess.Popen, subprocess.call, subprocess.check_call, subprocess.check_output, + utils.execute, utils.execute_with_timeout] +start_process_with_partial_path: + no_shell: [os.execl, os.execle, os.execlp, os.execlpe, os.execv, os.execve, os.execvp, + os.execvpe, os.spawnl, os.spawnle, os.spawnlp, os.spawnlpe, os.spawnv, os.spawnve, + os.spawnvp, os.spawnvpe, os.startfile] + shell: [os.system, os.popen, os.popen2, os.popen3, os.popen4, popen2.popen2, popen2.popen3, + popen2.popen4, popen2.Popen3, popen2.Popen4, commands.getoutput, commands.getstatusoutput] + subprocess: [subprocess.Popen, subprocess.call, subprocess.check_call, subprocess.check_output, + utils.execute, utils.execute_with_timeout] +subprocess_popen_with_shell_equals_true: + no_shell: [os.execl, os.execle, os.execlp, os.execlpe, os.execv, os.execve, os.execvp, + os.execvpe, os.spawnl, os.spawnle, os.spawnlp, os.spawnlpe, os.spawnv, os.spawnve, + os.spawnvp, os.spawnvpe, os.startfile] + shell: [os.system, os.popen, os.popen2, os.popen3, os.popen4, popen2.popen2, popen2.popen3, + popen2.popen4, popen2.Popen3, popen2.Popen4, commands.getoutput, commands.getstatusoutput] + subprocess: [subprocess.Popen, subprocess.call, subprocess.check_call, subprocess.check_output, + utils.execute, utils.execute_with_timeout] +subprocess_without_shell_equals_true: + no_shell: [os.execl, os.execle, os.execlp, os.execlpe, os.execv, os.execve, os.execvp, + os.execvpe, os.spawnl, os.spawnle, os.spawnlp, os.spawnlpe, os.spawnv, os.spawnve, + os.spawnvp, os.spawnvpe, os.startfile] + shell: [os.system, os.popen, os.popen2, os.popen3, os.popen4, popen2.popen2, popen2.popen3, + popen2.popen4, popen2.Popen3, popen2.Popen4, commands.getoutput, commands.getstatusoutput] + subprocess: [subprocess.Popen, subprocess.call, subprocess.check_call, subprocess.check_output, + utils.execute, utils.execute_with_timeout] +try_except_continue: {check_typed_exception: false} +try_except_pass: {check_typed_exception: false} + diff --git a/.coveragerc b/.coveragerc index 06a9fc22..9ed2314f 100644 --- a/.coveragerc +++ b/.coveragerc @@ -1,8 +1,26 @@ [run] +branch = True +source = + beem + beembase + beemapi + beemgrapheneapi + beemgraphenebase omit = */.eggs/* */.tox/* + [report] omit = */.eggs/* - */.tox/* \ No newline at end of file + */.tox/* + +[paths] +source = + beem + beembase + beemapi + beemgrapheneapi + beemgraphenebase + .tox/*/lib/python*/site-packages/beem + .tox/pypy/site-packages/beem diff --git a/.pylintrc b/.pylintrc new file mode 100644 index 00000000..f778dd4e --- /dev/null +++ b/.pylintrc @@ -0,0 +1,378 @@ +[MASTER] + +# Specify a configuration file. +#rcfile= + +# Python code to execute, usually for sys.path manipulation such as +# pygtk.require(). +#init-hook= + +# Add files or directories to the blacklist. They should be base names, not +# paths. +ignore=CVS,.git,flake8.egg-info + +# Pickle collected data for later comparisons. +persistent=yes + +# List of plugins (as comma separated values of python modules names) to load, +# usually to register additional checkers. +load-plugins= + +# Use multiple processes to speed up Pylint. +jobs=4 + +# Allow loading of arbitrary C extensions. Extensions are imported into the +# active Python interpreter and may run arbitrary code. +unsafe-load-any-extension=no + +# A comma-separated list of package or module names from where C extensions may +# be loaded. Extensions are loading into the active Python interpreter and may +# run arbitrary code +extension-pkg-whitelist= + +# Allow optimization of some AST trees. This will activate a peephole AST +# optimizer, which will apply various small optimizations. For instance, it can +# be used to obtain the result of joining multiple strings with the addition +# operator. Joining a lot of strings can lead to a maximum recursion error in +# Pylint and this flag can prevent that. It has one side effect, the resulting +# AST will be different than the one from reality. +optimize-ast=no + + +[MESSAGES CONTROL] + +# Only show warnings with the listed confidence levels. Leave empty to show +# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED +confidence=INFERENCE_FAILURE + +# Enable the message, report, category or checker with the given id(s). You can +# either give multiple identifier separated by comma (,) or put this option +# multiple time. See also the "--disable" option for examples. +#enable= + +# 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 reenable 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" +disable=intern-builtin,nonzero-method,parameter-unpacking,backtick,raw_input-builtin,dict-view-method,filter-builtin-not-iterating,long-builtin,unichr-builtin,input-builtin,unicode-builtin,file-builtin,map-builtin-not-iterating,delslice-method,apply-builtin,cmp-method,setslice-method,coerce-method,long-suffix,raising-string,import-star-module-level,buffer-builtin,reload-builtin,unpacking-in-except,print-statement,hex-method,old-octal-literal,metaclass-assignment,dict-iter-method,range-builtin-not-iterating,using-cmp-argument,indexing-exception,no-absolute-import,coerce-builtin,getslice-method,suppressed-message,execfile-builtin,round-builtin,useless-suppression,reduce-builtin,old-raise-syntax,zip-builtin-not-iterating,cmp-builtin,xrange-builtin,standarderror-builtin,old-division,oct-method,next-method-called,old-ne-operator,basestring-builtin + + +[REPORTS] + +# Set the output format. Available formats are text, parseable, colorized, msvs +# (visual studio) and html. You can also give a reporter class, eg +# mypackage.mymodule.MyReporterClass. +output-format=text + +# Put messages in a separate file for each module / package specified on the +# command line instead of printing them on stdout. Reports (if any) will be +# written in a file name "pylint_global.[txt|html]". +files-output=no + +# Tells whether to display a full report or only the messages +reports=no + +# Python expression which should return a note less than 10 (10 is the highest +# note). You have access to the variables errors warning, statement which +# respectively contain the number of errors / warnings messages and the total +# number of statements analyzed. This is used by the global evaluation report +# (RP0004). +evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) + +# Template used to display messages. This is a python new-style format string +# used to format the message information. See doc for all details +#msg-template= + + +[BASIC] + +# List of builtins function names that should not be used, separated by a comma +bad-functions=map,filter + +# Good variable names which should always be accepted, separated by a comma +good-names=i,j,k,ex,Run,_ + +# Bad variable names which should always be refused, separated by a comma +bad-names=foo,bar,baz,toto,tutu,tata + +# Colon-delimited sets of names that determine each other's naming style when +# the name regexes allow several styles. +name-group= + +# Include a hint for the correct naming format with invalid-name +include-naming-hint=yes + +# Regular expression matching correct argument names +argument-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Naming hint for argument names +argument-name-hint=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression matching correct attribute names +attr-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Naming hint for attribute names +attr-name-hint=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression matching correct constant names +const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$ + +# Naming hint for constant names +const-name-hint=(([A-Z_][A-Z0-9_]*)|(__.*__))$ + +# Regular expression matching correct class names +class-rgx=[A-Z_][a-zA-Z0-9]+$ + +# Naming hint for class names +class-name-hint=[A-Z_][a-zA-Z0-9]+$ + +# Regular expression matching correct inline iteration names +inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ + +# Naming hint for inline iteration names +inlinevar-name-hint=[A-Za-z_][A-Za-z0-9_]*$ + +# Regular expression matching correct class attribute names +class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ + +# Naming hint for class attribute names +class-attribute-name-hint=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ + +# Regular expression matching correct function names +function-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Naming hint for function names +function-name-hint=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression matching correct module names +module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ + +# Naming hint for module names +module-name-hint=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ + +# Regular expression matching correct method names +method-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Naming hint for method names +method-name-hint=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression matching correct variable names +variable-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Naming hint for variable names +variable-name-hint=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression which should only match function or class names that do +# not require a docstring. +no-docstring-rgx=^_ + +# Minimum line length for functions/classes that require docstrings, shorter +# ones are exempt. +docstring-min-length=-1 + + +[ELIF] + +# Maximum number of nested blocks for function / method body +max-nested-blocks=5 + + +[FORMAT] + +# Maximum number of characters on a single line. +max-line-length=100 + +# Regexp for a line that is allowed to be longer than the limit. +ignore-long-lines=^\s*(# )?<?https?://\S+>?$ + +# Allow the body of an if to be on the same line as the test if there is no +# else. +single-line-if-stmt=no + +# List of optional constructs for which whitespace checking is disabled. `dict- +# separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}. +# `trailing-comma` allows a space between comma and closing bracket: (a, ). +# `empty-line` allows space-only lines. +no-space-check=trailing-comma,dict-separator + +# Maximum number of lines in a module +max-module-lines=1000 + +# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 +# tab). +indent-string=' ' + +# Number of spaces of indent required inside a hanging or continued line. +indent-after-paren=4 + +# Expected format of line ending, e.g. empty (any line ending), LF or CRLF. +expected-line-ending-format= + + +[LOGGING] + +# Logging modules to check that the string format arguments are in logging +# function parameter format +logging-modules=logging + + +[MISCELLANEOUS] + +# List of note tags to take in consideration, separated by a comma. +notes=FIXME,XXX,TODO + + +[SIMILARITIES] + +# Minimum lines number of a similarity. +min-similarity-lines=4 + +# Ignore comments when computing similarities. +ignore-comments=yes + +# Ignore docstrings when computing similarities. +ignore-docstrings=yes + +# Ignore imports when computing similarities. +ignore-imports=no + + +[SPELLING] + +# Spelling dictionary name. Available dictionaries: none. To make it working +# install python-enchant package. +spelling-dict= + +# List of comma separated words that should not be checked. +spelling-ignore-words= + +# A path to a file that contains private dictionary; one word per line. +spelling-private-dict-file= + +# Tells whether to store unknown words to indicated private dictionary in +# --spelling-private-dict-file option instead of raising a message. +spelling-store-unknown-words=no + + +[TYPECHECK] + +# Tells whether missing members accessed in mixin class should be ignored. A +# mixin class is detected if its name ends with "mixin" (case insensitive). +ignore-mixin-members=yes + +# List of module names for which member attributes should not be checked +# (useful for modules/projects where namespaces are manipulated during runtime +# and thus existing member attributes cannot be deduced by static analysis. It +# supports qualified module names, as well as Unix pattern matching. +ignored-modules= + +# List of classes names for which member attributes should not be checked +# (useful for classes with attributes dynamically set). This supports can work +# with qualified names. +ignored-classes= + +# List of members which are set dynamically and missed by pylint inference +# system, and so shouldn't trigger E1101 when accessed. Python regular +# expressions are accepted. +generated-members= + + +[VARIABLES] + +# Tells whether we should check for unused import in __init__ files. +init-import=no + +# A regular expression matching the name of dummy variables (i.e. expectedly +# not used). +dummy-variables-rgx=_$|dummy + +# List of additional names supposed to be defined in builtins. Remember that +# you should avoid to define new builtins when possible. +additional-builtins= + +# List of strings which can identify a callback function by name. A callback +# name must start or end with one of those strings. +callbacks=cb_,_cb + + +[CLASSES] + +# List of method names used to declare (i.e. assign) instance attributes. +defining-attr-methods=__init__,__new__,setUp + +# List of valid names for the first argument in a class method. +valid-classmethod-first-arg=cls + +# List of valid names for the first argument in a metaclass class method. +valid-metaclass-classmethod-first-arg=mcs + +# List of member names, which should be excluded from the protected access +# warning. +exclude-protected=_asdict,_fields,_replace,_source,_make + + +[DESIGN] + +# Maximum number of arguments for function / method +max-args=20 + +# Argument names that match this expression will be ignored. Default to name +# with leading underscore +ignored-argument-names=_.* + +# Maximum number of locals for function / method body +max-locals=20 + +# Maximum number of return / yield for function / method body +max-returns=6 + +# Maximum number of branch for function / method body +max-branches=12 + +# Maximum number of statements in function / method body +max-statements=50 + +# Maximum number of parents for a class (see R0901). +max-parents=7 + +# Maximum number of attributes for a class (see R0902). +max-attributes=10 + +# Minimum number of public methods for a class (see R0903). +min-public-methods=2 + +# Maximum number of public methods for a class (see R0904). +max-public-methods=20 + +# Maximum number of boolean expressions in a if statement +max-bool-expr=5 + + +[IMPORTS] + +# Deprecated modules which should not be used, separated by a comma +deprecated-modules=optparse + +# Create a graph of every (i.e. internal and external) dependencies in the +# given file (report RP0402 must not be disabled) +import-graph= + +# Create a graph of external dependencies in the given file (report RP0402 must +# not be disabled) +ext-import-graph= + +# Create a graph of internal dependencies in the given file (report RP0402 must +# not be disabled) +int-import-graph= + + +[EXCEPTIONS] + +# Exceptions that will emit a warning when being caught. Defaults to +# "Exception" +overgeneral-exceptions=Exception diff --git a/beem/comment.py b/beem/comment.py index 2c23b39c..01fcf349 100644 --- a/beem/comment.py +++ b/beem/comment.py @@ -15,7 +15,6 @@ from beemgraphenebase.py23 import py23_bytes, bytes_types, integer_types, string import json import re import logging -import difflib from datetime import datetime log = logging.getLogger(__name__) @@ -309,7 +308,6 @@ class Comment(BlockchainObject): new_meta = {} if meta: if original_post["json_metadata"]: - import json new_meta = original_post["json_metadata"].update(meta) else: new_meta = meta diff --git a/beem/memo.py b/beem/memo.py index ae86eb8c..91773efb 100644 --- a/beem/memo.py +++ b/beem/memo.py @@ -9,7 +9,6 @@ from beem.instance import shared_steem_instance import random from beembase import memo as BtsMemo from beembase.account import PrivateKey, PublicKey -from beemgraphenebase.base58 import base58decode from .account import Account from .exceptions import MissingKeyError, KeyNotFound diff --git a/beem/steem.py b/beem/steem.py index cc69d610..18a90dd8 100644 --- a/beem/steem.py +++ b/beem/steem.py @@ -13,11 +13,9 @@ from beemapi.steemnoderpc import SteemNodeRPC from beemapi.exceptions import NoAccessApi from beembase.account import PrivateKey, PublicKey from beembase import transactions, operations -from .asset import Asset from .account import Account from .amount import Amount from .price import Price -from .witness import Witness from .storage import configStorage as config from .exceptions import ( AccountExistsException, diff --git a/beem/vote.py b/beem/vote.py index 3d62a35b..9144fa67 100644 --- a/beem/vote.py +++ b/beem/vote.py @@ -4,7 +4,7 @@ from __future__ import division from __future__ import print_function from __future__ import unicode_literals from builtins import str -from beemgraphenebase.py23 import bytes_types, integer_types, string_types, text_type +from beemgraphenebase.py23 import integer_types, string_types, text_type from .instance import shared_steem_instance from .account import Account from .exceptions import VoteDoesNotExistsException diff --git a/beem/witness.py b/beem/witness.py index a9ee4901..d3388ab8 100644 --- a/beem/witness.py +++ b/beem/witness.py @@ -10,7 +10,7 @@ from .account import Account from .amount import Amount from .exceptions import WitnessDoesNotExistsException from .blockchainobject import BlockchainObject -from .utils import formatTimeString, parse_time +from .utils import formatTimeString from datetime import datetime, timedelta from beembase import transactions, operations from beembase.account import PrivateKey, PublicKey diff --git a/beemapi/steemnoderpc.py b/beemapi/steemnoderpc.py index ecf2c03f..42e0eace 100644 --- a/beemapi/steemnoderpc.py +++ b/beemapi/steemnoderpc.py @@ -9,7 +9,6 @@ import threading import websocket import ssl import json -import time from itertools import cycle from beemgrapheneapi.graphenewsrpc import GrapheneWebsocketRPC from beembase.chains import known_chains diff --git a/beembase/bip38.py b/beembase/bip38.py index 2ae47c5a..ff79a04c 100644 --- a/beembase/bip38.py +++ b/beembase/bip38.py @@ -2,7 +2,7 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function from __future__ import unicode_literals -from builtins import bytes, int, str +from builtins import int, str from beemgraphenebase.bip38 import ( encrypt as GPHencrypt, decrypt as GPHdecrypt diff --git a/beembase/memo.py b/beembase/memo.py index 98d58522..ddd98b1e 100644 --- a/beembase/memo.py +++ b/beembase/memo.py @@ -53,15 +53,15 @@ def init_aes_bts(shared_secret, nonce): :rtype: AES """ - " Shared Secret " + # Shared Secret ss = hashlib.sha512(unhexlify(shared_secret)).digest() - " Seed " + # Seed seed = py23_bytes(str(nonce), 'ascii') + hexlify(ss) seed_digest = hexlify(hashlib.sha512(seed).digest()).decode('ascii') - " Check'sum' " + # Check'sum' check = hashlib.sha256(unhexlify(seed_digest)).digest() check = struct.unpack_from("<I", check[:4])[0] - " AES " + # AES key = unhexlify(seed_digest[0:64]) iv = unhexlify(seed_digest[64:96]) return AES.new(key, AES.MODE_CBC, iv) @@ -75,14 +75,14 @@ def init_aes(shared_secret, nonce): :rtype: length 2 tuple """ shared_secret = hashlib.sha512(unhexlify(shared_secret)).hexdigest() - " Seed " + # Seed ss = unhexlify(shared_secret) n = struct.pack("<Q", int(nonce)) encryption_key = hashlib.sha512(n + ss).hexdigest() - " Check'sum' " + # Check'sum' check = hashlib.sha256(unhexlify(encryption_key)).digest() check = struct.unpack_from("<I", check[:4])[0] - " AES " + # AES key = unhexlify(encryption_key[0:64]) iv = unhexlify(encryption_key[64:96]) return AES.new(key, AES.MODE_CBC, iv), check @@ -113,16 +113,16 @@ def encode_memo_bts(priv, pub, nonce, message): """ shared_secret = get_shared_secret(priv, pub) aes = init_aes_bts(shared_secret, nonce) - " Checksum " + # Checksum raw = py23_bytes(message, 'utf8') checksum = hashlib.sha256(raw).digest() raw = (checksum[0:4] + raw) - " Padding " + # Padding BS = 16 - " FIXME: this adds 16 bytes even if not required " + # FIXME: this adds 16 bytes even if not required if len(raw) % BS: raw = _pad(raw, BS) - " Encryption " + # Encryption return hexlify(aes.encrypt(raw)).decode('ascii') @@ -141,14 +141,14 @@ def decode_memo_bts(priv, pub, nonce, message): """ shared_secret = get_shared_secret(priv, pub) aes = init_aes_bts(shared_secret, nonce) - " Encryption " + # Encryption raw = py23_bytes(message, 'ascii') cleartext = aes.decrypt(unhexlify(raw)) - " TODO, verify checksum " + # TODO, verify checksum message = cleartext[4:] try: return _unpad(message.decode('utf8'), 16) - except Exception as e: + except Exception: raise ValueError(message) @@ -165,11 +165,11 @@ def encode_memo(priv, pub, nonce, message, **kwargs): aes, check = init_aes(shared_secret, nonce) raw = py23_bytes(message, 'utf8') - " Padding " + # Padding BS = 16 if len(raw) % BS: raw = _pad(raw, BS) - " Encryption " + # Encryption cipher = hexlify(aes.encrypt(raw)).decode('ascii') prefix = kwargs.pop("prefix", default_prefix) s = { @@ -193,7 +193,7 @@ def decode_memo(priv, message): :raise ValueError: if message cannot be decoded as valid UTF-8 string """ - " decode structure " + # decode structure raw = base58decode(message[1:]) from_key = PublicKey(raw[:66]) raw = raw[66:] @@ -212,13 +212,13 @@ def decode_memo(priv, message): else: raise ValueError("Incorrect PrivateKey") - " Init encryption " + # Init encryption aes, checksum = init_aes(shared_secret, nonce) - " Check " + # Check assert check == checksum, "Checksum failure" - " Encryption " + # Encryption # remove the varint prefix (FIXME, long messages!) message = cipher[2:] message = aes.decrypt(unhexlify(py23_bytes(message, 'ascii'))) diff --git a/beembase/operations.py b/beembase/operations.py index 6c0375e8..30bbd920 100644 --- a/beembase/operations.py +++ b/beembase/operations.py @@ -2,7 +2,7 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function from __future__ import unicode_literals -from builtins import bytes, int, str +from builtins import int, str from beemgraphenebase.py23 import bytes_types, integer_types, string_types, text_type from collections import OrderedDict import json diff --git a/beembase/signedtransactions.py b/beembase/signedtransactions.py index 81996099..e78664c8 100644 --- a/beembase/signedtransactions.py +++ b/beembase/signedtransactions.py @@ -2,7 +2,7 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function from __future__ import unicode_literals -from builtins import bytes, int, str +from builtins import int, str from beemgraphenebase.signedtransactions import Signed_Transaction as GrapheneSigned_Transaction from .operations import Operation from .chains import known_chains diff --git a/beembase/transactions.py b/beembase/transactions.py index 33bc3b2e..73895ab4 100644 --- a/beembase/transactions.py +++ b/beembase/transactions.py @@ -6,7 +6,6 @@ from .account import PublicKey from .chains import known_chains from .signedtransactions import Signed_Transaction from .operations import ( - Transfer, Op_wrapper, Account_create, ) diff --git a/beemgrapheneapi/graphenewsrpc.py b/beemgrapheneapi/graphenewsrpc.py index 7a4f7f03..56ca52ad 100644 --- a/beemgrapheneapi/graphenewsrpc.py +++ b/beemgrapheneapi/graphenewsrpc.py @@ -109,8 +109,7 @@ class GrapheneWebsocketRPC(object): self.api_id["history"] = self.history(api_id=1) self.api_id["network_broadcast"] = self.network_broadcast(api_id=1) - """ RPC Calls - """ + # RPC Calls def rpcexec(self, payload): """ Execute a call by sending the payload diff --git a/beemgraphenebase/account.py b/beemgraphenebase/account.py index 1282e115..9839b10e 100644 --- a/beemgraphenebase/account.py +++ b/beemgraphenebase/account.py @@ -312,7 +312,6 @@ class PrivateKey(PublicKey): """ def __init__(self, wif=None, prefix="GPH"): if wif is None: - import os self._wif = Base58(hexlify(os.urandom(32)).decode('ascii')) elif isinstance(wif, Base58): self._wif = wif diff --git a/beemgraphenebase/base58.py b/beemgraphenebase/base58.py index fc77ca45..4a10dd6e 100644 --- a/beemgraphenebase/base58.py +++ b/beemgraphenebase/base58.py @@ -3,14 +3,12 @@ from __future__ import division from __future__ import print_function from __future__ import unicode_literals from builtins import str -from builtins import bytes from builtins import object from builtins import chr from future.utils import python_2_unicode_compatible from binascii import hexlify, unhexlify from .py23 import py23_bytes, py23_chr, bytes_types, integer_types, string_types, text_type import hashlib -import sys import string import logging log = logging.getLogger(__name__) diff --git a/beemgraphenebase/ecdsasig.py b/beemgraphenebase/ecdsasig.py index 292c93ed..8a1c9f80 100644 --- a/beemgraphenebase/ecdsasig.py +++ b/beemgraphenebase/ecdsasig.py @@ -11,7 +11,6 @@ import ecdsa import hashlib import struct import logging -from binascii import hexlify from .account import PrivateKey from .py23 import py23_bytes, bytes_types log = logging.getLogger(__name__) diff --git a/beemgraphenebase/objects.py b/beemgraphenebase/objects.py index 995dde50..ba620816 100644 --- a/beemgraphenebase/objects.py +++ b/beemgraphenebase/objects.py @@ -2,7 +2,6 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function from __future__ import unicode_literals -from builtins import bytes from builtins import str from builtins import object from future.utils import python_2_unicode_compatible @@ -19,7 +18,6 @@ from beemgraphenebase.types import ( from .py23 import py23_bytes, bytes_types, integer_types, string_types from .chains import known_chains from .objecttypes import object_type -from .account import PublicKey from .chains import default_prefix from .operationids import operations diff --git a/beemgraphenebase/transactions.py b/beemgraphenebase/transactions.py index 3e0f5603..f41ddcd2 100644 --- a/beemgraphenebase/transactions.py +++ b/beemgraphenebase/transactions.py @@ -6,13 +6,11 @@ from collections import OrderedDict from binascii import hexlify, unhexlify from calendar import timegm from datetime import datetime -import json import struct import time from .account import PublicKey from .chains import known_chains -from .signedtransactions import Signed_Transaction from .operations import Operation from .objects import GrapheneObject, isArgsThisClass diff --git a/pytest.ini b/pytest.ini new file mode 100644 index 00000000..39a29feb --- /dev/null +++ b/pytest.ini @@ -0,0 +1,3 @@ +[pytest] +norecursedirs = .git .* *.egg* old docs dist build +addopts = -rw diff --git a/setup.cfg b/setup.cfg index 91932abc..3a5c3277 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,4 +1,9 @@ [metadata] description-file = README.rst +license_file = LICENSE.txt + [aliases] test=pytest + +[bdist_wheel] +universal = 1 diff --git a/setup.py b/setup.py index 5e541b15..b0a35b07 100755 --- a/setup.py +++ b/setup.py @@ -2,6 +2,7 @@ import os import sys +import io import subprocess from setuptools import setup @@ -16,6 +17,22 @@ except LookupError: VERSION = '0.19.11' +tests_require = ['mock >= 2.0.0', 'pytest', 'pytest-mock'] + +requires = [ + "future", + "ecdsa", + "requests", + "websocket-client", + "appdirs", + "Events", + "scrypt", + "pycryptodomex", + "pytz", + "Click", + "prettytable" +] + def write_version_py(filename): cnt = """ @@ -26,6 +43,16 @@ version = '%(version)s' a.write(cnt % {'version': VERSION}) +def get_long_description(): + """Generate a long description from the README file.""" + descr = [] + for fname in ('README.rst',): + with io.open(fname, encoding='utf-8') as f: + descr.append(f.read()) + return '\n\n'.join(descr) + + + if __name__ == '__main__': # Rewrite the version file everytime @@ -39,7 +66,7 @@ if __name__ == '__main__': name='beem', version=VERSION, description='Unofficial Python library for STEEM', - long_description=open('README.rst').read(), + long_description=get_long_description(), download_url='https://github.com/holgern/beem/tarball/' + VERSION, author='Holger Nahrstaedt', author_email='holger@nahrstaedt.de', @@ -68,25 +95,13 @@ if __name__ == '__main__': 'Intended Audience :: Financial and Insurance Industry', 'Topic :: Office/Business :: Financial', ], - install_requires=[ - "future", - "ecdsa", - "requests", - "websocket-client", - "appdirs", - "Events", - "scrypt", - "pycryptodomex", - "pytz", - "Click", - "prettytable" - ], + install_requires=requires, entry_points={ 'console_scripts': [ 'beempy=beem.cli:cli', ], }, setup_requires=['pytest-runner'], - tests_require=['pytest', 'pytest-mock', 'coverage', 'mock'], + tests_require=tests_require, include_package_data=True, ) diff --git a/tests/beemgraphene/test_account.py b/tests/beemgraphene/test_account.py index d7adf1b3..74dcd2ab 100644 --- a/tests/beemgraphene/test_account.py +++ b/tests/beemgraphene/test_account.py @@ -3,7 +3,6 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function from __future__ import unicode_literals -from builtins import str, bytes import unittest from beemgraphenebase.base58 import Base58 from beemgraphenebase.account import BrainKey, Address, PublicKey, PrivateKey, PasswordKey diff --git a/tests/test_cli.py b/tests/test_cli.py index bf212f61..3e3a35d6 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -12,7 +12,6 @@ from pprint import pprint from beem import Steem, exceptions from beem.account import Account from beem.amount import Amount -from beem.asset import Asset from beem.cli import cli, balance from beem.instance import set_shared_steem_instance from beembase.operationids import getOperationNameForId diff --git a/tests/test_txbuffers.py b/tests/test_txbuffers.py index 73c0793b..372dc721 100644 --- a/tests/test_txbuffers.py +++ b/tests/test_txbuffers.py @@ -5,7 +5,6 @@ from __future__ import unicode_literals from builtins import super import unittest from beem import Steem -from beembase import operations from beem.instance import set_shared_steem_instance wif = "5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3" diff --git a/tests/test_witness.py b/tests/test_witness.py index 41979d5a..cd04a234 100644 --- a/tests/test_witness.py +++ b/tests/test_witness.py @@ -7,7 +7,6 @@ import unittest from pprint import pprint from beem import Steem from beem.witness import Witness, Witnesses, WitnessesVotedByAccount, WitnessesRankedByVote -from beembase.operationids import getOperationNameForId from beem.instance import set_shared_steem_instance wif = "5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3" diff --git a/tox.ini b/tox.ini index ffc41603..aaf89b68 100644 --- a/tox.ini +++ b/tox.ini @@ -10,11 +10,67 @@ commands= coverage html -i coverage xml -[testenv:lint] +[testenv:flake8] deps= flake8 + flake8-docstrings>=0.2.7 + flake8-import-order>=0.9 + pep8-naming + flake8-colors commands= - flake8 --ignore=E501,F401 beem beemapi beembase beemgraphenebase beemgrapheneapi + flake8 beem beemapi beembase beemgraphenebase beemgrapheneapi tests + +[testenv:pylint] +deps= + pyflakes + pylint +commands= + pylint beem beemapi beembase beemgraphenebase beemgrapheneapi tests + +[testenv:doc8] +skip_install = true +deps = + sphinx + doc8 +commands = + doc8 docs/ + +[testenv:mypy] +skip_install = true +deps = + mypy-lang +commands = + mypy beem beemapi beembase beemgraphenebase beemgrapheneapi + + +[testenv:bandit] +skip_install = true +deps = + bandit +commands = + bandit -r beem beemapi beembase beemgraphenebase beemgrapheneapi -c .bandit.yml + +[testenv:linters] +skip_install = true +deps = + {[testenv:flake8]deps} + {[testenv:pylint]deps} + {[testenv:doc8]deps} + {[testenv:readme]deps} + {[testenv:bandit]deps} +commands = + {[testenv:flake8]commands} + {[testenv:pylint]commands} + {[testenv:doc8]commands} + {[testenv:readme]commands} + {[testenv:bandit]commands} + + +[testenv:readme] +deps = + readme_renderer +commands = + python setup.py check -r -s [testenv:docs] basepython= @@ -26,12 +82,6 @@ deps=-rdocs/requirements.txt commands= sphinx-build -b html ./ ./html -[testenv:pyflakes] -deps = - pyflakes -commands = - {envpython} -m pyflakes - [testenv:coverage] deps=-rrequirements-test.txt commands = @@ -44,4 +94,27 @@ passenv = CODACY_PROJECT_TOKEN commands = python-codacy-coverage -r coverage.xml - +# Flake8 Configuration +[flake8] +# Ignore some flake8-docstrings errors +# NOTE(sigmavirus24): While we're still using flake8 2.x, this ignore line +# defaults to selecting all other errors so we do not need select=E,F,W,I,D +# Once Flake8 3.0 is released and in a good state, we can use both and it will +# work well \o/ +ignore = D203 +exclude = + .tox, + .git, + __pycache__, + docs/source/conf.py, + build, + dist, + tests/fixtures/*, + *.pyc, + *.egg-info, + .cache, + .eggs +max-complexity = 10 +import-order-style = google +application-import-names = flake8 +format = ${cyan}%(path)s${reset}:${yellow_bold}%(row)d${reset}:${green_bold}%(col)d${reset}: ${red_bold}%(code)s${reset} %(text)s -- GitLab