From 9821cc4510d349230baafa1a6e50a06d578c00cf Mon Sep 17 00:00:00 2001 From: coffeedogs Date: Thu, 28 Jun 2018 11:32:32 +0100 Subject: [PATCH] Respond to PR comments * Address issues raised in PR comments * Add isort tool to code_quality fab task * Applied isort tool to changed files * Refactored devops dependencies install method * Refactored application path munging * Made bitmessagecli executable * Minor bug fixes to toolchain * Removed stale donation address * Added absolute_imports to give hints to pylint --- .gitignore | 2 + INSTALL.md | 12 ++- PULL_REQUEST_TEMPLATE.md | 23 +++++- build/scripts-2.7/pybitmessage | 15 ---- checkdeps.py | 33 ++++++-- fabfile/app_path.py | 14 ++++ fabfile/lib.py | 28 ++++++- fabfile/requirements.txt | 9 --- fabfile/tasks.py | 31 ++++--- setup.cfg | 18 ++++- setup.py | 51 +++++++----- src/api.py | 50 +++++------- src/bitmessagecli.py | 13 +-- src/bitmessagemain.py | 71 +++++++--------- src/bitmessageqt/__init__.py | 126 ++++++++++++++--------------- src/bitmessageqt/account.py | 2 - src/bitmessageqt/bitmessageui.py | 28 +++---- src/network/asyncore_pollchoose.py | 29 +++---- src/network/bmproto.py | 52 ++++++------ src/network/tcp.py | 41 +++++----- src/pathmagic.py | 14 ++++ src/proofofwork.py | 36 ++++----- src/pybitmessage | 6 +- src/upnp.py | 14 ++-- 24 files changed, 393 insertions(+), 325 deletions(-) delete mode 100755 build/scripts-2.7/pybitmessage create mode 100644 fabfile/app_path.py delete mode 100644 fabfile/requirements.txt mode change 100644 => 100755 src/bitmessagecli.py create mode 100644 src/pathmagic.py diff --git a/.gitignore b/.gitignore index 104f54c1..30a4e1e9 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,5 @@ dist docs/_*/* docs/autodoc/ pyan/ +build/scripts-2.7/ +desktop/icons/ diff --git a/INSTALL.md b/INSTALL.md index c140c199..ae9bd601 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -105,4 +105,14 @@ forums for instructions on how to create a package on OS X. Please note that some versions of OS X don't work. #### Windows -## TODO: Create Windows package creation instructions + +Run `python setup.py bdist_wininst` and this will create an appropriate installer executable in `dist/`. + +# Troubleshooting + +## Working in a virtualenv +If you get the error about importing PyQt4 when using a virtualenv, run these commands (adjusted to suit your venv name and site-wide PyQt4 installation) + +`ln -s /usr/lib/python2.7/dist-packages/PyQt4 ~/.virtualenvs/pybitmessage-devops/lib/python2.7/site-packages/` +`ln -s /usr/lib/python2.7/dist-packages/sip.x86_64-linux-gnu.so ~/.virtualenvs/pybitmessage-devops/lib/python2.7/site-packages/` + diff --git a/PULL_REQUEST_TEMPLATE.md b/PULL_REQUEST_TEMPLATE.md index c820c50d..9067c7e8 100644 --- a/PULL_REQUEST_TEMPLATE.md +++ b/PULL_REQUEST_TEMPLATE.md @@ -15,7 +15,28 @@ ### Tests - If there has been a change to the code, there's a good possibility there should be a corresponding change to the tests -- If you can't run `fab tests` successfully, ask for someone to run it against your branch +- If you can't run `fab tests` successfully, ask for someone to run it against your branch. If you can't (and know that this fab task is not working yet), at least make sure the following commands work: + + - Make sure the installer still works (this may be insufficient if files are deleted) and that the installed version + works. + + - `python setup.py install --record files.txt; tr '\n' '\0' < files.txt | xargs -0 rm -f --; python setup.py install` + - `pybitmessage` + + - And as root: + + - `sudo python setup.py install --record files.txt; tr '\n' '\0' < files.txt | xargs -0 sudo rm -f --; sudo python setup.py install` + - `pybitmessage` + + - Make sure the apps still work portably: + + - `./src/bitmessagemain.py` + - `./src/bitmessagecli.py` + + - Make sure the travis test still works (currently just `pybitmessage -t` but check travis.yml for changes + + - Ideally, try this in a virtualenv, as a user with no venv, system-wide as root and on windows with `python setup.py bdist_wininst +; dist/Bitmessage_x64_0.6.3.2.exe` followed by uninstalling through add/remove progragrams and re-installing (actual filename may vary). ## Translations diff --git a/build/scripts-2.7/pybitmessage b/build/scripts-2.7/pybitmessage deleted file mode 100755 index 7f9e2e37..00000000 --- a/build/scripts-2.7/pybitmessage +++ /dev/null @@ -1,15 +0,0 @@ -#!/home/coffeedogs/.virtualenvs/pybitmessage-devops/bin/python - -import os -import sys - -import pkg_resources - -import pybitmessage.pathmagic - -dist = pkg_resources.get_distribution('pybitmessage') -script_file = os.path.join(dist.location, dist.key, 'bitmessagemain.py') -new_globals = globals() -new_globals.update(__file__=script_file) - -execfile(script_file, new_globals) diff --git a/checkdeps.py b/checkdeps.py index f261c924..e8597bab 100755 --- a/checkdeps.py +++ b/checkdeps.py @@ -1,4 +1,5 @@ #!/usr/bin/env python2 +# pylint: disable=no-name-in-module,import-error; PyCQA/pylint/issues/73 """ Check dependendies and give recommendations about how to satisfy them @@ -10,8 +11,14 @@ Limitations: EXTRAS_REQUIRE. This is fine because most developers do, too. """ +from __future__ import print_function + import os from distutils.errors import CompileError +from importlib import import_module + +from src.depends import PACKAGE_MANAGER, PACKAGES, detectOS + try: from setuptools.dist import Distribution from setuptools.extension import Extension @@ -23,10 +30,6 @@ except ImportError: HAVE_SETUPTOOLS = False EXTRAS_REQUIRE = [] -from importlib import import_module - -from src.depends import detectOS, PACKAGES, PACKAGE_MANAGER - COMPILING = { "Debian": "build-essential libssl-dev", @@ -51,10 +54,23 @@ EXTRAS_REQUIRE_DEPS = { "Guix": [""], "Gentoo": ["dev-python/python-prctl"], }, + 'devops': { + "OpenBSD": [""], + "FreeBSD": [""], + "Debian": ["libncurses5-dev"], + "Ubuntu": [""], + "Ubuntu 12": [""], + "openSUSE": [""], + "Fedora": [""], + "Guix": [""], + "Gentoo": [""], + }, + } def detectPrereqs(missing=True): + """Detect pre-requesits of PACKAGES from src.depends""" available = [] for module in PACKAGES: try: @@ -68,6 +84,7 @@ def detectPrereqs(missing=True): def prereqToPackages(): + """Detect OS-specific package depenedncies""" if not detectPrereqs(): return print("%s %s" % ( @@ -76,6 +93,7 @@ def prereqToPackages(): def compilerToPackages(): + """Detect OS-specific compiler packages""" if not detectOS() in COMPILING: return print("%s %s" % ( @@ -83,6 +101,7 @@ def compilerToPackages(): def testCompiler(): + """Test the compiler and dependencies""" if not HAVE_SETUPTOOLS: # silent, we can't test without setuptools return True @@ -137,9 +156,9 @@ OPSYS = detectOS() CMD = PACKAGE_MANAGER[OPSYS] if OPSYS in PACKAGE_MANAGER else 'UNKNOWN_INSTALLER' for lhs, rhs in EXTRAS_REQUIRE.items(): if rhs and any([ - EXTRAS_REQUIRE_DEPS[x][OPSYS] - for x in rhs - if x in EXTRAS_REQUIRE_DEPS + EXTRAS_REQUIRE_DEPS[x][OPSYS] + for x in rhs + if x in EXTRAS_REQUIRE_DEPS ]): rhs_cmd = ''.join([ CMD, diff --git a/fabfile/app_path.py b/fabfile/app_path.py new file mode 100644 index 00000000..af5f7db8 --- /dev/null +++ b/fabfile/app_path.py @@ -0,0 +1,14 @@ +""" +app_path.py +=========== + +Since fabfile directories are not part of the project they can't see modules such as `version` to update the +documentation versioning for example. + +""" + +import os +import sys + +app_dir = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'src') +sys.path.insert(0, app_dir) diff --git a/fabfile/lib.py b/fabfile/lib.py index 7af40231..d7d85a47 100644 --- a/fabfile/lib.py +++ b/fabfile/lib.py @@ -5,15 +5,14 @@ A library of functions and constants for tasks to make use of. """ import os -import sys import re +import sys from functools import wraps -from fabric.api import run, hide, cd, env +from fabric.api import cd, env, hide, run from fabric.context_managers import settings, shell_env from fabvenv import virtualenv - FABRIC_ROOT = os.path.dirname(__file__) PROJECT_ROOT = os.path.dirname(FABRIC_ROOT) VENV_ROOT = os.path.expanduser(os.path.join('~', '.virtualenvs', 'pybitmessage-devops')) @@ -80,7 +79,12 @@ def filelist_from_git(rev=None): clean = re.sub('\n', '', clean) for line in clean.split('\r'): if line.endswith(".py"): - results.append(os.path.abspath(line)) + with settings(warn_only=True): + with hide('warnings'): + if run('stat {}'.format(os.path.abspath(line))).succeeded: + results.append(os.path.abspath(line)) + else: + print 'Deleted file {} skipped.'.format(line) return results @@ -133,6 +137,22 @@ def pylint(path_to_file): ) +def isort(path_to_file): + """Run isort on a file""" + with virtualenv(VENV_ROOT): + with hide('warnings', 'running', 'stdout', 'stderr'): + with settings(warn_only=True): + with shell_env(PYTHONPATH=PYTHONPATH): + returnable = run( + 'isort {0}'.format( + path_to_file, + ), + ) + # isort takes the view that a sorted file in is an error + returnable.return_code = not returnable.return_code + return returnable + + def autopep8(path_to_file): """Run autopep8 on a file""" with virtualenv(VENV_ROOT): diff --git a/fabfile/requirements.txt b/fabfile/requirements.txt deleted file mode 100644 index 0d0a3962..00000000 --- a/fabfile/requirements.txt +++ /dev/null @@ -1,9 +0,0 @@ -# These requirements are for the Fabric commands that support devops tasks for PyBitmessage, not for running -# PyBitmessage itself. -# TODO: Consider moving to an extra_requires group in setup.py - -pycodestyle==2.3.1 # https://github.com/PyCQA/pycodestyle/issues/741 -flake8 -pylint --e git://github.com/hhatto/autopep8.git@ver1.2.2#egg=autopep8 # Needed for fixing E712 -pep8 # autopep8 doesn't seem to like pycodestyle diff --git a/fabfile/tasks.py b/fabfile/tasks.py index fb05937d..d57c7660 100644 --- a/fabfile/tasks.py +++ b/fabfile/tasks.py @@ -4,23 +4,23 @@ Fabric tasks for PyBitmessage devops operations. Note that where tasks declare params to be bools, they use coerce_bool() and so will accept any commandline (string) representation of true or false that coerce_bool() understands. - """ import os import sys -from fabric.api import run, task, hide, cd, settings, sudo +from fabric.api import cd, hide, run, settings, sudo, task from fabric.contrib.project import rsync_project from fabvenv import virtualenv -from fabfile.lib import ( - autopep8, PROJECT_ROOT, VENV_ROOT, coerce_bool, flatten, filelist_from_git, default_hosts, - get_filtered_pycodestyle_output, get_filtered_flake8_output, get_filtered_pylint_output, -) +import fabfile.app_path # pylint: disable=unused-import -sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(os.path.dirname(__file__)), 'src'))) # noqa:E402 -from version import softwareVersion # pylint: disable=wrong-import-position +from version import softwareVersion + +from fabfile.lib import ( + PROJECT_ROOT, VENV_ROOT, autopep8, coerce_bool, default_hosts, filelist_from_git, flatten, + get_filtered_flake8_output, get_filtered_pycodestyle_output, get_filtered_pylint_output, isort +) def get_tool_results(file_list): @@ -69,6 +69,7 @@ def print_results(results, top, verbose, details): print line if details: + print print "pycodestyle:" for detail in flatten(item['pycodestyle_violations']): print detail @@ -107,7 +108,7 @@ def generate_file_list(filename): if filename: filename = os.path.abspath(filename) if not os.path.exists(filename): - print "Bad filename, specify a Python file" + print "Bad filename {}, specify a Python file".format(filename) sys.exit(1) else: file_list = [filename] @@ -201,8 +202,16 @@ def code_quality(verbose=True, details=False, fix=False, filename=None, top=10, results = get_tool_results(file_list) if fix: - for item in sort_and_slice(results, top): - autopep8(item['path_to_file']) + if filename: + sorted_and_sliced = [{'path_to_file': os.path.abspath(filename)}] + else: + sorted_and_sliced = sort_and_slice(results, top) + + for item in sorted_and_sliced: + path_to_file = item['path_to_file'] + print 'Applying automatic fixes to {}'.format(path_to_file) + isort(path_to_file) + autopep8(path_to_file) # Recalculate results after autopep8 to surprise the user the least results = get_tool_results(file_list) diff --git a/setup.cfg b/setup.cfg index d6d2afc5..49a56c2b 100644 --- a/setup.cfg +++ b/setup.cfg @@ -7,13 +7,27 @@ ignore = E722,E402 [flake8] max-line-length = 119 -ignore = E402,E722,F841 +ignore = E402,E722,F401,F841 # E402: pylint is preferred for wrong-import-position # E722: pylint is preferred for bare-except +# F401: pylint is preferred for unused-import # F841: pylint is preferred for unused-variable # pylint honours the [MESSAGES CONTROL] section [MESSAGES CONTROL] -disable=invalid-name,bare-except,broad-except +disable=invalid-name,bare-except,broad-except,ungrouped-imports # invalid-name: needs fixing during a large, project-wide refactor # bare-except,broad-except: Need fixing once thorough testing is easier +# ungrouped-imports: Incompatible with imports-before-froms which seems to be preferred + +[isort] +# https://github.com/timothycrosley/isort/wiki/isort-Settings +combine_star = true +known_app_path = fabfile.app_path +known_pathmagic = pybitmessage.pathmagic +known_pybitmessage = version,src +known_standard_library = distutils.errors +line_length = 119 +multi_line_output = 5 +sections = FUTURE,STDLIB,THIRDPARTY,PATHMAGIC,APP_PATH,PYBITMESSAGE,FIRSTPARTY,LOCALFOLDER +wrap_length = 119 diff --git a/setup.py b/setup.py index 1081b5aa..134da562 100644 --- a/setup.py +++ b/setup.py @@ -1,14 +1,21 @@ #!/usr/bin/env python2.7 +""" +setup.py +======== + +Install the pybitmessage package and dependencies. +""" + +from __future__ import print_function import os import shutil -from setuptools import setup, Extension +from setuptools import Extension, setup from setuptools.command.install import install from src.version import softwareVersion - EXTRAS_REQUIRE = { 'gir': ['pygobject'], 'notify2': ['notify2'], @@ -16,17 +23,25 @@ EXTRAS_REQUIRE = { 'prctl': ['python_prctl'], # Named threads 'qrcode': ['qrcode'], 'sound;platform_system=="Windows"': ['winsound'], - 'docs': [ - 'sphinx', # fab build_docs + 'devops': [ + 'autopep8', # fab code_quality + 'fabric==1.14.0', + 'fabric-virtualenv', + 'flake8==3.4.1', # https://github.com/PyCQA/pycodestyle/issues/741 'graphviz', # fab build_docs - 'curses', # src/depends.py - 'python2-pythondialog', # src/depends.py + 'isort', # fab code_quality 'm2r', # fab build_docs + 'pycodestyle==2.3.1', # https://github.com/PyCQA/pycodestyle/issues/741 + 'pylint', # fab code_quality + 'python2-pythondialog', # src/depends.py + 'sphinx', # fab build_docs ], } class InstallCmd(install): + """Install PyBitmessage""" + def run(self): # prepare icons directories try: @@ -46,6 +61,7 @@ class InstallCmd(install): if __name__ == "__main__": + here = os.path.abspath(os.path.dirname(__file__)) with open(os.path.join(here, 'README.md')) as f: README = f.read() @@ -63,21 +79,21 @@ if __name__ == "__main__": 'pybitmessage.bitmessagecurses', 'pybitmessage.messagetypes', 'pybitmessage.network', + 'pybitmessage.plugins', 'pybitmessage.pyelliptic', 'pybitmessage.socks', 'pybitmessage.storage', - 'pybitmessage.plugins' ] # this will silently accept alternative providers of msgpack # if they are already installed try: - import msgpack + import msgpack # pylint: disable=unused-import installRequires.append("msgpack-python") except ImportError: try: - import umsgpack + import umsgpack # pylint: disable=unused-import installRequires.append("umsgpack") except ImportError: packages += ['pybitmessage.fallback', 'pybitmessage.fallback.umsgpack'] @@ -89,12 +105,10 @@ if __name__ == "__main__": "a P2P communications protocol", long_description=README, license='MIT', - # TODO: add author info - #author='', - #author_email='', + author='The Bitmessage Team', + author_email='surda@economicsofbitcoin.com', url='https://bitmessage.org', - # TODO: add keywords - #keywords='', + keywords='bitmessage pybitmessage', install_requires=installRequires, extras_require=EXTRAS_REQUIRE, classifiers=[ @@ -114,11 +128,11 @@ if __name__ == "__main__": ]}, data_files=[ ('share/applications/', - ['desktop/pybitmessage.desktop']), + ['desktop/pybitmessage.desktop']), ('share/icons/hicolor/scalable/apps/', - ['desktop/icons/scalable/pybitmessage.svg']), + ['desktop/icons/scalable/pybitmessage.svg']), ('share/icons/hicolor/24x24/apps/', - ['desktop/icons/24x24/pybitmessage.png']) + ['desktop/icons/24x24/pybitmessage.png']) ], ext_modules=[bitmsghash], zip_safe=False, @@ -141,9 +155,6 @@ if __name__ == "__main__": 'libmessaging =' 'pybitmessage.plugins.indicator_libmessaging [gir]' ], - # 'console_scripts': [ - # 'pybitmessage = pybitmessage.bitmessagemain:main' - # ] }, scripts=['src/pybitmessage'], cmdclass={'install': InstallCmd} diff --git a/src/api.py b/src/api.py index d88bbc87..ea899e02 100644 --- a/src/api.py +++ b/src/api.py @@ -8,41 +8,33 @@ This is not what you run to run the Bitmessage API. Instead, enable the API ( https://bitmessage.org/wiki/API ) and optionally enable daemon mode ( https://bitmessage.org/wiki/Daemon ) then run bitmessagemain.py. """ - from __future__ import absolute_import import base64 import hashlib import json -from struct import pack import time from binascii import hexlify, unhexlify - from SimpleXMLRPCServer import SimpleXMLRPCRequestHandler, SimpleXMLRPCServer +from struct import pack + +from version import softwareVersion -import shared -from addresses import ( - decodeAddress, addBMIfNotPresent, decodeVarint, - calculateInventoryHash, varintDecodeError) -from bmconfigparser import BMConfigParser import defaults import helper_inbox import helper_sent - -import state -import queues -import shutdown import network.stats - -# Classes -from helper_sql import sqlQuery, sqlExecute, SqlBulkExecute, sqlStoredProcedure -from helper_ackPayload import genAckPayload -from debug import logger -from inventory import Inventory -from version import softwareVersion - -# Helper Functions import proofofwork +import queues +import shared +import shutdown +import state +from addresses import addBMIfNotPresent, calculateInventoryHash, decodeAddress, decodeVarint, varintDecodeError +from bmconfigparser import BMConfigParser +from debug import logger +from helper_ackPayload import genAckPayload +from helper_sql import SqlBulkExecute, sqlExecute, sqlQuery, sqlStoredProcedure +from inventory import Inventory str_chan = '[chan]' @@ -116,7 +108,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): response = self.server._marshaled_dispatch( # pylint: disable=protected-access data, getattr(self, '_dispatch', None) ) - except: # This should only happen if the module is buggy + except BaseException: # This should only happen if the module is buggy # internal error, report as HTTP server error self.send_response(500) self.end_headers() @@ -328,7 +320,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): label = self._decode(label, "base64") try: unicode(label, 'utf-8') - except: + except BaseException: raise APIError(17, 'Label is not valid UTF-8 data.') queues.apiAddressGeneratorReturnQueue.queue.clear() streamNumberForAddress = 1 @@ -505,7 +497,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): try: unicode(passphrase, 'utf-8') label = str_chan + ' ' + passphrase - except: + except BaseException: label = str_chan + ' ' + repr(passphrase) addressVersionNumber = 4 @@ -538,7 +530,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): try: unicode(passphrase, 'utf-8') label = str_chan + ' ' + passphrase - except: + except BaseException: label = str_chan + ' ' + repr(passphrase) status, addressVersionNumber, streamNumber, toRipe = self._verifyAddress( # pylint: disable=unused-variable @@ -925,7 +917,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): try: fromAddressEnabled = BMConfigParser().getboolean( fromAddress, 'enabled') - except: + except BaseException: raise APIError( 13, 'Could not find your fromAddress in the keys.dat file.') if not fromAddressEnabled: @@ -997,7 +989,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): self._verifyAddress(fromAddress) try: BMConfigParser().getboolean(fromAddress, 'enabled') - except: + except BaseException: raise APIError( 13, 'could not find your fromAddress in the keys.dat file.') streamNumber = decodeAddress(fromAddress)[2] @@ -1060,7 +1052,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): label = self._decode(label, "base64") try: unicode(label, 'utf-8') - except: + except BaseException: raise APIError(17, 'Label is not valid UTF-8 data.') if len(params) > 2: raise APIError(0, 'I need either 1 or 2 parameters!') @@ -1147,7 +1139,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): 'POW took', int(time.time() - powStartTime), 'seconds.', nonce / (time.time() - powStartTime), 'nonce trials per second.', ) - except: + except BaseException: pass encryptedPayload = pack('>Q', nonce) + encryptedPayload toStreamNumber = decodeVarint(encryptedPayload[16:26])[0] diff --git a/src/bitmessagecli.py b/src/bitmessagecli.py old mode 100644 new mode 100755 index 02fed7e9..8e9d88e8 --- a/src/bitmessagecli.py +++ b/src/bitmessagecli.py @@ -12,20 +12,21 @@ This is an example of a daemon client for PyBitmessage 0.6.2, by .dok (Version 0 TODO: fix the following (currently ignored) violations: """ +from __future__ import absolute_import -import xmlrpclib import datetime import imghdr -import ntpath import json -import socket -import time -import sys +import ntpath import os +import socket +import sys +import time +import xmlrpclib +import pathmagic from bmconfigparser import BMConfigParser - api = '' keysName = 'keys.dat' keysPath = 'keys.dat' diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index d2749cdd..ea011fb4 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -31,49 +31,32 @@ from struct import pack from subprocess import call from time import sleep -app_dir = os.path.dirname(os.path.abspath(__file__)) -os.chdir(app_dir) -sys.path.insert(0, app_dir) - -# Used to capture a Ctrl-C keypress so that Bitmessage can shutdown gracefully. -# The next 3 are used for the API -from singleinstance import singleinstance - -from api import MySimpleXMLRPCRequestHandler, StoppableXMLRPCServer -from helper_startup import ( - isOurOperatingSystemLimitedToHavingVeryFewHalfOpenConnections -) - import defaults import depends -import shared -import knownnodes -import state -import shutdown - -# Classes -from class_sqlThread import sqlThread -from class_singleCleaner import singleCleaner -from class_objectProcessor import objectProcessor -from class_singleWorker import singleWorker -from class_addressGenerator import addressGenerator -from bmconfigparser import BMConfigParser - -from inventory import Inventory - -from network.connectionpool import BMConnectionPool -from network.dandelion import Dandelion -from network.networkthread import BMNetworkThread -from network.receivequeuethread import ReceiveQueueThread -from network.announcethread import AnnounceThread -from network.invthread import InvThread -from network.addrthread import AddrThread -from network.downloadthread import DownloadThread - -# Helper Functions -import helper_bootstrap import helper_generic import helper_threading +import knownnodes +import shared +import shutdown +import state +from api import MySimpleXMLRPCRequestHandler, StoppableXMLRPCServer +from bmconfigparser import BMConfigParser +from class_addressGenerator import addressGenerator +from class_objectProcessor import objectProcessor +from class_singleCleaner import singleCleaner +from class_singleWorker import singleWorker +from class_sqlThread import sqlThread +from helper_startup import isOurOperatingSystemLimitedToHavingVeryFewHalfOpenConnections +from inventory import Inventory +from network.addrthread import AddrThread +from network.announcethread import AnnounceThread +from network.connectionpool import BMConnectionPool +from network.dandelion import Dandelion +from network.downloadthread import DownloadThread +from network.invthread import InvThread +from network.networkthread import BMNetworkThread +from network.receivequeuethread import ReceiveQueueThread +from singleinstance import singleinstance depends.check_dependencies() @@ -95,7 +78,7 @@ def connectToStream(streamNumber): if BMConfigParser().get( 'bitmessagesettings', 'socksproxytype') != 'none': state.maximumNumberOfHalfOpenConnections = 4 - except: + except BaseException: pass with knownnodes.knownNodesLock: @@ -188,7 +171,7 @@ class singleAPI(threading.Thread, helper_threading.StoppableThread): )) s.shutdown(socket.SHUT_RDWR) s.close() - except: + except BaseException: pass def run(self): @@ -364,11 +347,11 @@ class Main(object): try: apiNotifyPath = BMConfigParser().get( 'bitmessagesettings', 'apinotifypath') - except: + except BaseException: apiNotifyPath = '' if apiNotifyPath != '': with shared.printLock: - print('Trying to call', apiNotifyPath) + print 'Trying to call', apiNotifyPath call([apiNotifyPath, "startingUp"]) singleAPIThread = singleAPI() @@ -414,7 +397,7 @@ class Main(object): if state.curses: if not depends.check_curses(): sys.exit() - print('Running with curses') + print 'Running with curses' import bitmessagecurses bitmessagecurses.runwrapper() elif state.kivy: diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 97a3a420..5e4c18fd 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -395,13 +395,13 @@ class MyForm(settingsmixin.SMainWindow): treeWidget.header().setSortIndicator( 0, QtCore.Qt.AscendingOrder) # init dictionary - + db = getSortedSubscriptions(True) for address in db: for folder in folders: if not folder in db[address]: db[address][folder] = {} - + if treeWidget.isSortingEnabled(): treeWidget.setSortingEnabled(False) @@ -413,7 +413,7 @@ class MyForm(settingsmixin.SMainWindow): toAddress = widget.address else: toAddress = None - + if not toAddress in db: treeWidget.takeTopLevelItem(i) # no increment @@ -444,7 +444,7 @@ class MyForm(settingsmixin.SMainWindow): widget.setUnreadCount(unread) db.pop(toAddress, None) i += 1 - + i = 0 for toAddress in db: widget = Ui_SubscriptionWidget(treeWidget, i, toAddress, db[toAddress]["inbox"]['count'], db[toAddress]["inbox"]['label'], db[toAddress]["inbox"]['enabled']) @@ -459,7 +459,7 @@ class MyForm(settingsmixin.SMainWindow): j += 1 widget.setUnreadCount(unread) i += 1 - + treeWidget.setSortingEnabled(True) @@ -468,14 +468,14 @@ class MyForm(settingsmixin.SMainWindow): def rerenderTabTreeChans(self): self.rerenderTabTree('chan') - + def rerenderTabTree(self, tab): if tab == 'messages': treeWidget = self.ui.treeWidgetYourIdentities elif tab == 'chan': treeWidget = self.ui.treeWidgetChans folders = Ui_FolderWidget.folderWeight.keys() - + # sort ascending when creating if treeWidget.topLevelItemCount() == 0: treeWidget.header().setSortIndicator( @@ -483,7 +483,7 @@ class MyForm(settingsmixin.SMainWindow): # init dictionary db = {} enabled = {} - + for toAddress in getSortedAccounts(): isEnabled = BMConfigParser().getboolean( toAddress, 'enabled') @@ -502,7 +502,7 @@ class MyForm(settingsmixin.SMainWindow): db[toAddress] = {} for folder in folders: db[toAddress][folder] = 0 - + enabled[toAddress] = isEnabled # get number of (unread) messages @@ -520,10 +520,10 @@ class MyForm(settingsmixin.SMainWindow): db[None]["sent"] = 0 db[None]["trash"] = 0 enabled[None] = True - + if treeWidget.isSortingEnabled(): treeWidget.setSortingEnabled(False) - + widgets = {} i = 0 while i < treeWidget.topLevelItemCount(): @@ -532,7 +532,7 @@ class MyForm(settingsmixin.SMainWindow): toAddress = widget.address else: toAddress = None - + if not toAddress in db: treeWidget.takeTopLevelItem(i) # no increment @@ -565,7 +565,7 @@ class MyForm(settingsmixin.SMainWindow): widget.setUnreadCount(unread) db.pop(toAddress, None) i += 1 - + i = 0 for toAddress in db: widget = Ui_AddressWidget(treeWidget, i, toAddress, db[toAddress]["inbox"], enabled[toAddress]) @@ -580,7 +580,7 @@ class MyForm(settingsmixin.SMainWindow): j += 1 widget.setUnreadCount(unread) i += 1 - + treeWidget.setSortingEnabled(True) def __init__(self, parent=None): @@ -622,13 +622,13 @@ class MyForm(settingsmixin.SMainWindow): # e.g. for editing labels self.recurDepth = 0 - + # switch back to this when replying self.replyFromTab = None # so that quit won't loop self.quitAccepted = False - + self.init_file_menu() self.init_inbox_popup_menu() self.init_identities_popup_menu() @@ -730,7 +730,7 @@ class MyForm(settingsmixin.SMainWindow): self.ui.treeWidgetYourIdentities.setIconSize(QtCore.QSize(identicon_size, identicon_size)) self.ui.treeWidgetSubscriptions.setIconSize(QtCore.QSize(identicon_size, identicon_size)) self.ui.tableWidgetAddressBook.setIconSize(QtCore.QSize(identicon_size, identicon_size)) - + self.UISignalThread = UISignaler.get() QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL( "writeNewAddressToTable(PyQt_PyObject,PyQt_PyObject,PyQt_PyObject)"), self.writeNewAddressToTable) @@ -784,7 +784,7 @@ class MyForm(settingsmixin.SMainWindow): self.rerenderComboBoxSendFrom() self.rerenderComboBoxSendFromBroadcast() - + # Put the TTL slider in the correct spot TTL = BMConfigParser().getint('bitmessagesettings', 'ttl') if TTL < 3600: # an hour @@ -793,7 +793,7 @@ class MyForm(settingsmixin.SMainWindow): TTL = 28*24*60*60 self.ui.horizontalSliderTTL.setSliderPosition((TTL - 3600) ** (1/3.199)) self.updateHumanFriendlyTTLDescription(TTL) - + QtCore.QObject.connect(self.ui.horizontalSliderTTL, QtCore.SIGNAL( "valueChanged(int)"), self.updateTTL) @@ -817,7 +817,7 @@ class MyForm(settingsmixin.SMainWindow): self.updateHumanFriendlyTTLDescription(TTL) BMConfigParser().set('bitmessagesettings', 'ttl', str(TTL)) BMConfigParser().save() - + def updateHumanFriendlyTTLDescription(self, TTL): numberOfHours = int(round(TTL / (60*60))) font = QtGui.QFont() @@ -981,7 +981,7 @@ class MyForm(settingsmixin.SMainWindow): for row in queryReturn: broadcastsUnread[row[0]] = {} broadcastsUnread[row[0]][row[1]] = row[2] - + for treeWidget in widgets: root = treeWidget.invisibleRootItem() for i in range(root.childCount()): @@ -1100,7 +1100,7 @@ class MyForm(settingsmixin.SMainWindow): if acct is None: acct = BMAccount(fromAddress) acct.parseMessage(toAddress, fromAddress, subject, "") - + items = [] #to MessageList_AddressWidget(items, toAddress, unicode(acct.toLabel, 'utf-8'), not read) @@ -1176,7 +1176,7 @@ class MyForm(settingsmixin.SMainWindow): tableWidget.setRowCount(0) queryreturn = helper_search.search_sql(xAddress, account, folder, where, what, unreadOnly) - + for row in queryreturn: msgfolder, msgid, toAddress, fromAddress, subject, received, read = row self.addMessageListItemInbox(tableWidget, msgfolder, msgid, toAddress, fromAddress, subject, received, read) @@ -1934,7 +1934,7 @@ class MyForm(settingsmixin.SMainWindow): subject = acct.subject toAddress = acct.toAddress else: - if QtGui.QMessageBox.question(self, "Sending an email?", _translate("MainWindow", + if QtGui.QMessageBox.question(self, "Sending an email?", _translate("MainWindow", "You are trying to send an email instead of a bitmessage. This requires registering with a gateway. Attempt to register?"), QtGui.QMessageBox.Yes|QtGui.QMessageBox.No) != QtGui.QMessageBox.Yes: continue @@ -2111,17 +2111,17 @@ class MyForm(settingsmixin.SMainWindow): ackdata = genAckPayload(streamNumber, 0) toAddress = str_broadcast_subscribers ripe = '' - t = ('', # msgid. We don't know what this will be until the POW is done. - toAddress, - ripe, - fromAddress, - subject, - message, - ackdata, + t = ('', # msgid. We don't know what this will be until the POW is done. + toAddress, + ripe, + fromAddress, + subject, + message, + ackdata, int(time.time()), # sentTime (this will never change) int(time.time()), # lastActionTime 0, # sleepTill time. This will get set when the POW gets done. - 'broadcastqueued', + 'broadcastqueued', 0, # retryNumber 'sent', # folder encoding, # encoding type @@ -2131,7 +2131,7 @@ class MyForm(settingsmixin.SMainWindow): '''INSERT INTO sent VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)''', *t) toLabel = str_broadcast_subscribers - + self.displayNewSentMessage( toAddress, toLabel, fromAddress, subject, message, ackdata) @@ -2250,7 +2250,7 @@ class MyForm(settingsmixin.SMainWindow): continue elif not helper_search.check_match(toAddress, fromAddress, subject, message, self.getCurrentSearchOption(tab), self.getCurrentSearchLine(tab)): continue - + self.addMessageListItemSent(sent, toAddress, fromAddress, subject, "msgqueued", ackdata, time.time()) self.getAccountTextedit(acct).setPlainText(unicode(message, 'utf-8', 'replace')) sent.setCurrentCell(0, 0) @@ -2412,11 +2412,11 @@ class MyForm(settingsmixin.SMainWindow): self.settingsDialogInstance.ui.checkBoxUseIdenticons.isChecked())) BMConfigParser().set('bitmessagesettings', 'replybelow', str( self.settingsDialogInstance.ui.checkBoxReplyBelow.isChecked())) - + lang = str(self.settingsDialogInstance.ui.languageComboBox.itemData(self.settingsDialogInstance.ui.languageComboBox.currentIndex()).toString()) BMConfigParser().set('bitmessagesettings', 'userlocale', lang) change_translation(l10n.getTranslationLanguage()) - + if int(BMConfigParser().get('bitmessagesettings', 'port')) != int(self.settingsDialogInstance.ui.lineEditTCPPort.text()): if not BMConfigParser().safeGetBoolean('bitmessagesettings', 'dontconnect'): QtGui.QMessageBox.about(self, _translate("MainWindow", "Restart"), _translate( @@ -2481,7 +2481,7 @@ class MyForm(settingsmixin.SMainWindow): self.settingsDialogInstance.ui.lineEditNamecoinUser.text())) BMConfigParser().set('bitmessagesettings', 'namecoinrpcpassword', str( self.settingsDialogInstance.ui.lineEditNamecoinPassword.text())) - + # Demanded difficulty tab if float(self.settingsDialogInstance.ui.lineEditTotalDifficulty.text()) >= 1: BMConfigParser().set('bitmessagesettings', 'defaultnoncetrialsperbyte', str(int(float( @@ -2495,7 +2495,7 @@ class MyForm(settingsmixin.SMainWindow): queues.workerQueue.put(('resetPoW', '')) acceptableDifficultyChanged = False - + if float(self.settingsDialogInstance.ui.lineEditMaxAcceptableTotalDifficulty.text()) >= 1 or float(self.settingsDialogInstance.ui.lineEditMaxAcceptableTotalDifficulty.text()) == 0: if BMConfigParser().get('bitmessagesettings','maxacceptablenoncetrialsperbyte') != str(int(float( self.settingsDialogInstance.ui.lineEditMaxAcceptableTotalDifficulty.text()) * defaults.networkDefaultProofOfWorkNonceTrialsPerByte)): @@ -2511,13 +2511,13 @@ class MyForm(settingsmixin.SMainWindow): BMConfigParser().set('bitmessagesettings', 'maxacceptablepayloadlengthextrabytes', str(int(float( self.settingsDialogInstance.ui.lineEditMaxAcceptableSmallMessageDifficulty.text()) * defaults.networkDefaultPayloadLengthExtraBytes))) if acceptableDifficultyChanged: - # It might now be possible to send msgs which were previously marked as toodifficult. + # It might now be possible to send msgs which were previously marked as toodifficult. # Let us change them to 'msgqueued'. The singleWorker will try to send them and will again # mark them as toodifficult if the receiver's required difficulty is still higher than # we are willing to do. sqlExecute('''UPDATE sent SET status='msgqueued' WHERE status='toodifficult' ''') queues.workerQueue.put(('sendmessage', '')) - + #start:UI setting to stop trying to send messages after X days/months # I'm open to changing this UI to something else if someone has a better idea. if ((self.settingsDialogInstance.ui.lineEditDays.text()=='') and (self.settingsDialogInstance.ui.lineEditMonths.text()=='')):#We need to handle this special case. Bitmessage has its default behavior. The input is blank/blank @@ -2718,7 +2718,7 @@ class MyForm(settingsmixin.SMainWindow): if getPowType() == "python" and (powQueueSize() > 0 or pendingUpload() > 0): reply = QtGui.QMessageBox.question(self, _translate("MainWindow", "Proof of work pending"), _translate("MainWindow", "%n object(s) pending proof of work", None, QtCore.QCoreApplication.CodecForTr, powQueueSize()) + ", " + - _translate("MainWindow", "%n object(s) waiting to be distributed", None, QtCore.QCoreApplication.CodecForTr, pendingUpload()) + "\n\n" + + _translate("MainWindow", "%n object(s) waiting to be distributed", None, QtCore.QCoreApplication.CodecForTr, pendingUpload()) + "\n\n" + _translate("MainWindow", "Wait until these tasks finish?"), QtGui.QMessageBox.Yes|QtGui.QMessageBox.No|QtGui.QMessageBox.Cancel, QtGui.QMessageBox.Cancel) if reply == QtGui.QMessageBox.No: @@ -2807,7 +2807,7 @@ class MyForm(settingsmixin.SMainWindow): self.updateStatusBar(_translate( "MainWindow", "Waiting for objects to be sent... %1%").arg(50)) maxPendingUpload = max(1, pendingUpload()) - + while pendingUpload() > 1: self.updateStatusBar(_translate( "MainWindow", @@ -2936,7 +2936,7 @@ class MyForm(settingsmixin.SMainWindow): # self.propagateUnreadCount(tableWidget.item(currentRow, 1 if tableWidget.item(currentRow, 1).type == AccountMixin.SUBSCRIPTION else 0).data(QtCore.Qt.UserRole), self.getCurrentFolder()) # else: # self.propagateUnreadCount(tableWidget.item(currentRow, 1 if tableWidget.item(currentRow, 1).type == AccountMixin.SUBSCRIPTION else 0).data(QtCore.Qt.UserRole), self.getCurrentFolder(), self.getCurrentTreeWidget(), 0) - # tableWidget.selectRow(currentRow + 1) + # tableWidget.selectRow(currentRow + 1) # This doesn't de-select the last message if you try to mark it unread, but that doesn't interfere. Might not be necessary. # We could also select upwards, but then our problem would be with the topmost message. # tableWidget.clearSelection() manages to mark the message as read again. @@ -2980,18 +2980,18 @@ class MyForm(settingsmixin.SMainWindow): def on_action_InboxReplyChan(self): self.on_action_InboxReply(self.REPLY_TYPE_CHAN) - + def on_action_InboxReply(self, replyType = None): tableWidget = self.getCurrentMessagelist() if not tableWidget: return - + if replyType is None: replyType = self.REPLY_TYPE_SENDER - + # save this to return back after reply is done self.replyFromTab = self.ui.tabWidget.currentIndex() - + currentInboxRow = tableWidget.currentRow() toAddressAtCurrentInboxRow = tableWidget.item( currentInboxRow, 0).address @@ -3040,7 +3040,7 @@ class MyForm(settingsmixin.SMainWindow): self.ui.lineEditTo.setText(str(acct.fromAddress)) else: self.ui.lineEditTo.setText(tableWidget.item(currentInboxRow, 1).label + " <" + str(acct.fromAddress) + ">") - + # If the previous message was to a chan then we should send our reply to the chan rather than to the particular person who sent the message. if acct.type == AccountMixin.CHAN and replyType == self.REPLY_TYPE_CHAN: logger.debug('original sent to a chan. Setting the to address in the reply to the chan address.') @@ -3048,9 +3048,9 @@ class MyForm(settingsmixin.SMainWindow): self.ui.lineEditTo.setText(str(toAddressAtCurrentInboxRow)) else: self.ui.lineEditTo.setText(tableWidget.item(currentInboxRow, 0).label + " <" + str(acct.toAddress) + ">") - + self.setSendFromComboBox(toAddressAtCurrentInboxRow) - + quotedText = self.quoted_text(unicode(messageAtCurrentInboxRow, 'utf-8', 'replace')) widget['message'].setPlainText(quotedText) if acct.subject[0:3] in ['Re:', 'RE:']: @@ -3497,7 +3497,7 @@ class MyForm(settingsmixin.SMainWindow): return messagelistList[currentIndex] else: return False - + def getAccountMessagelist(self, account): try: if account.type == AccountMixin.CHAN: @@ -3584,7 +3584,7 @@ class MyForm(settingsmixin.SMainWindow): if currentItem: return currentItem return False - + def getCurrentAccount(self, treeWidget=None): currentItem = self.getCurrentItem(treeWidget) if currentItem: @@ -3711,7 +3711,7 @@ class MyForm(settingsmixin.SMainWindow): def on_action_AddressBookSetAvatar(self): self.on_action_SetAvatar(self.ui.tableWidgetAddressBook) - + def on_action_SetAvatar(self, thisTableWidget): currentRow = thisTableWidget.currentRow() addressAtCurrentRow = thisTableWidget.item( @@ -3765,7 +3765,7 @@ class MyForm(settingsmixin.SMainWindow): self, 'Message', displayMsg, QtGui.QMessageBox.Yes, QtGui.QMessageBox.No) else: overwrite = QtGui.QMessageBox.No - + # copy the image file to the appdata folder if (not exists) | (overwrite == QtGui.QMessageBox.Yes): if overwrite == QtGui.QMessageBox.Yes: @@ -3983,11 +3983,7 @@ class MyForm(settingsmixin.SMainWindow): if column != 0: return # only account names of normal addresses (no chans/mailinglists) - if ( - not isinstance(item, Ui_AddressWidget) or - not self.getCurrentTreeWidget() or - self.getCurrentTreeWidget().currentItem() is None - ): + if (not isinstance(item, Ui_AddressWidget)) or (not self.getCurrentTreeWidget()) or self.getCurrentTreeWidget().currentItem() is None: return # not visible if (not self.getCurrentItem()) or (not isinstance (self.getCurrentItem(), Ui_AddressWidget)): @@ -3998,7 +3994,7 @@ class MyForm(settingsmixin.SMainWindow): # "All accounts" can't be renamed if item.type == AccountMixin.ALL: return - + newLabel = unicode(item.text(0), 'utf-8', 'ignore') oldLabel = item.defaultLabel() @@ -4141,7 +4137,7 @@ class settingsDialog(QtGui.QDialog): BMConfigParser().safeGetBoolean('bitmessagesettings', 'useidenticons')) self.ui.checkBoxReplyBelow.setChecked( BMConfigParser().safeGetBoolean('bitmessagesettings', 'replybelow')) - + if state.appdata == paths.lookupExeFolder(): self.ui.checkBoxPortableMode.setChecked(True) else: @@ -4266,8 +4262,8 @@ class settingsDialog(QtGui.QDialog): BMConfigParser().get('bitmessagesettings', 'stopresendingafterxdays'))) self.ui.lineEditMonths.setText(str( BMConfigParser().get('bitmessagesettings', 'stopresendingafterxmonths'))) - - + + #'System' tab removed for now. """try: maxCores = BMConfigParser().getint('bitmessagesettings', 'maxcores') @@ -4318,7 +4314,7 @@ class settingsDialog(QtGui.QDialog): def namecoinTypeChanged(self, checked): nmctype = self.getNamecoinType() assert nmctype == "namecoind" or nmctype == "nmcontrol" - + isNamecoind = (nmctype == "namecoind") self.ui.lineEditNamecoinUser.setEnabled(isNamecoind) self.ui.labelNamecoinUser.setEnabled(isNamecoind) @@ -4442,7 +4438,7 @@ def run(): # myapp.showMigrationWizard(BMConfigParser().get('bitmessagesettings', 'mailchuck')) # except: # myapp.showMigrationWizard(0) - + # only show after wizards and connect dialogs have completed if not BMConfigParser().getboolean('bitmessagesettings', 'startintray'): myapp.show() diff --git a/src/bitmessageqt/account.py b/src/bitmessageqt/account.py index 50ea3548..8b1a94fa 100644 --- a/src/bitmessageqt/account.py +++ b/src/bitmessageqt/account.py @@ -7,8 +7,6 @@ Account related functions. """ -from __future__ import absolute_import - import inspect import re import sys diff --git a/src/bitmessageqt/bitmessageui.py b/src/bitmessageqt/bitmessageui.py index 7aec31f2..13d6ed7b 100644 --- a/src/bitmessageqt/bitmessageui.py +++ b/src/bitmessageqt/bitmessageui.py @@ -1,29 +1,23 @@ # -*- coding: utf-8 -*- -# pylint: disable=too-many-locals +# pylint: disable=too-many-locals,c-extension-no-member """ -Form implementation generated from reading ui file 'bitmessageui.ui' +bitmessageui.py +=============== -Created: Mon Mar 23 22:18:07 2015 - by: PyQt4 UI code generator 4.10.4 - -WARNING! All changes made in this file will be lost! +Originally generated from reading ui file 'bitmessageui.ui'. Since then maintained manually. """ -from __future__ import absolute_import - import sys from PyQt4 import QtCore, QtGui +from bitmessageqt import settingsmixin +from bitmessageqt.blacklist import Blacklist +from bitmessageqt.foldertree import AddressBookCompleter +from bitmessageqt.messagecompose import MessageCompose +from bitmessageqt.messageview import MessageView +from bitmessageqt.networkstatus import NetworkStatus from bmconfigparser import BMConfigParser -from . import bitmessage_icons_rc # pylint: disable=unused-import -from . import settingsmixin -from .messageview import MessageView -from .messagecompose import MessageCompose -from .networkstatus import NetworkStatus -from .blacklist import Blacklist -from .foldertree import AddressBookCompleter - try: _fromUtf8 = QtCore.QString.fromUtf8 @@ -760,7 +754,7 @@ class Ui_MainWindow(object): hours = 48 try: hours = int(BMConfigParser().getint('bitmessagesettings', 'ttl') / 60 / 60) - except: + except BaseException: pass self.labelHumanFriendlyTTLDescription.setText( _translate( diff --git a/src/network/asyncore_pollchoose.py b/src/network/asyncore_pollchoose.py index 233a49b1..bbe89119 100644 --- a/src/network/asyncore_pollchoose.py +++ b/src/network/asyncore_pollchoose.py @@ -53,13 +53,15 @@ import select import socket import sys import time -from threading import current_thread import warnings -from errno import EALREADY, EINPROGRESS, EWOULDBLOCK, ECONNRESET, EINVAL, \ - ENOTCONN, ESHUTDOWN, EISCONN, EBADF, ECONNABORTED, EPIPE, EAGAIN, \ - ECONNREFUSED, EHOSTUNREACH, ENETUNREACH, ENOTSOCK, EINTR, ETIMEDOUT, \ - EADDRINUSE, \ - errorcode +from errno import ( + EADDRINUSE, EAGAIN, EALREADY, EBADF, ECONNABORTED, ECONNREFUSED, ECONNRESET, EHOSTUNREACH, EINPROGRESS, EINTR, + EINVAL, EISCONN, ENETUNREACH, ENOTCONN, ENOTSOCK, EPIPE, ESHUTDOWN, ETIMEDOUT, EWOULDBLOCK, errorcode +) +from threading import current_thread + +import helper_random + try: from errno import WSAEWOULDBLOCK except (ImportError, AttributeError): @@ -77,7 +79,6 @@ try: from errno import WSAEADDRINUSE # pylint: disable=unused-import except (ImportError, AttributeError): WSAEADDRINUSE = EADDRINUSE -import helper_random _DISCONNECTED = frozenset(( @@ -128,7 +129,7 @@ def read(obj): obj.handle_read_event() except _reraised_exceptions: raise - except: + except BaseException: obj.handle_error() @@ -141,7 +142,7 @@ def write(obj): obj.handle_write_event() except _reraised_exceptions: raise - except: + except BaseException: obj.handle_error() @@ -209,7 +210,7 @@ def _exception(obj): obj.handle_expt_event() except _reraised_exceptions: raise - except: + except BaseException: obj.handle_error() @@ -232,7 +233,7 @@ def readwrite(obj, flags): obj.handle_close() except _reraised_exceptions: raise - except: + except BaseException: obj.handle_error() @@ -788,7 +789,7 @@ class dispatcher: def log_info(self, message, log_type='info'): """Conditionally print a message""" if log_type not in self.ignore_log_types: - print '%s: %s' % log_type, message + print '%s: %s' % (log_type, message) def handle_read_event(self): """Handle a read event""" @@ -850,7 +851,7 @@ class dispatcher: # sometimes a user repr method will crash. try: self_repr = repr(self) - except: + except BaseException: self_repr = '<__repr__(self) failed for object at %0x>' % id(self) self.log_info( @@ -975,7 +976,7 @@ def close_all(map=None, ignore_all=False): raise except _reraised_exceptions: raise - except: + except BaseException: if not ignore_all: raise map.clear() diff --git a/src/network/bmproto.py b/src/network/bmproto.py index 72639ba6..d3f5bfce 100644 --- a/src/network/bmproto.py +++ b/src/network/bmproto.py @@ -11,25 +11,26 @@ import socket import struct import time +import addresses +import helper_random +import knownnodes +import network.connectionpool +import protocol +import shared +import state from bmconfigparser import BMConfigParser from debug import logger from inventory import Inventory -import knownnodes from network.advanceddispatcher import AdvancedDispatcher +from network.bmobject import ( + BMObject, BMObjectAlreadyHaveError, BMObjectExpiredError, BMObjectInsufficientPOWError, BMObjectInvalidDataError, + BMObjectInvalidError, BMObjectUnwantedStreamError +) from network.dandelion import Dandelion -from network.bmobject import BMObject, BMObjectInsufficientPOWError, BMObjectInvalidDataError, \ - BMObjectExpiredError, BMObjectUnwantedStreamError, BMObjectInvalidError, BMObjectAlreadyHaveError -import network.connectionpool from network.node import Node from network.objectracker import ObjectTracker from network.proxy import ProxyError - -import addresses -from queues import objectProcessorQueue, portCheckerQueue, invQueue, addrQueue -import shared -import state -import protocol -import helper_random +from queues import addrQueue, invQueue, objectProcessorQueue, portCheckerQueue class BMProtoError(ProxyError): @@ -74,7 +75,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker): self.local = False def bm_proto_reset(self): - """TBC""" + """Reset the bitmessage object parser""" self.magic = None self.command = None self.payloadLength = 0 @@ -86,7 +87,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker): self.object = None def state_bm_header(self): - """Predicate to indicate the prescence of a header""" + """Predicate (with logging) to indicate the prescence of a header""" self.magic, self.command, self.payloadLength, self.checksum = protocol.Header.unpack( self.read_buf[:protocol.Header.size]) @@ -106,7 +107,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker): return True def state_bm_command(self): - """TBC""" + """Predicate (with logging) to indicate the presence of a command""" self.payload = self.read_buf[:self.payloadLength] if self.checksum != hashlib.sha512(self.payload).digest()[0:4]: logger.debug("Bad checksum, ignoring") @@ -295,16 +296,16 @@ class BMProto(AdvancedDispatcher, ObjectTracker): raise BMProtoInsufficientDataError() def bm_command_error(self): - """TBC""" + """Decode an error message and log it""" # pylint: disable=unused-variable fatalStatus, banTime, inventoryVector, errorText = self.decode_payload_content("vvlsls") logger.error("%s:%i error: %i, %s", self.destination.host, self.destination.port, fatalStatus, errorText) return True def bm_command_getdata(self): - """TBC""" + """Decode object data, conditionally append a newly created object to the write buffer""" items = self.decode_payload_content("l32s") - # ..todo:: skip? + # .. todo:: skip? if time.time() < self.skipUntil: return True # .. todo:: make this more asynchronous @@ -349,13 +350,11 @@ class BMProto(AdvancedDispatcher, ObjectTracker): return True def bm_command_inv(self): - """TBC""" + """Non-dandelion announce""" return self._command_inv(False) def bm_command_dinv(self): - """ - Dandelion stem announce - """ + """Dandelion stem announce""" return self._command_inv(True) def bm_command_object(self): @@ -442,12 +441,12 @@ class BMProto(AdvancedDispatcher, ObjectTracker): return True def bm_command_portcheck(self): - """TBC""" + """Add a job port of a peer""" portCheckerQueue.put(state.Peer(self.destination, self.peerNode.port)) return True def bm_command_ping(self): - """TBC""" + """Respond to a ping""" self.append_write_buf(protocol.CreatePacket('pong')) return True @@ -457,8 +456,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker): return True def bm_command_verack(self): - """TBC""" - + """Return True if a verack has been sent, False otherwise""" self.verackReceived = True if self.verackSent: if self.isSSL: @@ -469,7 +467,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker): return True def bm_command_version(self): - """TBC""" + """Determine and log protocol version and other details""" self.remoteProtocolVersion, self.services, self.timestamp, self.sockNode, self.peerNode, self.nonce, \ self.userAgent, self.streams = self.decode_payload_content("IQQiiQlsLv") @@ -547,7 +545,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker): logger.debug('Closed connection to %s because we are already connected to that IP.', str(self.destination)) return False - except: + except BaseException: pass if not self.isOutbound: # incoming from a peer we're connected to as outbound, or server full diff --git a/src/network/tcp.py b/src/network/tcp.py index 8aa905fe..814c8cfa 100644 --- a/src/network/tcp.py +++ b/src/network/tcp.py @@ -4,34 +4,31 @@ tcp.py ====== """ -from __future__ import absolute_import - import math -import time -import socket import random +import socket +import time -from debug import logger -from helper_random import randomBytes -import helper_random -from inventory import Inventory -import knownnodes -from network.advanceddispatcher import AdvancedDispatcher - -from network.bmproto import BMProto -import network.connectionpool -from network.dandelion import Dandelion -import network.asyncore_pollchoose as asyncore -from network.objectracker import ObjectTracker -from network.socks5 import Socks5Connection -from network.socks4a import Socks4aConnection -from network.tls import TLSDispatcher import addresses -from bmconfigparser import BMConfigParser -from queues import invQueue, UISignalQueue, receiveDataQueue +import helper_random +import knownnodes +import network.asyncore_pollchoose as asyncore +import network.connectionpool +import protocol import shared import state -import protocol +from bmconfigparser import BMConfigParser +from debug import logger +from helper_random import randomBytes +from inventory import Inventory +from network.advanceddispatcher import AdvancedDispatcher +from network.bmproto import BMProto +from network.dandelion import Dandelion +from network.objectracker import ObjectTracker +from network.socks4a import Socks4aConnection +from network.socks5 import Socks5Connection +from network.tls import TLSDispatcher +from queues import UISignalQueue, invQueue, receiveDataQueue class TCPConnection(BMProto, TLSDispatcher): # pylint: disable=too-many-instance-attributes diff --git a/src/pathmagic.py b/src/pathmagic.py new file mode 100644 index 00000000..4c153b3a --- /dev/null +++ b/src/pathmagic.py @@ -0,0 +1,14 @@ +""" +pathmagic.py +=========== + +Makes the app portable by adding the parent directory to the path and changing to that directory. Putting this in a +seperate module make it re-usable and does not confuse isort and friends due to code interspersed among the imports. +""" + +import os +import sys + +app_dir = os.path.dirname(os.path.abspath(__file__)) +os.chdir(app_dir) +sys.path.insert(0, app_dir) diff --git a/src/proofofwork.py b/src/proofofwork.py index aeb782c8..47737534 100644 --- a/src/proofofwork.py +++ b/src/proofofwork.py @@ -11,18 +11,17 @@ import hashlib import os import sys import time -from struct import unpack, pack +from struct import pack, unpack from subprocess import call -import paths import openclpow +import paths import queues -import tr import state +import tr from bmconfigparser import BMConfigParser from debug import logger - bitmsglib = 'bitmsghash.so' bmpow = None @@ -132,18 +131,13 @@ def _doGPUPoW(target, initialHash): trialValue, = unpack('>Q', hashlib.sha512(hashlib.sha512(pack('>Q', nonce) + initialHash).digest()).digest()[0:8]) if trialValue > target: deviceNames = ", ".join(gpu.name for gpu in openclpow.enabledGpus) - queues.UISignalQueue.put( - ( - 'updateStatusBar', - ( - tr._translate( - "MainWindow", - 'Your GPU(s) did not calculate correctly, disabling OpenCL. Please report to the developers.' - ), - 1 - ) - ) - ) + queues.UISignalQueue.put(( + 'updateStatusBar', ( + tr._translate( + "MainWindow", + 'Your GPU(s) did not calculate correctly, disabling OpenCL. Please report to the developers.' + ), + 1))) logger.error( "Your GPUs (%s) did not calculate correctly, disabling OpenCL. Please report to the developers.", deviceNames) @@ -198,7 +192,7 @@ def getPowType(): def notifyBuild(tried=False): - """TBC""" + """Notify the user of the success or otherwise of building the PoW C module""" if bmpow: queues.UISignalQueue.put(('updateStatusBar', (tr._translate( @@ -221,7 +215,7 @@ def notifyBuild(tried=False): def buildCPoW(): - """TBC""" + """Attempt to build the PoW C module""" if bmpow is not None: return if paths.frozen is not None: @@ -250,7 +244,7 @@ def run(target, initialHash): """Run the proof of work thread""" if state.shutdown != 0: - raise + raise # pylint: disable=misplaced-bare-raise target = int(target) if openclpow.openclEnabled(): try: @@ -287,7 +281,7 @@ def run(target, initialHash): def resetPoW(): - """TBC""" + """Initialise the OpenCL PoW""" openclpow.initCL() @@ -295,7 +289,7 @@ def resetPoW(): def init(): - """TBC""" + """Initialise PoW""" # pylint: disable=global-statement global bitmsglib, bmpow diff --git a/src/pybitmessage b/src/pybitmessage index decebfff..ed4dcf0d 100644 --- a/src/pybitmessage +++ b/src/pybitmessage @@ -1,8 +1,12 @@ -#!/usr/bin/python2.7 +#!/usr/bin/env python2.7 import os +import sys + import pkg_resources +import pybitmessage.pathmagic + dist = pkg_resources.get_distribution('pybitmessage') script_file = os.path.join(dist.location, dist.key, 'bitmessagemain.py') new_globals = globals() diff --git a/src/upnp.py b/src/upnp.py index c89beb96..af206384 100644 --- a/src/upnp.py +++ b/src/upnp.py @@ -7,23 +7,23 @@ Reference: http://mattscodecave.com/posts/using-python-and-upnp-to-forward-a-por from __future__ import absolute_import import httplib -from random import randint import socket -from struct import unpack import threading import time import urllib2 +from random import randint +from struct import unpack from urlparse import urlparse from xml.dom.minidom import Document, parseString -from bmconfigparser import BMConfigParser -from debug import logger -from network.connectionpool import BMConnectionPool -from helper_threading import StoppableThread import queues import shared import state import tr +from bmconfigparser import BMConfigParser +from debug import logger +from helper_threading import StoppableThread +from network.connectionpool import BMConnectionPool def createRequestXML(service, action, arguments=None): @@ -85,7 +85,7 @@ class UPnPError(Exception): class Router: # pylint: disable=old-style-class - """TBC""" + """Encapulate routing""" name = "" path = "" address = None