From 6fcac89dd5d0a3b589fa6b6fe827428536dee639 Mon Sep 17 00:00:00 2001 From: Romain Bignon Date: Sat, 17 May 2014 13:37:47 +0200 Subject: [PATCH] first step in python3 support --- modules/creditmutuel/browser.py | 7 +- modules/creditmutuel/pages.py | 6 +- weboob/applications/boobank/boobank.py | 23 ++-- weboob/capabilities/bank.py | 2 + weboob/capabilities/base.py | 1 + weboob/core/backendscfg.py | 5 +- weboob/core/bcall.py | 5 +- weboob/core/repositories.py | 76 ++++++------ weboob/core/scheduler.py | 11 +- weboob/tools/application/base.py | 30 +++-- weboob/tools/application/console.py | 107 +++++++++-------- .../application/formatters/iformatter.py | 4 +- weboob/tools/application/formatters/json.py | 6 +- weboob/tools/application/formatters/table.py | 4 +- weboob/tools/application/media_player.py | 18 +-- weboob/tools/application/qt/qt.py | 6 +- weboob/tools/application/repl.py | 113 +++++++++--------- weboob/tools/browser/browser.py | 11 +- weboob/tools/browser/firefox_cookies.py | 4 +- weboob/tools/browser2/browser.py | 9 +- weboob/tools/browser2/cookies.py | 5 +- weboob/tools/browser2/filters.py | 7 +- weboob/tools/browser2/page.py | 12 +- weboob/tools/compat.py | 37 ++++++ weboob/tools/misc.py | 1 + 25 files changed, 302 insertions(+), 208 deletions(-) create mode 100644 weboob/tools/compat.py diff --git a/modules/creditmutuel/browser.py b/modules/creditmutuel/browser.py index 84aecc37..11c3362b 100644 --- a/modules/creditmutuel/browser.py +++ b/modules/creditmutuel/browser.py @@ -18,9 +18,14 @@ # along with weboob. If not, see . -from urlparse import urlsplit, parse_qsl, urlparse +try: + from urlparse import urlsplit, parse_qsl, urlparse +except ImportError: + from urllib.parse import urlsplit, parse_qsl, urlparse + from datetime import datetime, timedelta +from weboob.tools.compat import basestring from weboob.tools.browser2 import LoginBrowser, URL, Wget, need_login from weboob.tools.exceptions import BrowserIncorrectPassword from weboob.capabilities.bank import Transfer, TransferError diff --git a/modules/creditmutuel/pages.py b/modules/creditmutuel/pages.py index 7a7a555d..170fad57 100644 --- a/modules/creditmutuel/pages.py +++ b/modules/creditmutuel/pages.py @@ -18,7 +18,11 @@ # along with weboob. If not, see . -from urlparse import urlparse, parse_qs +try: + from urlparse import urlparse, parse_qs +except ImportError: + from urllib.parse import urlparse, parse_qs + from decimal import Decimal import re from dateutil.relativedelta import relativedelta diff --git a/weboob/applications/boobank/boobank.py b/weboob/applications/boobank/boobank.py index 7a327ad3..b8745c37 100644 --- a/weboob/applications/boobank/boobank.py +++ b/weboob/applications/boobank/boobank.py @@ -17,6 +17,7 @@ # You should have received a copy of the GNU Affero General Public License # along with weboob. If not, see . +from __future__ import print_function import datetime, uuid from dateutil.relativedelta import relativedelta @@ -321,15 +322,15 @@ class Boobank(ReplApplication): account = self.get_object(id, 'get_account', []) if not account: - print >>sys.stderr, 'Error: account "%s" not found (Hint: try the command "list")' % id + print('Error: account "%s" not found (Hint: try the command "list")' % id, file=sys.stderr) return 2 if end_date is not None: try: end_date = parse_date(end_date) except ValueError: - print >>sys.stderr, '"%s" is an incorrect date format (for example "%s")' % \ - (end_date, (datetime.date.today() - relativedelta(months=1)).strftime('%Y-%m-%d')) + print('"%s" is an incorrect date format (for example "%s")' % \ + (end_date, (datetime.date.today() - relativedelta(months=1)).strftime('%Y-%m-%d')), file=sys.stderr) return 3 old_count = self.options.count self.options.count = None @@ -399,7 +400,7 @@ class Boobank(ReplApplication): account = self.get_object(id_from, 'get_account', []) if not account: - print >>sys.stderr, 'Error: account %s not found' % id_from + print('Error: account %s not found' % id_from, file=sys.stderr) return 1 if not id_to: @@ -415,13 +416,13 @@ class Boobank(ReplApplication): id_to, backend_name_to = self.parse_id(id_to) if account.backend != backend_name_to: - print >>sys.stderr, "Transfer between different backends is not implemented" + print("Transfer between different backends is not implemented", file=sys.stderr) return 4 try: amount = Decimal(amount) except (TypeError, ValueError, InvalidOperation): - print >>sys.stderr, 'Error: please give a decimal amount to transfer' + print('Error: please give a decimal amount to transfer', file=sys.stderr) return 2 if self.interactive: @@ -434,10 +435,10 @@ class Boobank(ReplApplication): to = recipient.label break - print 'Amount: %s%s' % (amount, account.currency_text) - print 'From: %s' % account.label - print 'To: %s' % to - print 'Reason: %s' % (reason or '') + print('Amount: %s%s' % (amount, account.currency_text)) + print('From: %s' % account.label) + print('To: %s' % to) + print('Reason: %s' % (reason or '')) if not self.ask('Are you sure to do this transfer?', default=True): return @@ -453,7 +454,7 @@ class Boobank(ReplApplication): """ account = self.get_object(id, 'get_account', []) if not account: - print >>sys.stderr, 'Error: account "%s" not found (Hint: try the command "list")' % id + print('Error: account "%s" not found (Hint: try the command "list")' % id, file=sys.stderr) return 2 self.start_format() diff --git a/weboob/capabilities/bank.py b/weboob/capabilities/bank.py index b2a32280..c3a9892e 100644 --- a/weboob/capabilities/bank.py +++ b/weboob/capabilities/bank.py @@ -22,6 +22,8 @@ from datetime import date, datetime from binascii import crc32 import re +from weboob.tools.compat import basestring, long + from .base import CapBaseObject, Field, StringField, DateField, DecimalField, IntField, UserError, Currency from .collection import ICapCollection diff --git a/weboob/capabilities/base.py b/weboob/capabilities/base.py index 6ca1fa4a..5b660203 100644 --- a/weboob/capabilities/base.py +++ b/weboob/capabilities/base.py @@ -24,6 +24,7 @@ import re from decimal import Decimal from copy import deepcopy, copy +from weboob.tools.compat import unicode, long from weboob.tools.misc import to_unicode from weboob.tools.date import new_date, new_datetime from weboob.tools.ordereddict import OrderedDict diff --git a/weboob/core/backendscfg.py b/weboob/core/backendscfg.py index 2a81cbfc..601cd261 100644 --- a/weboob/core/backendscfg.py +++ b/weboob/core/backendscfg.py @@ -23,7 +23,10 @@ import stat import os import sys -from ConfigParser import RawConfigParser, DuplicateSectionError +try: + from ConfigParser import RawConfigParser, DuplicateSectionError +except ImportError: + from configparser import RawConfigParser, DuplicateSectionError from logging import warning __all__ = ['BackendsConfig', 'BackendAlreadyExists'] diff --git a/weboob/core/bcall.py b/weboob/core/bcall.py index 32fe59bd..5fbd6e87 100644 --- a/weboob/core/bcall.py +++ b/weboob/core/bcall.py @@ -20,7 +20,10 @@ from copy import copy from threading import Thread -import Queue +try: + import Queue +except ImportError: + import queue as Queue from weboob.capabilities.base import CapBaseObject from weboob.tools.misc import get_backtrace diff --git a/weboob/core/repositories.py b/weboob/core/repositories.py index 62fd4df3..b9dba7e0 100644 --- a/weboob/core/repositories.py +++ b/weboob/core/repositories.py @@ -18,7 +18,7 @@ # along with weboob. If not, see . - +from __future__ import print_function import imp import tarfile import posixpath @@ -32,29 +32,24 @@ from tempfile import NamedTemporaryFile from datetime import datetime from contextlib import closing from compileall import compile_dir -from StringIO import StringIO +from io import BytesIO from .modules import Module from weboob.tools.log import getLogger from weboob.tools.misc import to_unicode -from weboob.tools.browser import StandardBrowser, BrowserUnavailable -from ConfigParser import RawConfigParser, DEFAULTSECT +from weboob.tools.browser2.browser import BaseBrowser, Weboob as WeboobProfile +try: + from configparser import RawConfigParser, DEFAULTSECT +except ImportError: + from ConfigParser import RawConfigParser, DEFAULTSECT + +BrowserUnavailable = object() __all__ = ['IProgress', 'ModuleInstallError', 'ModuleInfo', 'RepositoryUnavailable', 'Repository', 'Versions', 'Repositories', 'InvalidSignature', 'Keyring'] -class WeboobBrowser(StandardBrowser): - """ - Browser with a specific useragent. - """ - - @classmethod - def set_version(klass, version): - klass.USER_AGENT = 'weboob/%s' % version - - class ModuleInfo(object): """ Information about a module available on a repository. @@ -125,7 +120,8 @@ class Repository(object): KEYDIR = '.keys' KEYRING = 'trusted.gpg' - def __init__(self, url): + def __init__(self, browser, url): + self.browser = browser self.url = url self.name = u'' self.update = 0 @@ -179,9 +175,8 @@ class Repository(object): fp = open(filename, 'r') else: # This is a remote repository, download file - browser = WeboobBrowser() try: - fp = browser.openurl(posixpath.join(self.url, self.INDEX)) + fp = BytesIO(self.browser.open(posixpath.join(self.url, self.INDEX)).content) except BrowserUnavailable as e: raise RepositoryUnavailable(unicode(e)) @@ -208,20 +203,19 @@ class Repository(object): if not keyring.exists() or self.key_update > keyring.version: # This is a remote repository, download file - browser = WeboobBrowser() try: - keyring_data = browser.readurl(posixpath.join(self.url, self.KEYRING)) - sig_data = browser.readurl(posixpath.join(self.url, self.KEYRING + '.sig')) + keyring_data = self.browser.open(posixpath.join(self.url, self.KEYRING)).content + sig_data = self.browser.open(posixpath.join(self.url, self.KEYRING + '.sig')).content except BrowserUnavailable as e: raise RepositoryUnavailable(unicode(e)) if keyring.exists(): if not keyring.is_valid(keyring_data, sig_data): raise InvalidSignature('the keyring itself') - print 'The keyring was updated (and validated by the previous one).' + print('The keyring was updated (and validated by the previous one).') else: - print 'First time saving the keyring, blindly accepted.' + print('First time saving the keyring, blindly accepted.') keyring.save(keyring_data, self.key_update) - print keyring + print(keyring) def parse_index(self, fp): """ @@ -275,7 +269,7 @@ class Repository(object): :param filename: file to save index :type filename: str """ - print 'Rebuild index' + print('Rebuild index') self.modules.clear() if os.path.isdir(os.path.join(path, self.KEYDIR)): @@ -298,7 +292,7 @@ class Repository(object): if fp: fp.close() except Exception as e: - print >>sys.stderr, 'Unable to build module %s: [%s] %s' % (name, type(e).__name__, e) + print('Unable to build module %s: [%s] %s' % (name, type(e).__name__, e), file=sys.stderr) else: m = ModuleInfo(module.name) m.version = self.get_tree_mtime(module_path) @@ -388,10 +382,10 @@ class Versions(object): class IProgress(object): def progress(self, percent, message): - print '=== [%3.0f%%] %s' % (percent*100, message) + print('=== [%3.0f%%] %s' % (percent*100, message)) def error(self, message): - print >>sys.stderr, 'ERROR: %s' % message + print('ERROR: %s' % message, file=sys.stderr) class ModuleInstallError(Exception): @@ -425,7 +419,11 @@ class Repositories(object): def __init__(self, workdir, datadir, version): self.logger = getLogger('repositories') self.version = version - WeboobBrowser.set_version(version) + + class WeboobBrowser(BaseBrowser): + PROFILE = WeboobProfile(version) + + self.browser = WeboobBrowser() self.workdir = workdir self.datadir = datadir @@ -503,10 +501,10 @@ class Repositories(object): for name in sorted(os.listdir(self.repos_dir)): path = os.path.join(self.repos_dir, name) try: - repository = Repository(path) + repository = Repository(self.browser, path) self.repositories.append(repository) except RepositoryUnavailable as e: - print >>sys.stderr, 'Unable to load repository %s (%s), try to update repositories.' % (name, e) + print('Unable to load repository %s (%s), try to update repositories.' % (name, e), file=sys.stderr) def get_module_icon_path(self, module): return os.path.join(self.icons_dir, '%s.png' % module.name) @@ -530,14 +528,13 @@ class Repositories(object): else: icon_url = module.url.replace('.tar.gz', '.png') - browser = WeboobBrowser() try: - icon = browser.openurl(icon_url) + icon = self.browser.open(icon_url) except BrowserUnavailable: pass # no icon, no problem else: with open(dest_path, 'wb') as fp: - fp.write(icon.read()) + fp.write(icon.content) def _parse_source_list(self): l = [] @@ -564,7 +561,7 @@ class Repositories(object): gpgv = Keyring.find_gpgv() for line in self._parse_source_list(): progress.progress(0.0, 'Getting %s' % line) - repository = Repository(line) + repository = Repository(self.browser, line) filename = self.url2filename(repository.url) prio_filename = '%02d-%s' % (len(self.repositories), filename) repo_path = os.path.join(self.repos_dir, prio_filename) @@ -587,7 +584,7 @@ class Repositories(object): """ l = [] for line in self._parse_source_list(): - repository = Repository(line) + repository = Repository(self.browser, line) filename = self.url2filename(repository.url) prio_filename = '%02d-%s' % (len(l), filename) repo_path = os.path.join(self.repos_dir, prio_filename) @@ -657,17 +654,16 @@ class Repositories(object): else: raise ModuleInstallError('The latest version of %s is already installed' % module.name) - browser = WeboobBrowser() progress.progress(0.2, 'Downloading module...') try: - tardata = browser.readurl(module.url) + tardata = self.browser.open(module.url).content except BrowserUnavailable as e: raise ModuleInstallError('Unable to fetch module: %s' % e) # Check signature if module.signed and Keyring.find_gpgv(): progress.progress(0.5, 'Checking module authenticity...') - sig_data = browser.readurl(posixpath.join(module.url + '.sig')) + sig_data = self.browser.open(posixpath.join(module.url + '.sig')).content keyring_path = os.path.join(self.keyrings_dir, self.url2filename(module.repo_url)) keyring = Keyring(keyring_path) if not keyring.exists(): @@ -679,7 +675,7 @@ class Repositories(object): if os.path.isdir(module_dir): shutil.rmtree(module_dir) progress.progress(0.7, 'Setting up module...') - with closing(tarfile.open('', 'r:gz', StringIO(tardata))) as tar: + with closing(tarfile.open('', 'r:gz', BytesIO(tardata))) as tar: tar.extractall(self.modules_dir) if not os.path.isdir(module_dir): raise ModuleInstallError('The archive for %s looks invalid.' % module.name) @@ -776,7 +772,7 @@ class Keyring(object): stderr=subprocess.PIPE) out, err = proc.communicate(data) if proc.returncode or 'GOODSIG' not in out or 'VALIDSIG' not in out: - print >>sys.stderr, out, err + print(out, err, file=sys.stderr) return False return True diff --git a/weboob/core/scheduler.py b/weboob/core/scheduler.py index aed3fbd5..2b3a0378 100644 --- a/weboob/core/scheduler.py +++ b/weboob/core/scheduler.py @@ -18,9 +18,14 @@ # along with weboob. If not, see . +from __future__ import print_function +from threading import Event, RLock +try: + from threading import _Timer as Timer +except ImportError: + from threading import Timer -from threading import Timer, Event, RLock, _Timer from weboob.tools.log import getLogger from weboob.tools.misc import get_backtrace @@ -45,14 +50,14 @@ class IScheduler(object): raise NotImplementedError() -class RepeatedTimer(_Timer): +class RepeatedTimer(Timer): def run(self): while not self.finished.isSet(): try: self.function(*self.args, **self.kwargs) except Exception: # do not stop timer because of an exception - print get_backtrace() + print(get_backtrace()) self.finished.wait(self.interval) self.finished.set() diff --git a/weboob/tools/application/base.py b/weboob/tools/application/base.py index 8fce3c89..c0b5a618 100644 --- a/weboob/tools/application/base.py +++ b/weboob/tools/application/base.py @@ -18,6 +18,8 @@ # along with weboob. If not, see . +from __future__ import print_function + import logging import optparse from optparse import OptionGroup, OptionParser @@ -27,7 +29,6 @@ import tempfile import warnings from weboob.capabilities.base import ConversionWarning, CapBaseObject -from weboob.tools.browser.browser import FormFieldConversionWarning from weboob.core import Weboob, CallErrors from weboob.core.backendscfg import BackendsConfig from weboob.tools.config.iconfig import ConfigError @@ -295,9 +296,9 @@ class BaseApplication(object): if isinstance(error, MoreResultsAvailable): return False - print >>sys.stderr, u'Error(%s): %s' % (backend.name, error) + print(u'Error(%s): %s' % (backend.name, error), file=sys.stderr) if logging.root.level == logging.DEBUG: - print >>sys.stderr, backtrace + print(backtrace, file=sys.stderr) else: return True @@ -322,7 +323,7 @@ class BaseApplication(object): ask_debug_mode = True if ask_debug_mode: - print >>sys.stderr, debugmsg + print(debugmsg, file=sys.stderr) def parse_args(self, args): self.options, args = self._parser.parse_args(args) @@ -333,7 +334,7 @@ class BaseApplication(object): if not option.help is optparse.SUPPRESS_HELP: items.update(str(option).split('/')) items.update(self._get_completions()) - print ' '.join(items) + print(' '.join(items)) sys.exit(0) if self.options.debug or self.options.save_responses: @@ -350,13 +351,18 @@ class BaseApplication(object): # this only matters to developers if not self.options.debug and not self.options.save_responses: warnings.simplefilter('ignore', category=ConversionWarning) - warnings.simplefilter('ignore', category=FormFieldConversionWarning) + try: + from weboob.tools.browser.browser import FormFieldConversionWarning + except ImportError: + pass + else: + warnings.simplefilter('ignore', category=FormFieldConversionWarning) handlers = [] if self.options.save_responses: responses_dirname = tempfile.mkdtemp(prefix='weboob_session_') - print >>sys.stderr, 'Debug data will be saved in this directory: %s' % responses_dirname + print('Debug data will be saved in this directory: %s' % responses_dirname, file=sys.stderr) log_settings['save_responses'] = True log_settings['responses_dirname'] = responses_dirname handlers.append(self.create_logging_file_handler(os.path.join(responses_dirname, 'debug.log'))) @@ -424,12 +430,12 @@ class BaseApplication(object): cls.setup_logging(logging.INFO, [cls.create_default_logger()]) if args is None: - args = [(sys.stdin.encoding and arg.decode(sys.stdin.encoding) or to_unicode(arg)) for arg in sys.argv] + args = [(sys.stdin.encoding and isinstance(arg, bytes) and arg.decode(sys.stdin.encoding) or to_unicode(arg)) for arg in sys.argv] try: app = cls() except BackendsConfig.WrongPermissions as e: - print >>sys.stderr, e + print(e, file=sys.stderr) sys.exit(1) try: @@ -437,12 +443,12 @@ class BaseApplication(object): args = app.parse_args(args) sys.exit(app.main(args)) except KeyboardInterrupt: - print >>sys.stderr, 'Program killed by SIGINT' + print('Program killed by SIGINT', file=sys.stderr) sys.exit(0) except EOFError: sys.exit(0) except ConfigError as e: - print >>sys.stderr, 'Configuration error: %s' % e + print('Configuration error: %s' % e, file=sys.stderr) sys.exit(1) except CallErrors as e: try: @@ -451,7 +457,7 @@ class BaseApplication(object): pass sys.exit(1) except ResultsConditionError as e: - print >>sys.stderr, '%s' % e + print('%s' % e, file=sys.stderr) sys.exit(1) finally: app.deinit() diff --git a/weboob/tools/application/console.py b/weboob/tools/application/console.py index badf1b8d..8ec602c9 100644 --- a/weboob/tools/application/console.py +++ b/weboob/tools/application/console.py @@ -18,6 +18,7 @@ # along with weboob. If not, see . +from __future__ import print_function from copy import copy import getpass @@ -110,7 +111,7 @@ class ConsoleApplication(BaseApplication): ret = super(ConsoleApplication, self).load_backends(*args, **kwargs) for err in errors: - print >>sys.stderr, 'Error(%s): %s' % (err.backend_name, err) + print('Error(%s): %s' % (err.backend_name, err), file=sys.stderr) if self.ask('Do you want to reconfigure this backend?', default=True): self.edit_backend(err.backend_name) self.load_backends(names=[err.backend_name]) @@ -124,7 +125,7 @@ class ConsoleApplication(BaseApplication): def check_loaded_backends(self, default_config=None): while len(self.enabled_backends) == 0: - print 'Warning: there is currently no configured backend for %s' % self.APPNAME + print('Warning: there is currently no configured backend for %s' % self.APPNAME) if not os.isatty(sys.stdout.fileno()) or not self.ask('Do you want to configure backends?', default=True): return False @@ -136,7 +137,7 @@ class ConsoleApplication(BaseApplication): r = '' while r != 'q': modules = [] - print '\nAvailable modules:' + print('\nAvailable modules:') for name, info in sorted(self.weboob.repositories.get_all_modules_info().iteritems()): if not self.is_module_loadable(info): continue @@ -150,16 +151,16 @@ class ConsoleApplication(BaseApplication): loaded = 2 else: loaded += 1 - print '%s%d)%s [%s] %s%-15s%s %s' % (self.BOLD, len(modules), self.NC, loaded, - self.BOLD, name, self.NC, info.description) - print '%sa) --all--%s install all backends' % (self.BOLD, self.NC) - print '%sq)%s --stop--\n' % (self.BOLD, self.NC) + print('%s%d)%s [%s] %s%-15s%s %s' % (self.BOLD, len(modules), self.NC, loaded, + self.BOLD, name, self.NC, info.description)) + print('%sa) --all--%s install all backends' % (self.BOLD, self.NC)) + print('%sq)%s --stop--\n' % (self.BOLD, self.NC)) r = self.ask('Select a backend to create (q to stop)', regexp='^(\d+|q|a)$') if str(r).isdigit(): i = int(r) - 1 if i < 0 or i >= len(modules): - print >>sys.stderr, 'Error: %s is not a valid choice' % r + print('Error: %s is not a valid choice' % r, file=sys.stderr) continue name = modules[i] try: @@ -167,7 +168,7 @@ class ConsoleApplication(BaseApplication): if inst: self.load_backends(names=[inst]) except (KeyboardInterrupt, EOFError): - print '\nAborted.' + print('\nAborted.') elif r == 'a': try: for name in modules: @@ -177,11 +178,11 @@ class ConsoleApplication(BaseApplication): if inst: self.load_backends(names=[inst]) except (KeyboardInterrupt, EOFError): - print '\nAborted.' + print('\nAborted.') else: break - print 'Right right!' + print('Right right!') def _handle_options(self): self.load_default_backends() @@ -202,7 +203,7 @@ class ConsoleApplication(BaseApplication): try: super(ConsoleApplication, klass).run(args) except BackendNotFound as e: - print 'Error: Backend "%s" not found.' % e + print('Error: Backend "%s" not found.' % e) sys.exit(1) def do(self, function, *args, **kwargs): @@ -234,11 +235,11 @@ class ConsoleApplication(BaseApplication): backend = None if not backend: - print >>sys.stderr, 'Backend "%s" does not exist.' % name + print('Backend "%s" does not exist.' % name, file=sys.stderr) return 1 if not backend.has_caps(ICapAccount) or backend.klass.ACCOUNT_REGISTER_PROPERTIES is None: - print >>sys.stderr, 'You can\'t register a new account with %s' % name + print('You can\'t register a new account with %s' % name, file=sys.stderr) return 1 account = Account() @@ -252,17 +253,17 @@ class ConsoleApplication(BaseApplication): for key, prop in backend.klass.ACCOUNT_REGISTER_PROPERTIES.iteritems(): if not asked_config: asked_config = True - print 'Configuration of new account %s' % website - print '-----------------------------%s' % ('-' * len(website)) + print('Configuration of new account %s' % website) + print('-----------------------------%s' % ('-' * len(website))) p = copy(prop) p.set(self.ask(prop, default=account.properties[key].get() if (key in account.properties) else prop.default)) account.properties[key] = p if asked_config: - print '-----------------------------%s' % ('-' * len(website)) + print('-----------------------------%s' % ('-' * len(website))) try: backend.klass.register_account(account) except AccountRegisterError as e: - print u'%s' % e + print(u'%s' % e) if self.ask('Do you want to try again?', default=True): continue else: @@ -283,10 +284,10 @@ class ConsoleApplication(BaseApplication): try: self.weboob.repositories.install(name) except ModuleInstallError as e: - print >>sys.stderr, 'Unable to install module "%s": %s' % (name, e) + print('Unable to install module "%s": %s' % (name, e), file=sys.stderr) return False - print '' + print('') return True def edit_backend(self, name, params=None): @@ -304,7 +305,7 @@ class ConsoleApplication(BaseApplication): if minfo is None: raise ModuleLoadError(name, 'Module does not exist') if not minfo.is_installed(): - print 'Module "%s" is available but not installed.' % minfo.name + print('Module "%s" is available but not installed.' % minfo.name) self.install_module(minfo) module = self.weboob.modules_loader.get_or_load_module(name) config = module.config @@ -315,7 +316,7 @@ class ConsoleApplication(BaseApplication): params = items config = module.config.load(self.weboob, bname, name, params, nofail=True) except ModuleLoadError as e: - print >>sys.stderr, 'Unable to load module "%s": %s' % (name, e) + print('Unable to load module "%s": %s' % (name, e), file=sys.stderr) return 1 # ask for params non-specified on command-line arguments @@ -323,18 +324,18 @@ class ConsoleApplication(BaseApplication): for key, value in config.iteritems(): if not asked_config: asked_config = True - print '' - print 'Configuration of backend %s' % module.name - print '-------------------------%s' % ('-' * len(module.name)) + print('') + print('Configuration of backend %s' % module.name) + print('-------------------------%s' % ('-' * len(module.name))) if key not in params or edit: params[key] = self.ask(value, default=params[key] if (key in params) else value.default) else: - print u' [%s] %s: %s' % (key, value.description, '(masked)' if value.masked else params[key]) + print(u' [%s] %s: %s' % (key, value.description, '(masked)' if value.masked else params[key])) if asked_config: - print '-------------------------%s' % ('-' * len(module.name)) + print('-------------------------%s' % ('-' * len(module.name))) while not edit and self.weboob.backends_config.backend_exists(name): - print >>sys.stderr, 'Backend instance "%s" already exists in "%s"' % (name, self.weboob.backends_config.confpath) + print('Backend instance "%s" already exists in "%s"' % (name, self.weboob.backends_config.confpath), file=sys.stderr) if not self.ask('Add new backend for module "%s"?' % module.name, default=False): return 1 @@ -347,10 +348,10 @@ class ConsoleApplication(BaseApplication): continue config[key].set(value) config.save(edit=edit) - print 'Backend "%s" successfully %s.' % (name, 'edited' if edit else 'added') + print('Backend "%s" successfully %s.' % (name, 'edited' if edit else 'added')) return name except BackendAlreadyExists: - print >>sys.stderr, 'Backend "%s" already exists.' % name + print('Backend "%s" already exists.' % name, file=sys.stderr) return 1 def ask(self, question, default=None, masked=None, regexp=None, choices=None, tiny=None): @@ -395,7 +396,7 @@ class ConsoleApplication(BaseApplication): question = u'[%s] %s' % (v.id, question) if isinstance(v, ValueBackendPassword): - print question.encode(sys.stdout.encoding or locale.getpreferredencoding()) + ':' + print(question.encode(sys.stdout.encoding or locale.getpreferredencoding()) + ':') question = v.label choices = OrderedDict() choices['c'] = 'Run an external tool during backend load' @@ -414,9 +415,9 @@ class ConsoleApplication(BaseApplication): if r == 'p': return '' if r == 'c': - print 'Enter the shell command that will print the required value on the standard output' + print('Enter the shell command that will print the required value on the standard output') if v.is_command(v.default): - print ': %s' % v.default[1:-1] + print(': %s' % v.default[1:-1]) else: d = None while True: @@ -424,7 +425,7 @@ class ConsoleApplication(BaseApplication): try: subprocess.check_output(cmd, shell=True) except subprocess.CalledProcessError as e: - print '%s' % e + print('%s' % e) else: return '`%s`' % cmd @@ -443,10 +444,10 @@ class ConsoleApplication(BaseApplication): question = u'%s (%s)' % (question, '/'.join((s.upper() if s == v.default else s) for s in (v.choices.iterkeys()))) for key, value in v.choices.iteritems(): - print ' %s%s%s: %s' % (self.BOLD, key, self.NC, value) + print(' %s%s%s: %s' % (self.BOLD, key, self.NC, value)) else: for n, (key, value) in enumerate(v.choices.iteritems()): - print ' %s%2d)%s %s' % (self.BOLD, n + 1, self.NC, value) + print(' %s%2d)%s %s' % (self.BOLD, n + 1, self.NC, value)) aliases[str(n + 1)] = key question = u'%s (choose in list)' % question if v.masked: @@ -483,7 +484,7 @@ class ConsoleApplication(BaseApplication): try: v.set(line) except ValueError as e: - print >>sys.stderr, u'Error: %s' % e + print(u'Error: %s' % e, file=sys.stderr) else: break @@ -509,8 +510,8 @@ class ConsoleApplication(BaseApplication): text = f.read() else: if sys.stdin.isatty(): - print 'Reading content from stdin... Type ctrl-D ' \ - 'from an empty line to stop.' + print('Reading content from stdin... Type ctrl-D ' \ + 'from an empty line to stop.') text = sys.stdin.read() return text.decode(sys.stdin.encoding or locale.getpreferredencoding()) @@ -524,7 +525,7 @@ class ConsoleApplication(BaseApplication): msg = unicode(error) if not msg: msg = 'invalid login/password.' - print >>sys.stderr, 'Error(%s): %s' % (backend.name, msg) + print('Error(%s): %s' % (backend.name, msg), file=sys.stderr) if self.ask('Do you want to reconfigure this backend?', default=True): self.unload_backends(names=[backend.name]) self.edit_backend(backend.name) @@ -533,21 +534,21 @@ class ConsoleApplication(BaseApplication): msg = unicode(error) if not msg: msg = 'website is unavailable.' - print >>sys.stderr, u'Error(%s): %s' % (backend.name, msg) + print(u'Error(%s): %s' % (backend.name, msg), file=sys.stderr) elif isinstance(error, BrowserForbidden): - print >>sys.stderr, u'Error(%s): %s' % (backend.name, msg or 'Forbidden') + print(u'Error(%s): %s' % (backend.name, msg or 'Forbidden'), file=sys.stderr) elif isinstance(error, NotImplementedError): - print >>sys.stderr, u'Error(%s): this feature is not supported yet by this backend.' % backend.name - print >>sys.stderr, u' %s To help the maintainer of this backend implement this feature,' % (' ' * len(backend.name)) - print >>sys.stderr, u' %s please contact: %s <%s@issues.weboob.org>' % (' ' * len(backend.name), backend.MAINTAINER, backend.NAME) + print(u'Error(%s): this feature is not supported yet by this backend.' % backend.name, file=sys.stderr) + print(u' %s To help the maintainer of this backend implement this feature,' % (' ' * len(backend.name)), file=sys.stderr) + print(u' %s please contact: %s <%s@issues.weboob.org>' % (' ' * len(backend.name), backend.MAINTAINER, backend.NAME), file=sys.stderr) elif isinstance(error, UserError): - print >>sys.stderr, u'Error(%s): %s' % (backend.name, to_unicode(error)) + print(u'Error(%s): %s' % (backend.name, to_unicode(error)), file=sys.stderr) elif isinstance(error, MoreResultsAvailable): - print >>sys.stderr, u'Hint: There are more results for backend %s' % (backend.name) + print(u'Hint: There are more results for backend %s' % (backend.name), file=sys.stderr) elif isinstance(error, SSLError): - print >>sys.stderr, u'FATAL(%s): ' % backend.name + self.BOLD + '/!\ SERVER CERTIFICATE IS INVALID /!\\' + self.NC + print(u'FATAL(%s): ' % backend.name + self.BOLD + '/!\ SERVER CERTIFICATE IS INVALID /!\\' + self.NC, file=sys.stderr) else: - print >>sys.stderr, u'Bug(%s): %s' % (backend.name, to_unicode(error)) + print(u'Bug(%s): %s' % (backend.name, to_unicode(error)), file=sys.stderr) minfo = self.weboob.repositories.get_module_info(backend.NAME) if minfo and not minfo.is_local(): @@ -558,11 +559,11 @@ class ConsoleApplication(BaseApplication): if minfo and minfo.version > self.weboob.repositories.versions.get(minfo.name) and \ self.ask('A new version of %s is available. Do you want to install it?' % minfo.name, default=True) and \ self.install_module(minfo): - print 'New version of module %s has been installed. Retry to call the command.' % minfo.name + print('New version of module %s has been installed. Retry to call the command.' % minfo.name) return if logging.root.level == logging.DEBUG: - print >>sys.stderr, backtrace + print(backtrace, file=sys.stderr) else: return True @@ -581,6 +582,6 @@ class ConsoleApplication(BaseApplication): ask_debug_mode = True if ask_debug_mode: - print >>sys.stderr, debugmsg + print(debugmsg, file=sys.stderr) elif len(more_results) > 0: - print >>sys.stderr, 'Hint: There are more results available for %s (use option -n or count command)' % (', '.join(more_results)) + print('Hint: There are more results available for %s (use option -n or count command)' % (', '.join(more_results)), file=sys.stderr) diff --git a/weboob/tools/application/formatters/iformatter.py b/weboob/tools/application/formatters/iformatter.py index 8c0f75de..36266c7e 100644 --- a/weboob/tools/application/formatters/iformatter.py +++ b/weboob/tools/application/formatters/iformatter.py @@ -18,6 +18,8 @@ # along with weboob. If not, see . +from __future__ import print_function + import os import sys import subprocess @@ -118,7 +120,7 @@ class IFormatter(object): if isinstance(line, unicode): line = line.encode('utf-8') - print line + print(line) self.print_lines += 1 def start_format(self, **kwargs): diff --git a/weboob/tools/application/formatters/json.py b/weboob/tools/application/formatters/json.py index cb78fc04..e1334ab3 100644 --- a/weboob/tools/application/formatters/json.py +++ b/weboob/tools/application/formatters/json.py @@ -18,6 +18,8 @@ # along with weboob. If not, see . +from __future__ import print_function + from weboob.capabilities.base import NotAvailable, NotLoaded from weboob.tools.json import json @@ -52,7 +54,7 @@ class JsonFormatter(IFormatter): self.queue = [] def flush(self): - print json.dumps(self.queue, cls=Encoder) + print(json.dumps(self.queue, cls=Encoder)) def format_dict(self, item): self.queue.append(item) @@ -64,4 +66,4 @@ class JsonLineFormatter(IFormatter): The advantage is that it can be streamed. """ def format_dict(self, item): - print json.dumps(item, cls=Encoder) + print(json.dumps(item, cls=Encoder)) diff --git a/weboob/tools/application/formatters/table.py b/weboob/tools/application/formatters/table.py index 7ac6a7ab..68949e24 100644 --- a/weboob/tools/application/formatters/table.py +++ b/weboob/tools/application/formatters/table.py @@ -18,6 +18,8 @@ # along with weboob. If not, see . +from __future__ import print_function + from prettytable import PrettyTable from weboob.capabilities.base import empty @@ -40,7 +42,7 @@ class TableFormatter(IFormatter): def flush(self): s = self.get_formatted_table() if s is not None: - print s.encode('utf-8') + print(s.encode('utf-8')) def get_formatted_table(self): if len(self.queue) == 0: diff --git a/weboob/tools/application/media_player.py b/weboob/tools/application/media_player.py index af7279be..f2847bed 100644 --- a/weboob/tools/application/media_player.py +++ b/weboob/tools/application/media_player.py @@ -18,6 +18,8 @@ # along with weboob. If not, see . +from __future__ import print_function + import os from subprocess import PIPE, Popen import cookielib @@ -102,7 +104,7 @@ class MediaPlayer(object): player_name = args[0] args.append(media.url) - print 'Invoking "%s".' % (' '.join(args)) + print('Invoking "%s".' % (' '.join(args))) os.spawnlp(os.P_WAIT, player_name, *args) def _play_proxy(self, media, player_name, args): @@ -120,9 +122,9 @@ class MediaPlayer(object): assert args is not None - print ':: Play_proxy streaming from %s' % media.url - print ':: to %s %s' % (player_name, args) - print player_name + ' ' + args + print(':: Play_proxy streaming from %s' % media.url) + print(':: to %s %s' % (player_name, args)) + print(player_name + ' ' + args) proc = Popen(player_name + ' ' + args, stdin=PIPE, shell=True) # Handle cookies (and redirection 302...) @@ -142,7 +144,7 @@ class MediaPlayer(object): try: proc.stdin.write(_buffer) except: - print "play_proxy broken pipe. Can't write anymore." + print("play_proxy broken pipe. Can't write anymore.") break def _play_rtmp(self, media, player_name, args): @@ -181,9 +183,9 @@ class MediaPlayer(object): player_name = player_name.split(' ') args = args.split(' ') - print ':: Streaming from %s' % media_url - print ':: to %s %s' % (player_name, args) - print ':: %s' % rtmp + print(':: Streaming from %s' % media_url) + print(':: to %s %s' % (player_name, args)) + print(':: %s' % rtmp) p1 = Popen(rtmp.split(), stdout=PIPE) Popen(player_name + args, stdin=p1.stdout, stderr=PIPE) diff --git a/weboob/tools/application/qt/qt.py b/weboob/tools/application/qt/qt.py index 4f958f27..667216e6 100644 --- a/weboob/tools/application/qt/qt.py +++ b/weboob/tools/application/qt/qt.py @@ -17,6 +17,8 @@ # You should have received a copy of the GNU Affero General Public License # along with weboob. If not, see . +from __future__ import print_function + import sys import logging import re @@ -237,8 +239,8 @@ class QtDo(QObject): msg += u'
%s' % to_unicode(line) if ul_opened: msg += u'' - print >>sys.stderr, error - print >>sys.stderr, backtrace + print(error, file=sys.stderr) + print(backtrace, file=sys.stderr) QMessageBox.critical(None, unicode(self.tr('Error with backend %s')) % backend.name, msg, QMessageBox.Ok) diff --git a/weboob/tools/application/repl.py b/weboob/tools/application/repl.py index a213c60d..8b2b7cea 100644 --- a/weboob/tools/application/repl.py +++ b/weboob/tools/application/repl.py @@ -17,6 +17,7 @@ # You should have received a copy of the GNU Affero General Public License # along with weboob. If not, see . +from __future__ import print_function import atexit from cmd import Cmd @@ -198,20 +199,20 @@ class ReplApplication(Cmd, ConsoleApplication): except BackendNotGiven as e: backend_name = None while not backend_name: - print 'This command works with an unique backend. Availables:' + print('This command works with an unique backend. Availables:') for index, (name, backend) in enumerate(e.backends): - print '%s%d)%s %s%-15s%s %s' % (self.BOLD, index + 1, self.NC, self.BOLD, name, self.NC, - backend.DESCRIPTION) + print('%s%d)%s %s%-15s%s %s' % (self.BOLD, index + 1, self.NC, self.BOLD, name, self.NC, + backend.DESCRIPTION)) i = self.ask('Select a backend to proceed with "%s"' % id) if not i.isdigit(): if not i in dict(e.backends): - print >>sys.stderr, 'Error: %s is not a valid backend' % i + print('Error: %s is not a valid backend' % i, file=sys.stderr) continue backend_name = i else: i = int(i) if i < 0 or i > len(e.backends): - print >>sys.stderr, 'Error: %s is not a valid choice' % i + print('Error: %s is not a valid choice' % i, file=sys.stderr) continue backend_name = e.backends[i-1][0] @@ -405,12 +406,12 @@ class ReplApplication(Cmd, ConsoleApplication): except CallErrors as e: self.bcall_errors_handler(e) except BackendNotGiven as e: - print >>sys.stderr, 'Error: %s' % str(e) + print('Error: %s' % str(e), file=sys.stderr) except NotEnoughArguments as e: - print >>sys.stderr, 'Error: not enough arguments. %s' % str(e) + print('Error: not enough arguments. %s' % str(e), file=sys.stderr) except (KeyboardInterrupt, EOFError): # ^C during a command process doesn't exit application. - print '\nAborted.' + print('\nAborted.') finally: self.flush() @@ -422,12 +423,12 @@ class ReplApplication(Cmd, ConsoleApplication): pass def default(self, line): - print >>sys.stderr, 'Unknown command: "%s"' % line + print('Unknown command: "%s"' % line, file=sys.stderr) cmd, arg, ignore = Cmd.parseline(self, line) if cmd is not None: names = set(name[3:] for name in self.get_names() if name.startswith('do_' + cmd)) if len(names) > 0: - print >>sys.stderr, 'Do you mean: %s?' % ', '.join(names) + print('Do you mean: %s?' % ', '.join(names), file=sys.stderr) return 2 def completenames(self, text, *ignored): @@ -561,7 +562,7 @@ class ReplApplication(Cmd, ConsoleApplication): Quit the command line interpreter when ^D is pressed. """ # print empty line for the next shell prompt to appear on the first column of the terminal - print + print() return self.do_quit(arg) def do_help(self, arg=None): @@ -581,7 +582,7 @@ class ReplApplication(Cmd, ConsoleApplication): lines[0] = '%s%s%s' % (self.BOLD, lines[0], self.NC) self.stdout.write('%s\n' % '\n'.join(lines)) else: - print >>sys.stderr, 'Unknown command: "%s"' % arg + print('Unknown command: "%s"' % arg, file=sys.stderr) else: cmds = self._parser.formatter.format_commands(self._parser.commands) self.stdout.write('%s\n' % cmds) @@ -644,20 +645,20 @@ class ReplApplication(Cmd, ConsoleApplication): if action in ('add', 'register'): minfo = self.weboob.repositories.get_module_info(backend_name) if minfo is None: - print >>sys.stderr, 'Module "%s" does not exist.' % backend_name + print('Module "%s" does not exist.' % backend_name, file=sys.stderr) return 1 else: if not minfo.has_caps(self.CAPS): - print >>sys.stderr, 'Module "%s" is not supported by this application => skipping.' % backend_name + print('Module "%s" is not supported by this application => skipping.' % backend_name, file=sys.stderr) return 1 else: if backend_name not in [backend.name for backend in self.weboob.iter_backends()]: - print >>sys.stderr, 'Backend "%s" does not exist => skipping.' % backend_name + print('Backend "%s" does not exist => skipping.' % backend_name, file=sys.stderr) return 1 if action in ('enable', 'disable', 'only', 'add', 'register', 'edit', 'remove'): if not given_backend_names: - print >>sys.stderr, 'Please give at least a backend name.' + print('Please give at least a backend name.', file=sys.stderr) return 2 given_backends = set(backend for backend in self.weboob.iter_backends() if backend.name in given_backend_names) @@ -670,7 +671,7 @@ class ReplApplication(Cmd, ConsoleApplication): try: self.enabled_backends.remove(backend) except KeyError: - print >>sys.stderr, '%s is not enabled' % backend.name + print('%s is not enabled' % backend.name, file=sys.stderr) elif action == 'only': self.enabled_backends = set() for backend in given_backends: @@ -678,9 +679,9 @@ class ReplApplication(Cmd, ConsoleApplication): elif action == 'list': enabled_backends_names = set(backend.name for backend in self.enabled_backends) disabled_backends_names = set(backend.name for backend in self.weboob.iter_backends()) - enabled_backends_names - print 'Enabled: %s' % ', '.join(enabled_backends_names) + print('Enabled: %s' % ', '.join(enabled_backends_names)) if len(disabled_backends_names) > 0: - print 'Disabled: %s' % ', '.join(disabled_backends_names) + print('Disabled: %s' % ', '.join(disabled_backends_names)) elif action == 'add': for name in given_backend_names: instname = self.add_backend(name) @@ -705,7 +706,7 @@ class ReplApplication(Cmd, ConsoleApplication): self.unload_backends(backend.name) elif action == 'list-modules': modules = [] - print 'Modules list:' + print('Modules list:') for name, info in sorted(self.weboob.repositories.get_all_modules_info().iteritems()): if not self.is_module_loadable(info): continue @@ -719,14 +720,14 @@ class ReplApplication(Cmd, ConsoleApplication): loaded = 2 else: loaded += 1 - print '[%s] %s%-15s%s %s' % (loaded, self.BOLD, name, self.NC, info.description) + print('[%s] %s%-15s%s %s' % (loaded, self.BOLD, name, self.NC, info.description)) else: - print >>sys.stderr, 'Unknown action: "%s"' % action + print('Unknown action: "%s"' % action, file=sys.stderr) return 1 if len(self.enabled_backends) == 0: - print >>sys.stderr, 'Warning: no more backends are loaded. %s is probably unusable.' % self.APPNAME.capitalize() + print('Warning: no more backends are loaded. %s is probably unusable.' % self.APPNAME.capitalize(), file=sys.stderr) def complete_logging(self, text, line, begidx, endidx): levels = ('debug', 'info', 'warning', 'error', 'quiet', 'default') @@ -760,15 +761,15 @@ class ReplApplication(Cmd, ConsoleApplication): if logging.root.level == level: current = label break - print 'Current level: %s' % current + print('Current level: %s' % current) return levels = dict(levels) try: level = levels[args[0]] except KeyError: - print >>sys.stderr, 'Level "%s" does not exist.' % args[0] - print >>sys.stderr, 'Availables: %s' % ' '.join(levels.iterkeys()) + print('Level "%s" does not exist.' % args[0], file=sys.stderr) + print('Availables: %s' % ' '.join(levels.iterkeys()), file=sys.stderr) return 2 else: logging.root.setLevel(level) @@ -792,13 +793,13 @@ class ReplApplication(Cmd, ConsoleApplication): try: self.condition = ResultsCondition(line) except ResultsConditionError as e: - print >>sys.stderr, '%s' % e + print('%s' % e, file=sys.stderr) return 2 else: if self.condition is None: - print 'No condition is set.' + print('No condition is set.') else: - print str(self.condition) + print(str(self.condition)) def do_count(self, line): """ @@ -819,7 +820,7 @@ class ReplApplication(Cmd, ConsoleApplication): try: count = int(line) except ValueError: - print >>sys.stderr, 'Could not interpret "%s" as a number.' % line + print('Could not interpret "%s" as a number.' % line, file=sys.stderr) return 2 else: if count > 0: @@ -830,9 +831,9 @@ class ReplApplication(Cmd, ConsoleApplication): self._is_default_count = False else: if self.options.count is None: - print 'Counting disabled.' + print('Counting disabled.') else: - print self.options.count + print(self.options.count) def complete_formatter(self, text, line, *ignored): formatters = self.formatters_loader.get_available_formatters() @@ -871,17 +872,17 @@ class ReplApplication(Cmd, ConsoleApplication): args = line.strip().split() if args: if args[0] == 'list': - print ', '.join(self.formatters_loader.get_available_formatters()) + print(', '.join(self.formatters_loader.get_available_formatters())) elif args[0] == 'option': if len(args) > 1: if len(args) == 2: if args[1] == 'header': - print 'off' if self.options.no_header else 'on' + print('off' if self.options.no_header else 'on') elif args[1] == 'keys': - print 'off' if self.options.no_keys else 'on' + print('off' if self.options.no_keys else 'on') else: if args[2] not in ('on', 'off'): - print >>sys.stderr, 'Invalid value "%s". Please use "on" or "off" values.' % args[2] + print('Invalid value "%s". Please use "on" or "off" values.' % args[2], file=sys.stderr) return 2 else: if args[1] == 'header': @@ -889,7 +890,7 @@ class ReplApplication(Cmd, ConsoleApplication): elif args[1] == 'keys': self.options.no_keys = True if args[2] == 'off' else False else: - print >>sys.stderr, 'Don\'t know which option to set. Available options: header, keys.' + print('Don\'t know which option to set. Available options: header, keys.', file=sys.stderr) return 2 else: if args[0] in self.formatters_loader.get_available_formatters(): @@ -899,13 +900,13 @@ class ReplApplication(Cmd, ConsoleApplication): self.commands_formatters = {} self.DEFAULT_FORMATTER = self.set_formatter(args[0]) else: - print >>sys.stderr, 'Formatter "%s" is not available.\n' \ - 'Available formatters: %s.' % (args[0], ', '.join(self.formatters_loader.get_available_formatters())) + print('Formatter "%s" is not available.\n' \ + 'Available formatters: %s.' % (args[0], ', '.join(self.formatters_loader.get_available_formatters())), file=sys.stderr) return 1 else: - print 'Default formatter: %s' % self.DEFAULT_FORMATTER + print('Default formatter: %s' % self.DEFAULT_FORMATTER) for key, klass in self.commands_formatters.iteritems(): - print 'Command "%s": %s' % (key, klass) + print('Command "%s": %s' % (key, klass)) def do_select(self, line): """ @@ -922,7 +923,7 @@ class ReplApplication(Cmd, ConsoleApplication): split = line.split() self.selected_fields = split else: - print ' '.join(self.selected_fields) + print(' '.join(self.selected_fields)) def complete_inspect(self, text, line, begidx, endidx): return sorted(set(backend.name for backend in self.enabled_backends)) @@ -940,18 +941,18 @@ class ReplApplication(Cmd, ConsoleApplication): else: backend_name = line.strip() if not backend_name: - print >>sys.stderr, 'Please specify a backend name.' + print('Please specify a backend name.', file=sys.stderr) return 2 backends = set(backend for backend in self.enabled_backends if backend.name == backend_name) if not backends: - print >>sys.stderr, 'No backend found for "%s"' % backend_name + print('No backend found for "%s"' % backend_name, file=sys.stderr) return 1 backend = backends.pop() if not backend.browser: - print >>sys.stderr, 'No browser created for backend "%s".' % backend.name + print('No browser created for backend "%s".' % backend.name, file=sys.stderr) return 1 if not backend.browser.page: - print >>sys.stderr, 'The browser of %s is not on any page.' % backend.name + print('The browser of %s is not on any page.' % backend.name, file=sys.stderr) return 1 browser = backend.browser data = browser.parser.tostring(browser.page.document) @@ -959,7 +960,7 @@ class ReplApplication(Cmd, ConsoleApplication): from webkit_mechanize_browser.browser import Browser from weboob.tools.inspect import Page except ImportError: - print data + print(data) else: page = Page(core=browser, data=data, uri=browser._response.geturl()) browser = Browser(view=page.view) @@ -1064,11 +1065,11 @@ class ReplApplication(Cmd, ConsoleApplication): def _format_collection(self, collection, only): if only is False or collection.basename in only: if collection.basename and collection.title: - print u'%s~ (%s) %s (%s)%s' % \ - (self.BOLD, collection.basename, collection.title, collection.backend, self.NC) + print(u'%s~ (%s) %s (%s)%s' % \ + (self.BOLD, collection.basename, collection.title, collection.backend, self.NC)) else: - print u'%s~ (%s) (%s)%s' % \ - (self.BOLD, collection.basename, collection.backend, self.NC) + print(u'%s~ (%s) (%s)%s' % \ + (self.BOLD, collection.basename, collection.backend, self.NC)) def _format_obj(self, obj, only): @@ -1106,7 +1107,7 @@ class ReplApplication(Cmd, ConsoleApplication): if len(collections) == 1: self.working_path.split_path = collections[0].split_path else: - print >>sys.stderr, u"Path: %s not found" % unicode(self.working_path) + print(u"Path: %s not found" % unicode(self.working_path), file=sys.stderr) self.working_path.restore() return 1 @@ -1199,10 +1200,10 @@ class ReplApplication(Cmd, ConsoleApplication): try: self.formatter = self.formatters_loader.build_formatter(name) except FormatterLoadError as e: - print >>sys.stderr, '%s' % e + print('%s' % e, file=sys.stderr) if self.DEFAULT_FORMATTER == name: self.DEFAULT_FORMATTER = ReplApplication.DEFAULT_FORMATTER - print >>sys.stderr, 'Falling back to "%s".' % (self.DEFAULT_FORMATTER) + print('Falling back to "%s".' % (self.DEFAULT_FORMATTER), file=sys.stderr) self.formatter = self.formatters_loader.build_formatter(self.DEFAULT_FORMATTER) name = self.DEFAULT_FORMATTER if self.options.no_header: @@ -1235,9 +1236,9 @@ class ReplApplication(Cmd, ConsoleApplication): try: self.formatter.format(obj=result, selected_fields=fields, alias=alias) except FieldNotFound as e: - print >>sys.stderr, e + print(e, file=sys.stderr) except MandatoryFieldsNotFound as e: - print >>sys.stderr, '%s Hint: select missing fields or use another formatter (ex: multiline).' % e + print('%s Hint: select missing fields or use another formatter (ex: multiline).' % e, file=sys.stderr) def flush(self): self.formatter.flush() diff --git a/weboob/tools/browser/browser.py b/weboob/tools/browser/browser.py index e10f3cba..85552a5c 100644 --- a/weboob/tools/browser/browser.py +++ b/weboob/tools/browser/browser.py @@ -18,6 +18,12 @@ # along with weboob. If not, see . +from __future__ import print_function +import sys + +if sys.version_info >= (3,0): + raise ImportError("This module isn't compatible with python3") + from copy import copy from httplib import BadStatusLine @@ -28,7 +34,6 @@ except ImportError: raise ImportError('Please install python-mechanize') import os -import sys import re import tempfile from threading import RLock @@ -288,7 +293,7 @@ class StandardBrowser(mechanize.Browser): """ if self.responses_dirname is None: self.responses_dirname = tempfile.mkdtemp(prefix='weboob_session_') - print >>sys.stderr, 'Debug data will be saved in this directory: %s' % self.responses_dirname + print('Debug data will be saved in this directory: %s' % self.responses_dirname, file=sys.stderr) elif not os.path.isdir(self.responses_dirname): os.makedirs(self.responses_dirname) # get the content-type, remove optionnal charset part @@ -391,7 +396,7 @@ class StandardBrowser(mechanize.Browser): value = [self.str(is_list.index(args[label]))] except ValueError as e: if args[label]: - print >>sys.stderr, '[%s] %s: %s' % (label, args[label], e) + print('[%s] %s: %s' % (label, args[label], e), file=sys.stderr) return else: value = [self.str(args[label])] diff --git a/weboob/tools/browser/firefox_cookies.py b/weboob/tools/browser/firefox_cookies.py index 6d5c1cba..de60879c 100644 --- a/weboob/tools/browser/firefox_cookies.py +++ b/weboob/tools/browser/firefox_cookies.py @@ -18,6 +18,8 @@ # along with weboob. If not, see . +from __future__ import print_function + try: import sqlite3 as sqlite except ImportError as e: @@ -40,7 +42,7 @@ class FirefoxCookieJar(CookieJar): try: db = sqlite.connect(database=self.sqlite_file, timeout=10.0) except sqlite.OperationalError as err: - print 'Unable to open %s database: %s' % (self.sqlite_file, err) + print('Unable to open %s database: %s' % (self.sqlite_file, err)) return None return db diff --git a/weboob/tools/browser2/browser.py b/weboob/tools/browser2/browser.py index cabf6b9d..cdbd0196 100644 --- a/weboob/tools/browser2/browser.py +++ b/weboob/tools/browser2/browser.py @@ -17,10 +17,13 @@ # You should have received a copy of the GNU Affero General Public License # along with weboob. If not, see . -from __future__ import absolute_import +from __future__ import absolute_import, print_function import re -from urlparse import urlparse, urljoin +try: + from urllib.parse import urlparse, urljoin +except ImportError: + from urlparse import urlparse, urljoin import mimetypes import os import tempfile @@ -157,7 +160,7 @@ class BaseBrowser(object): def _save(self, response, warning=False, **kwargs): if self.responses_dirname is None: self.responses_dirname = tempfile.mkdtemp(prefix='weboob_session_') - print >>sys.stderr, 'Debug data will be saved in this directory: %s' % self.responses_dirname + print('Debug data will be saved in this directory: %s' % self.responses_dirname, file=sys.stderr) elif not os.path.isdir(self.responses_dirname): os.makedirs(self.responses_dirname) diff --git a/weboob/tools/browser2/cookies.py b/weboob/tools/browser2/cookies.py index 6d250528..8941c788 100644 --- a/weboob/tools/browser2/cookies.py +++ b/weboob/tools/browser2/cookies.py @@ -17,7 +17,10 @@ # along with weboob. If not, see . import requests.cookies -import cookielib +try: + import cookielib +except ImportError: + import http.cookiejar as cookielib __all__ = ['WeboobCookieJar'] diff --git a/weboob/tools/browser2/filters.py b/weboob/tools/browser2/filters.py index 91e7fdd8..f2175190 100644 --- a/weboob/tools/browser2/filters.py +++ b/weboob/tools/browser2/filters.py @@ -26,6 +26,7 @@ import re import lxml.html as html from weboob.tools.misc import html2text +from weboob.tools.compat import basestring from weboob.capabilities.base import empty @@ -258,7 +259,7 @@ class CleanDecimal(CleanText): if self.replace_dots: text = text.replace('.','').replace(',','.') try: - return Decimal(re.sub(ur'[^\d\-\.]', '', text)) + return Decimal(re.sub(r'[^\d\-\.]', '', text)) except InvalidOperation as e: return self.default_or_raise(e) @@ -388,7 +389,7 @@ class DateGuesser(Filter): class Time(Filter): klass = datetime.time - regexp = re.compile(ur'(?P\d+):?(?P\d+)(:(?P\d+))?') + regexp = re.compile(r'(?P\d+):?(?P\d+)(:(?P\d+))?') kwargs = {'hour': 'hh', 'minute': 'mm', 'second': 'ss'} def __init__(self, selector, default=_NO_DEFAULT): @@ -407,7 +408,7 @@ class Time(Filter): class Duration(Time): klass = datetime.timedelta - regexp = re.compile(ur'((?P\d+)[:;])?(?P\d+)[;:](?P\d+)') + regexp = re.compile(r'((?P\d+)[:;])?(?P\d+)[;:](?P\d+)') kwargs = {'hours': 'hh', 'minutes': 'mm', 'seconds': 'ss'} diff --git a/weboob/tools/browser2/page.py b/weboob/tools/browser2/page.py index 5684bf94..7835d074 100644 --- a/weboob/tools/browser2/page.py +++ b/weboob/tools/browser2/page.py @@ -19,18 +19,22 @@ from __future__ import absolute_import -from urllib import unquote +try: + from urllib.parse import unquote +except ImportError: + from urllib import unquote import requests import re import sys from copy import deepcopy -from cStringIO import StringIO +from io import BytesIO import lxml.html as html import lxml.etree as etree from weboob.tools.json import json from weboob.tools.ordereddict import OrderedDict from weboob.tools.regex_helper import normalize +from weboob.tools.compat import basestring from weboob.tools.log import getLogger @@ -527,7 +531,7 @@ class XMLPage(BasePage): def __init__(self, browser, response, *args, **kwargs): super(XMLPage, self).__init__(browser, response, *args, **kwargs) parser = etree.XMLParser(encoding=self.ENCODING or response.encoding) - self.doc = etree.parse(StringIO(response.content), parser) + self.doc = etree.parse(BytesIO(response.content), parser) class RawPage(BasePage): @@ -551,7 +555,7 @@ class HTMLPage(BasePage): def __init__(self, browser, response, *args, **kwargs): super(HTMLPage, self).__init__(browser, response, *args, **kwargs) parser = html.HTMLParser(encoding=self.ENCODING or response.encoding) - self.doc = html.parse(StringIO(response.content), parser) + self.doc = html.parse(BytesIO(response.content), parser) def get_form(self, xpath='//form', name=None, nr=None): """ diff --git a/weboob/tools/compat.py b/weboob/tools/compat.py new file mode 100644 index 00000000..cc10099a --- /dev/null +++ b/weboob/tools/compat.py @@ -0,0 +1,37 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2014 Romain Bignon +# +# This file is part of weboob. +# +# weboob is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# weboob is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with weboob. If not, see . + + +__all__ = ['unicode', 'long', 'basestring'] + + +try: + unicode = unicode +except NameError: + unicode = str + +try: + long = long +except NameError: + long = int + +try: + basestring = basestring +except NameError: + basestring = str diff --git a/weboob/tools/misc.py b/weboob/tools/misc.py index 94cd6ced..5d479071 100644 --- a/weboob/tools/misc.py +++ b/weboob/tools/misc.py @@ -27,6 +27,7 @@ import traceback import types # keep compatibility from .date import local2utc, utc2local +from .compat import unicode __all__ = ['get_backtrace', 'get_bytes_size', 'html2text', 'iter_fields',