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',