first step in python3 support

This commit is contained in:
Romain Bignon 2014-05-17 13:37:47 +02:00
commit 6fcac89dd5
25 changed files with 302 additions and 208 deletions

View file

@ -18,9 +18,14 @@
# along with weboob. If not, see <http://www.gnu.org/licenses/>. # along with weboob. If not, see <http://www.gnu.org/licenses/>.
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 datetime import datetime, timedelta
from weboob.tools.compat import basestring
from weboob.tools.browser2 import LoginBrowser, URL, Wget, need_login from weboob.tools.browser2 import LoginBrowser, URL, Wget, need_login
from weboob.tools.exceptions import BrowserIncorrectPassword from weboob.tools.exceptions import BrowserIncorrectPassword
from weboob.capabilities.bank import Transfer, TransferError from weboob.capabilities.bank import Transfer, TransferError

View file

@ -18,7 +18,11 @@
# along with weboob. If not, see <http://www.gnu.org/licenses/>. # along with weboob. If not, see <http://www.gnu.org/licenses/>.
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 from decimal import Decimal
import re import re
from dateutil.relativedelta import relativedelta from dateutil.relativedelta import relativedelta

View file

@ -17,6 +17,7 @@
# You should have received a copy of the GNU Affero General Public License # You should have received a copy of the GNU Affero General Public License
# along with weboob. If not, see <http://www.gnu.org/licenses/>. # along with weboob. If not, see <http://www.gnu.org/licenses/>.
from __future__ import print_function
import datetime, uuid import datetime, uuid
from dateutil.relativedelta import relativedelta from dateutil.relativedelta import relativedelta
@ -321,15 +322,15 @@ class Boobank(ReplApplication):
account = self.get_object(id, 'get_account', []) account = self.get_object(id, 'get_account', [])
if not 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 return 2
if end_date is not None: if end_date is not None:
try: try:
end_date = parse_date(end_date) end_date = parse_date(end_date)
except ValueError: except ValueError:
print >>sys.stderr, '"%s" is an incorrect date format (for example "%s")' % \ print('"%s" is an incorrect date format (for example "%s")' % \
(end_date, (datetime.date.today() - relativedelta(months=1)).strftime('%Y-%m-%d')) (end_date, (datetime.date.today() - relativedelta(months=1)).strftime('%Y-%m-%d')), file=sys.stderr)
return 3 return 3
old_count = self.options.count old_count = self.options.count
self.options.count = None self.options.count = None
@ -399,7 +400,7 @@ class Boobank(ReplApplication):
account = self.get_object(id_from, 'get_account', []) account = self.get_object(id_from, 'get_account', [])
if not 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 return 1
if not id_to: if not id_to:
@ -415,13 +416,13 @@ class Boobank(ReplApplication):
id_to, backend_name_to = self.parse_id(id_to) id_to, backend_name_to = self.parse_id(id_to)
if account.backend != backend_name_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 return 4
try: try:
amount = Decimal(amount) amount = Decimal(amount)
except (TypeError, ValueError, InvalidOperation): 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 return 2
if self.interactive: if self.interactive:
@ -434,10 +435,10 @@ class Boobank(ReplApplication):
to = recipient.label to = recipient.label
break break
print 'Amount: %s%s' % (amount, account.currency_text) print('Amount: %s%s' % (amount, account.currency_text))
print 'From: %s' % account.label print('From: %s' % account.label)
print 'To: %s' % to print('To: %s' % to)
print 'Reason: %s' % (reason or '') print('Reason: %s' % (reason or ''))
if not self.ask('Are you sure to do this transfer?', default=True): if not self.ask('Are you sure to do this transfer?', default=True):
return return
@ -453,7 +454,7 @@ class Boobank(ReplApplication):
""" """
account = self.get_object(id, 'get_account', []) account = self.get_object(id, 'get_account', [])
if not 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 return 2
self.start_format() self.start_format()

View file

@ -22,6 +22,8 @@ from datetime import date, datetime
from binascii import crc32 from binascii import crc32
import re import re
from weboob.tools.compat import basestring, long
from .base import CapBaseObject, Field, StringField, DateField, DecimalField, IntField, UserError, Currency from .base import CapBaseObject, Field, StringField, DateField, DecimalField, IntField, UserError, Currency
from .collection import ICapCollection from .collection import ICapCollection

View file

@ -24,6 +24,7 @@ import re
from decimal import Decimal from decimal import Decimal
from copy import deepcopy, copy from copy import deepcopy, copy
from weboob.tools.compat import unicode, long
from weboob.tools.misc import to_unicode from weboob.tools.misc import to_unicode
from weboob.tools.date import new_date, new_datetime from weboob.tools.date import new_date, new_datetime
from weboob.tools.ordereddict import OrderedDict from weboob.tools.ordereddict import OrderedDict

View file

@ -23,7 +23,10 @@
import stat import stat
import os import os
import sys import sys
from ConfigParser import RawConfigParser, DuplicateSectionError try:
from ConfigParser import RawConfigParser, DuplicateSectionError
except ImportError:
from configparser import RawConfigParser, DuplicateSectionError
from logging import warning from logging import warning
__all__ = ['BackendsConfig', 'BackendAlreadyExists'] __all__ = ['BackendsConfig', 'BackendAlreadyExists']

View file

@ -20,7 +20,10 @@
from copy import copy from copy import copy
from threading import Thread from threading import Thread
import Queue try:
import Queue
except ImportError:
import queue as Queue
from weboob.capabilities.base import CapBaseObject from weboob.capabilities.base import CapBaseObject
from weboob.tools.misc import get_backtrace from weboob.tools.misc import get_backtrace

View file

@ -18,7 +18,7 @@
# along with weboob. If not, see <http://www.gnu.org/licenses/>. # along with weboob. If not, see <http://www.gnu.org/licenses/>.
from __future__ import print_function
import imp import imp
import tarfile import tarfile
import posixpath import posixpath
@ -32,29 +32,24 @@ from tempfile import NamedTemporaryFile
from datetime import datetime from datetime import datetime
from contextlib import closing from contextlib import closing
from compileall import compile_dir from compileall import compile_dir
from StringIO import StringIO from io import BytesIO
from .modules import Module from .modules import Module
from weboob.tools.log import getLogger from weboob.tools.log import getLogger
from weboob.tools.misc import to_unicode from weboob.tools.misc import to_unicode
from weboob.tools.browser import StandardBrowser, BrowserUnavailable from weboob.tools.browser2.browser import BaseBrowser, Weboob as WeboobProfile
from ConfigParser import RawConfigParser, DEFAULTSECT try:
from configparser import RawConfigParser, DEFAULTSECT
except ImportError:
from ConfigParser import RawConfigParser, DEFAULTSECT
BrowserUnavailable = object()
__all__ = ['IProgress', 'ModuleInstallError', 'ModuleInfo', 'RepositoryUnavailable', __all__ = ['IProgress', 'ModuleInstallError', 'ModuleInfo', 'RepositoryUnavailable',
'Repository', 'Versions', 'Repositories', 'InvalidSignature', 'Keyring'] '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): class ModuleInfo(object):
""" """
Information about a module available on a repository. Information about a module available on a repository.
@ -125,7 +120,8 @@ class Repository(object):
KEYDIR = '.keys' KEYDIR = '.keys'
KEYRING = 'trusted.gpg' KEYRING = 'trusted.gpg'
def __init__(self, url): def __init__(self, browser, url):
self.browser = browser
self.url = url self.url = url
self.name = u'' self.name = u''
self.update = 0 self.update = 0
@ -179,9 +175,8 @@ class Repository(object):
fp = open(filename, 'r') fp = open(filename, 'r')
else: else:
# This is a remote repository, download file # This is a remote repository, download file
browser = WeboobBrowser()
try: 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: except BrowserUnavailable as e:
raise RepositoryUnavailable(unicode(e)) raise RepositoryUnavailable(unicode(e))
@ -208,20 +203,19 @@ class Repository(object):
if not keyring.exists() or self.key_update > keyring.version: if not keyring.exists() or self.key_update > keyring.version:
# This is a remote repository, download file # This is a remote repository, download file
browser = WeboobBrowser()
try: try:
keyring_data = browser.readurl(posixpath.join(self.url, self.KEYRING)) keyring_data = self.browser.open(posixpath.join(self.url, self.KEYRING)).content
sig_data = browser.readurl(posixpath.join(self.url, self.KEYRING + '.sig')) sig_data = self.browser.open(posixpath.join(self.url, self.KEYRING + '.sig')).content
except BrowserUnavailable as e: except BrowserUnavailable as e:
raise RepositoryUnavailable(unicode(e)) raise RepositoryUnavailable(unicode(e))
if keyring.exists(): if keyring.exists():
if not keyring.is_valid(keyring_data, sig_data): if not keyring.is_valid(keyring_data, sig_data):
raise InvalidSignature('the keyring itself') 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: else:
print 'First time saving the keyring, blindly accepted.' print('First time saving the keyring, blindly accepted.')
keyring.save(keyring_data, self.key_update) keyring.save(keyring_data, self.key_update)
print keyring print(keyring)
def parse_index(self, fp): def parse_index(self, fp):
""" """
@ -275,7 +269,7 @@ class Repository(object):
:param filename: file to save index :param filename: file to save index
:type filename: str :type filename: str
""" """
print 'Rebuild index' print('Rebuild index')
self.modules.clear() self.modules.clear()
if os.path.isdir(os.path.join(path, self.KEYDIR)): if os.path.isdir(os.path.join(path, self.KEYDIR)):
@ -298,7 +292,7 @@ class Repository(object):
if fp: if fp:
fp.close() fp.close()
except Exception as e: 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: else:
m = ModuleInfo(module.name) m = ModuleInfo(module.name)
m.version = self.get_tree_mtime(module_path) m.version = self.get_tree_mtime(module_path)
@ -388,10 +382,10 @@ class Versions(object):
class IProgress(object): class IProgress(object):
def progress(self, percent, message): def progress(self, percent, message):
print '=== [%3.0f%%] %s' % (percent*100, message) print('=== [%3.0f%%] %s' % (percent*100, message))
def error(self, message): def error(self, message):
print >>sys.stderr, 'ERROR: %s' % message print('ERROR: %s' % message, file=sys.stderr)
class ModuleInstallError(Exception): class ModuleInstallError(Exception):
@ -425,7 +419,11 @@ class Repositories(object):
def __init__(self, workdir, datadir, version): def __init__(self, workdir, datadir, version):
self.logger = getLogger('repositories') self.logger = getLogger('repositories')
self.version = version self.version = version
WeboobBrowser.set_version(version)
class WeboobBrowser(BaseBrowser):
PROFILE = WeboobProfile(version)
self.browser = WeboobBrowser()
self.workdir = workdir self.workdir = workdir
self.datadir = datadir self.datadir = datadir
@ -503,10 +501,10 @@ class Repositories(object):
for name in sorted(os.listdir(self.repos_dir)): for name in sorted(os.listdir(self.repos_dir)):
path = os.path.join(self.repos_dir, name) path = os.path.join(self.repos_dir, name)
try: try:
repository = Repository(path) repository = Repository(self.browser, path)
self.repositories.append(repository) self.repositories.append(repository)
except RepositoryUnavailable as e: 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): def get_module_icon_path(self, module):
return os.path.join(self.icons_dir, '%s.png' % module.name) return os.path.join(self.icons_dir, '%s.png' % module.name)
@ -530,14 +528,13 @@ class Repositories(object):
else: else:
icon_url = module.url.replace('.tar.gz', '.png') icon_url = module.url.replace('.tar.gz', '.png')
browser = WeboobBrowser()
try: try:
icon = browser.openurl(icon_url) icon = self.browser.open(icon_url)
except BrowserUnavailable: except BrowserUnavailable:
pass # no icon, no problem pass # no icon, no problem
else: else:
with open(dest_path, 'wb') as fp: with open(dest_path, 'wb') as fp:
fp.write(icon.read()) fp.write(icon.content)
def _parse_source_list(self): def _parse_source_list(self):
l = [] l = []
@ -564,7 +561,7 @@ class Repositories(object):
gpgv = Keyring.find_gpgv() gpgv = Keyring.find_gpgv()
for line in self._parse_source_list(): for line in self._parse_source_list():
progress.progress(0.0, 'Getting %s' % line) progress.progress(0.0, 'Getting %s' % line)
repository = Repository(line) repository = Repository(self.browser, line)
filename = self.url2filename(repository.url) filename = self.url2filename(repository.url)
prio_filename = '%02d-%s' % (len(self.repositories), filename) prio_filename = '%02d-%s' % (len(self.repositories), filename)
repo_path = os.path.join(self.repos_dir, prio_filename) repo_path = os.path.join(self.repos_dir, prio_filename)
@ -587,7 +584,7 @@ class Repositories(object):
""" """
l = [] l = []
for line in self._parse_source_list(): for line in self._parse_source_list():
repository = Repository(line) repository = Repository(self.browser, line)
filename = self.url2filename(repository.url) filename = self.url2filename(repository.url)
prio_filename = '%02d-%s' % (len(l), filename) prio_filename = '%02d-%s' % (len(l), filename)
repo_path = os.path.join(self.repos_dir, prio_filename) repo_path = os.path.join(self.repos_dir, prio_filename)
@ -657,17 +654,16 @@ class Repositories(object):
else: else:
raise ModuleInstallError('The latest version of %s is already installed' % module.name) raise ModuleInstallError('The latest version of %s is already installed' % module.name)
browser = WeboobBrowser()
progress.progress(0.2, 'Downloading module...') progress.progress(0.2, 'Downloading module...')
try: try:
tardata = browser.readurl(module.url) tardata = self.browser.open(module.url).content
except BrowserUnavailable as e: except BrowserUnavailable as e:
raise ModuleInstallError('Unable to fetch module: %s' % e) raise ModuleInstallError('Unable to fetch module: %s' % e)
# Check signature # Check signature
if module.signed and Keyring.find_gpgv(): if module.signed and Keyring.find_gpgv():
progress.progress(0.5, 'Checking module authenticity...') 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_path = os.path.join(self.keyrings_dir, self.url2filename(module.repo_url))
keyring = Keyring(keyring_path) keyring = Keyring(keyring_path)
if not keyring.exists(): if not keyring.exists():
@ -679,7 +675,7 @@ class Repositories(object):
if os.path.isdir(module_dir): if os.path.isdir(module_dir):
shutil.rmtree(module_dir) shutil.rmtree(module_dir)
progress.progress(0.7, 'Setting up module...') 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) tar.extractall(self.modules_dir)
if not os.path.isdir(module_dir): if not os.path.isdir(module_dir):
raise ModuleInstallError('The archive for %s looks invalid.' % module.name) raise ModuleInstallError('The archive for %s looks invalid.' % module.name)
@ -776,7 +772,7 @@ class Keyring(object):
stderr=subprocess.PIPE) stderr=subprocess.PIPE)
out, err = proc.communicate(data) out, err = proc.communicate(data)
if proc.returncode or 'GOODSIG' not in out or 'VALIDSIG' not in out: 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 False
return True return True

View file

@ -18,9 +18,14 @@
# along with weboob. If not, see <http://www.gnu.org/licenses/>. # along with weboob. If not, see <http://www.gnu.org/licenses/>.
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.log import getLogger
from weboob.tools.misc import get_backtrace from weboob.tools.misc import get_backtrace
@ -45,14 +50,14 @@ class IScheduler(object):
raise NotImplementedError() raise NotImplementedError()
class RepeatedTimer(_Timer): class RepeatedTimer(Timer):
def run(self): def run(self):
while not self.finished.isSet(): while not self.finished.isSet():
try: try:
self.function(*self.args, **self.kwargs) self.function(*self.args, **self.kwargs)
except Exception: except Exception:
# do not stop timer because of an exception # do not stop timer because of an exception
print get_backtrace() print(get_backtrace())
self.finished.wait(self.interval) self.finished.wait(self.interval)
self.finished.set() self.finished.set()

View file

@ -18,6 +18,8 @@
# along with weboob. If not, see <http://www.gnu.org/licenses/>. # along with weboob. If not, see <http://www.gnu.org/licenses/>.
from __future__ import print_function
import logging import logging
import optparse import optparse
from optparse import OptionGroup, OptionParser from optparse import OptionGroup, OptionParser
@ -27,7 +29,6 @@ import tempfile
import warnings import warnings
from weboob.capabilities.base import ConversionWarning, CapBaseObject from weboob.capabilities.base import ConversionWarning, CapBaseObject
from weboob.tools.browser.browser import FormFieldConversionWarning
from weboob.core import Weboob, CallErrors from weboob.core import Weboob, CallErrors
from weboob.core.backendscfg import BackendsConfig from weboob.core.backendscfg import BackendsConfig
from weboob.tools.config.iconfig import ConfigError from weboob.tools.config.iconfig import ConfigError
@ -295,9 +296,9 @@ class BaseApplication(object):
if isinstance(error, MoreResultsAvailable): if isinstance(error, MoreResultsAvailable):
return False 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: if logging.root.level == logging.DEBUG:
print >>sys.stderr, backtrace print(backtrace, file=sys.stderr)
else: else:
return True return True
@ -322,7 +323,7 @@ class BaseApplication(object):
ask_debug_mode = True ask_debug_mode = True
if ask_debug_mode: if ask_debug_mode:
print >>sys.stderr, debugmsg print(debugmsg, file=sys.stderr)
def parse_args(self, args): def parse_args(self, args):
self.options, args = self._parser.parse_args(args) self.options, args = self._parser.parse_args(args)
@ -333,7 +334,7 @@ class BaseApplication(object):
if not option.help is optparse.SUPPRESS_HELP: if not option.help is optparse.SUPPRESS_HELP:
items.update(str(option).split('/')) items.update(str(option).split('/'))
items.update(self._get_completions()) items.update(self._get_completions())
print ' '.join(items) print(' '.join(items))
sys.exit(0) sys.exit(0)
if self.options.debug or self.options.save_responses: if self.options.debug or self.options.save_responses:
@ -350,13 +351,18 @@ class BaseApplication(object):
# this only matters to developers # this only matters to developers
if not self.options.debug and not self.options.save_responses: if not self.options.debug and not self.options.save_responses:
warnings.simplefilter('ignore', category=ConversionWarning) 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 = [] handlers = []
if self.options.save_responses: if self.options.save_responses:
responses_dirname = tempfile.mkdtemp(prefix='weboob_session_') 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['save_responses'] = True
log_settings['responses_dirname'] = responses_dirname log_settings['responses_dirname'] = responses_dirname
handlers.append(self.create_logging_file_handler(os.path.join(responses_dirname, 'debug.log'))) 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()]) cls.setup_logging(logging.INFO, [cls.create_default_logger()])
if args is None: 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: try:
app = cls() app = cls()
except BackendsConfig.WrongPermissions as e: except BackendsConfig.WrongPermissions as e:
print >>sys.stderr, e print(e, file=sys.stderr)
sys.exit(1) sys.exit(1)
try: try:
@ -437,12 +443,12 @@ class BaseApplication(object):
args = app.parse_args(args) args = app.parse_args(args)
sys.exit(app.main(args)) sys.exit(app.main(args))
except KeyboardInterrupt: except KeyboardInterrupt:
print >>sys.stderr, 'Program killed by SIGINT' print('Program killed by SIGINT', file=sys.stderr)
sys.exit(0) sys.exit(0)
except EOFError: except EOFError:
sys.exit(0) sys.exit(0)
except ConfigError as e: except ConfigError as e:
print >>sys.stderr, 'Configuration error: %s' % e print('Configuration error: %s' % e, file=sys.stderr)
sys.exit(1) sys.exit(1)
except CallErrors as e: except CallErrors as e:
try: try:
@ -451,7 +457,7 @@ class BaseApplication(object):
pass pass
sys.exit(1) sys.exit(1)
except ResultsConditionError as e: except ResultsConditionError as e:
print >>sys.stderr, '%s' % e print('%s' % e, file=sys.stderr)
sys.exit(1) sys.exit(1)
finally: finally:
app.deinit() app.deinit()

View file

@ -18,6 +18,7 @@
# along with weboob. If not, see <http://www.gnu.org/licenses/>. # along with weboob. If not, see <http://www.gnu.org/licenses/>.
from __future__ import print_function
from copy import copy from copy import copy
import getpass import getpass
@ -110,7 +111,7 @@ class ConsoleApplication(BaseApplication):
ret = super(ConsoleApplication, self).load_backends(*args, **kwargs) ret = super(ConsoleApplication, self).load_backends(*args, **kwargs)
for err in errors: 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): if self.ask('Do you want to reconfigure this backend?', default=True):
self.edit_backend(err.backend_name) self.edit_backend(err.backend_name)
self.load_backends(names=[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): def check_loaded_backends(self, default_config=None):
while len(self.enabled_backends) == 0: 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): if not os.isatty(sys.stdout.fileno()) or not self.ask('Do you want to configure backends?', default=True):
return False return False
@ -136,7 +137,7 @@ class ConsoleApplication(BaseApplication):
r = '' r = ''
while r != 'q': while r != 'q':
modules = [] modules = []
print '\nAvailable modules:' print('\nAvailable modules:')
for name, info in sorted(self.weboob.repositories.get_all_modules_info().iteritems()): for name, info in sorted(self.weboob.repositories.get_all_modules_info().iteritems()):
if not self.is_module_loadable(info): if not self.is_module_loadable(info):
continue continue
@ -150,16 +151,16 @@ class ConsoleApplication(BaseApplication):
loaded = 2 loaded = 2
else: else:
loaded += 1 loaded += 1
print '%s%d)%s [%s] %s%-15s%s %s' % (self.BOLD, len(modules), self.NC, loaded, print('%s%d)%s [%s] %s%-15s%s %s' % (self.BOLD, len(modules), self.NC, loaded,
self.BOLD, name, self.NC, info.description) self.BOLD, name, self.NC, info.description))
print '%sa) --all--%s install all backends' % (self.BOLD, self.NC) print('%sa) --all--%s install all backends' % (self.BOLD, self.NC))
print '%sq)%s --stop--\n' % (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)$') r = self.ask('Select a backend to create (q to stop)', regexp='^(\d+|q|a)$')
if str(r).isdigit(): if str(r).isdigit():
i = int(r) - 1 i = int(r) - 1
if i < 0 or i >= len(modules): 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 continue
name = modules[i] name = modules[i]
try: try:
@ -167,7 +168,7 @@ class ConsoleApplication(BaseApplication):
if inst: if inst:
self.load_backends(names=[inst]) self.load_backends(names=[inst])
except (KeyboardInterrupt, EOFError): except (KeyboardInterrupt, EOFError):
print '\nAborted.' print('\nAborted.')
elif r == 'a': elif r == 'a':
try: try:
for name in modules: for name in modules:
@ -177,11 +178,11 @@ class ConsoleApplication(BaseApplication):
if inst: if inst:
self.load_backends(names=[inst]) self.load_backends(names=[inst])
except (KeyboardInterrupt, EOFError): except (KeyboardInterrupt, EOFError):
print '\nAborted.' print('\nAborted.')
else: else:
break break
print 'Right right!' print('Right right!')
def _handle_options(self): def _handle_options(self):
self.load_default_backends() self.load_default_backends()
@ -202,7 +203,7 @@ class ConsoleApplication(BaseApplication):
try: try:
super(ConsoleApplication, klass).run(args) super(ConsoleApplication, klass).run(args)
except BackendNotFound as e: except BackendNotFound as e:
print 'Error: Backend "%s" not found.' % e print('Error: Backend "%s" not found.' % e)
sys.exit(1) sys.exit(1)
def do(self, function, *args, **kwargs): def do(self, function, *args, **kwargs):
@ -234,11 +235,11 @@ class ConsoleApplication(BaseApplication):
backend = None backend = None
if not backend: if not backend:
print >>sys.stderr, 'Backend "%s" does not exist.' % name print('Backend "%s" does not exist.' % name, file=sys.stderr)
return 1 return 1
if not backend.has_caps(ICapAccount) or backend.klass.ACCOUNT_REGISTER_PROPERTIES is None: 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 return 1
account = Account() account = Account()
@ -252,17 +253,17 @@ class ConsoleApplication(BaseApplication):
for key, prop in backend.klass.ACCOUNT_REGISTER_PROPERTIES.iteritems(): for key, prop in backend.klass.ACCOUNT_REGISTER_PROPERTIES.iteritems():
if not asked_config: if not asked_config:
asked_config = True asked_config = True
print 'Configuration of new account %s' % website print('Configuration of new account %s' % website)
print '-----------------------------%s' % ('-' * len(website)) print('-----------------------------%s' % ('-' * len(website)))
p = copy(prop) p = copy(prop)
p.set(self.ask(prop, default=account.properties[key].get() if (key in account.properties) else prop.default)) p.set(self.ask(prop, default=account.properties[key].get() if (key in account.properties) else prop.default))
account.properties[key] = p account.properties[key] = p
if asked_config: if asked_config:
print '-----------------------------%s' % ('-' * len(website)) print('-----------------------------%s' % ('-' * len(website)))
try: try:
backend.klass.register_account(account) backend.klass.register_account(account)
except AccountRegisterError as e: except AccountRegisterError as e:
print u'%s' % e print(u'%s' % e)
if self.ask('Do you want to try again?', default=True): if self.ask('Do you want to try again?', default=True):
continue continue
else: else:
@ -283,10 +284,10 @@ class ConsoleApplication(BaseApplication):
try: try:
self.weboob.repositories.install(name) self.weboob.repositories.install(name)
except ModuleInstallError as e: 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 return False
print '' print('')
return True return True
def edit_backend(self, name, params=None): def edit_backend(self, name, params=None):
@ -304,7 +305,7 @@ class ConsoleApplication(BaseApplication):
if minfo is None: if minfo is None:
raise ModuleLoadError(name, 'Module does not exist') raise ModuleLoadError(name, 'Module does not exist')
if not minfo.is_installed(): 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) self.install_module(minfo)
module = self.weboob.modules_loader.get_or_load_module(name) module = self.weboob.modules_loader.get_or_load_module(name)
config = module.config config = module.config
@ -315,7 +316,7 @@ class ConsoleApplication(BaseApplication):
params = items params = items
config = module.config.load(self.weboob, bname, name, params, nofail=True) config = module.config.load(self.weboob, bname, name, params, nofail=True)
except ModuleLoadError as e: 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 return 1
# ask for params non-specified on command-line arguments # ask for params non-specified on command-line arguments
@ -323,18 +324,18 @@ class ConsoleApplication(BaseApplication):
for key, value in config.iteritems(): for key, value in config.iteritems():
if not asked_config: if not asked_config:
asked_config = True asked_config = True
print '' print('')
print 'Configuration of backend %s' % module.name print('Configuration of backend %s' % module.name)
print '-------------------------%s' % ('-' * len(module.name)) print('-------------------------%s' % ('-' * len(module.name)))
if key not in params or edit: if key not in params or edit:
params[key] = self.ask(value, default=params[key] if (key in params) else value.default) params[key] = self.ask(value, default=params[key] if (key in params) else value.default)
else: 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: if asked_config:
print '-------------------------%s' % ('-' * len(module.name)) print('-------------------------%s' % ('-' * len(module.name)))
while not edit and self.weboob.backends_config.backend_exists(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): if not self.ask('Add new backend for module "%s"?' % module.name, default=False):
return 1 return 1
@ -347,10 +348,10 @@ class ConsoleApplication(BaseApplication):
continue continue
config[key].set(value) config[key].set(value)
config.save(edit=edit) 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 return name
except BackendAlreadyExists: except BackendAlreadyExists:
print >>sys.stderr, 'Backend "%s" already exists.' % name print('Backend "%s" already exists.' % name, file=sys.stderr)
return 1 return 1
def ask(self, question, default=None, masked=None, regexp=None, choices=None, tiny=None): 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) question = u'[%s] %s' % (v.id, question)
if isinstance(v, ValueBackendPassword): 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 question = v.label
choices = OrderedDict() choices = OrderedDict()
choices['c'] = 'Run an external tool during backend load' choices['c'] = 'Run an external tool during backend load'
@ -414,9 +415,9 @@ class ConsoleApplication(BaseApplication):
if r == 'p': if r == 'p':
return '' return ''
if r == 'c': 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): if v.is_command(v.default):
print ': %s' % v.default[1:-1] print(': %s' % v.default[1:-1])
else: else:
d = None d = None
while True: while True:
@ -424,7 +425,7 @@ class ConsoleApplication(BaseApplication):
try: try:
subprocess.check_output(cmd, shell=True) subprocess.check_output(cmd, shell=True)
except subprocess.CalledProcessError as e: except subprocess.CalledProcessError as e:
print '%s' % e print('%s' % e)
else: else:
return '`%s`' % cmd return '`%s`' % cmd
@ -443,10 +444,10 @@ class ConsoleApplication(BaseApplication):
question = u'%s (%s)' % (question, '/'.join((s.upper() if s == v.default else s) question = u'%s (%s)' % (question, '/'.join((s.upper() if s == v.default else s)
for s in (v.choices.iterkeys()))) for s in (v.choices.iterkeys())))
for key, value in v.choices.iteritems(): 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: else:
for n, (key, value) in enumerate(v.choices.iteritems()): 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 aliases[str(n + 1)] = key
question = u'%s (choose in list)' % question question = u'%s (choose in list)' % question
if v.masked: if v.masked:
@ -483,7 +484,7 @@ class ConsoleApplication(BaseApplication):
try: try:
v.set(line) v.set(line)
except ValueError as e: except ValueError as e:
print >>sys.stderr, u'Error: %s' % e print(u'Error: %s' % e, file=sys.stderr)
else: else:
break break
@ -509,8 +510,8 @@ class ConsoleApplication(BaseApplication):
text = f.read() text = f.read()
else: else:
if sys.stdin.isatty(): if sys.stdin.isatty():
print 'Reading content from stdin... Type ctrl-D ' \ print('Reading content from stdin... Type ctrl-D ' \
'from an empty line to stop.' 'from an empty line to stop.')
text = sys.stdin.read() text = sys.stdin.read()
return text.decode(sys.stdin.encoding or locale.getpreferredencoding()) return text.decode(sys.stdin.encoding or locale.getpreferredencoding())
@ -524,7 +525,7 @@ class ConsoleApplication(BaseApplication):
msg = unicode(error) msg = unicode(error)
if not msg: if not msg:
msg = 'invalid login/password.' 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): if self.ask('Do you want to reconfigure this backend?', default=True):
self.unload_backends(names=[backend.name]) self.unload_backends(names=[backend.name])
self.edit_backend(backend.name) self.edit_backend(backend.name)
@ -533,21 +534,21 @@ class ConsoleApplication(BaseApplication):
msg = unicode(error) msg = unicode(error)
if not msg: if not msg:
msg = 'website is unavailable.' 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): 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): elif isinstance(error, NotImplementedError):
print >>sys.stderr, u'Error(%s): this feature is not supported yet by this backend.' % backend.name print(u'Error(%s): this feature is not supported yet by this backend.' % backend.name, file=sys.stderr)
print >>sys.stderr, u' %s To help the maintainer of this backend implement this feature,' % (' ' * len(backend.name)) print(u' %s To help the maintainer of this backend implement this feature,' % (' ' * len(backend.name)), file=sys.stderr)
print >>sys.stderr, u' %s please contact: %s <%s@issues.weboob.org>' % (' ' * len(backend.name), backend.MAINTAINER, backend.NAME) print(u' %s please contact: %s <%s@issues.weboob.org>' % (' ' * len(backend.name), backend.MAINTAINER, backend.NAME), file=sys.stderr)
elif isinstance(error, UserError): 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): 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): 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: 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) minfo = self.weboob.repositories.get_module_info(backend.NAME)
if minfo and not minfo.is_local(): 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 \ 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.ask('A new version of %s is available. Do you want to install it?' % minfo.name, default=True) and \
self.install_module(minfo): 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 return
if logging.root.level == logging.DEBUG: if logging.root.level == logging.DEBUG:
print >>sys.stderr, backtrace print(backtrace, file=sys.stderr)
else: else:
return True return True
@ -581,6 +582,6 @@ class ConsoleApplication(BaseApplication):
ask_debug_mode = True ask_debug_mode = True
if ask_debug_mode: if ask_debug_mode:
print >>sys.stderr, debugmsg print(debugmsg, file=sys.stderr)
elif len(more_results) > 0: 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)

View file

@ -18,6 +18,8 @@
# along with weboob. If not, see <http://www.gnu.org/licenses/>. # along with weboob. If not, see <http://www.gnu.org/licenses/>.
from __future__ import print_function
import os import os
import sys import sys
import subprocess import subprocess
@ -118,7 +120,7 @@ class IFormatter(object):
if isinstance(line, unicode): if isinstance(line, unicode):
line = line.encode('utf-8') line = line.encode('utf-8')
print line print(line)
self.print_lines += 1 self.print_lines += 1
def start_format(self, **kwargs): def start_format(self, **kwargs):

View file

@ -18,6 +18,8 @@
# along with weboob. If not, see <http://www.gnu.org/licenses/>. # along with weboob. If not, see <http://www.gnu.org/licenses/>.
from __future__ import print_function
from weboob.capabilities.base import NotAvailable, NotLoaded from weboob.capabilities.base import NotAvailable, NotLoaded
from weboob.tools.json import json from weboob.tools.json import json
@ -52,7 +54,7 @@ class JsonFormatter(IFormatter):
self.queue = [] self.queue = []
def flush(self): def flush(self):
print json.dumps(self.queue, cls=Encoder) print(json.dumps(self.queue, cls=Encoder))
def format_dict(self, item): def format_dict(self, item):
self.queue.append(item) self.queue.append(item)
@ -64,4 +66,4 @@ class JsonLineFormatter(IFormatter):
The advantage is that it can be streamed. The advantage is that it can be streamed.
""" """
def format_dict(self, item): def format_dict(self, item):
print json.dumps(item, cls=Encoder) print(json.dumps(item, cls=Encoder))

View file

@ -18,6 +18,8 @@
# along with weboob. If not, see <http://www.gnu.org/licenses/>. # along with weboob. If not, see <http://www.gnu.org/licenses/>.
from __future__ import print_function
from prettytable import PrettyTable from prettytable import PrettyTable
from weboob.capabilities.base import empty from weboob.capabilities.base import empty
@ -40,7 +42,7 @@ class TableFormatter(IFormatter):
def flush(self): def flush(self):
s = self.get_formatted_table() s = self.get_formatted_table()
if s is not None: if s is not None:
print s.encode('utf-8') print(s.encode('utf-8'))
def get_formatted_table(self): def get_formatted_table(self):
if len(self.queue) == 0: if len(self.queue) == 0:

View file

@ -18,6 +18,8 @@
# along with weboob. If not, see <http://www.gnu.org/licenses/>. # along with weboob. If not, see <http://www.gnu.org/licenses/>.
from __future__ import print_function
import os import os
from subprocess import PIPE, Popen from subprocess import PIPE, Popen
import cookielib import cookielib
@ -102,7 +104,7 @@ class MediaPlayer(object):
player_name = args[0] player_name = args[0]
args.append(media.url) args.append(media.url)
print 'Invoking "%s".' % (' '.join(args)) print('Invoking "%s".' % (' '.join(args)))
os.spawnlp(os.P_WAIT, player_name, *args) os.spawnlp(os.P_WAIT, player_name, *args)
def _play_proxy(self, media, player_name, args): def _play_proxy(self, media, player_name, args):
@ -120,9 +122,9 @@ class MediaPlayer(object):
assert args is not None assert args is not None
print ':: Play_proxy streaming from %s' % media.url print(':: Play_proxy streaming from %s' % media.url)
print ':: to %s %s' % (player_name, args) print(':: to %s %s' % (player_name, args))
print player_name + ' ' + args print(player_name + ' ' + args)
proc = Popen(player_name + ' ' + args, stdin=PIPE, shell=True) proc = Popen(player_name + ' ' + args, stdin=PIPE, shell=True)
# Handle cookies (and redirection 302...) # Handle cookies (and redirection 302...)
@ -142,7 +144,7 @@ class MediaPlayer(object):
try: try:
proc.stdin.write(_buffer) proc.stdin.write(_buffer)
except: except:
print "play_proxy broken pipe. Can't write anymore." print("play_proxy broken pipe. Can't write anymore.")
break break
def _play_rtmp(self, media, player_name, args): def _play_rtmp(self, media, player_name, args):
@ -181,9 +183,9 @@ class MediaPlayer(object):
player_name = player_name.split(' ') player_name = player_name.split(' ')
args = args.split(' ') args = args.split(' ')
print ':: Streaming from %s' % media_url print(':: Streaming from %s' % media_url)
print ':: to %s %s' % (player_name, args) print(':: to %s %s' % (player_name, args))
print ':: %s' % rtmp print(':: %s' % rtmp)
p1 = Popen(rtmp.split(), stdout=PIPE) p1 = Popen(rtmp.split(), stdout=PIPE)
Popen(player_name + args, stdin=p1.stdout, stderr=PIPE) Popen(player_name + args, stdin=p1.stdout, stderr=PIPE)

View file

@ -17,6 +17,8 @@
# You should have received a copy of the GNU Affero General Public License # You should have received a copy of the GNU Affero General Public License
# along with weboob. If not, see <http://www.gnu.org/licenses/>. # along with weboob. If not, see <http://www.gnu.org/licenses/>.
from __future__ import print_function
import sys import sys
import logging import logging
import re import re
@ -237,8 +239,8 @@ class QtDo(QObject):
msg += u'<br />%s' % to_unicode(line) msg += u'<br />%s' % to_unicode(line)
if ul_opened: if ul_opened:
msg += u'</li></ul>' msg += u'</li></ul>'
print >>sys.stderr, error print(error, file=sys.stderr)
print >>sys.stderr, backtrace print(backtrace, file=sys.stderr)
QMessageBox.critical(None, unicode(self.tr('Error with backend %s')) % backend.name, QMessageBox.critical(None, unicode(self.tr('Error with backend %s')) % backend.name,
msg, QMessageBox.Ok) msg, QMessageBox.Ok)

View file

@ -17,6 +17,7 @@
# You should have received a copy of the GNU Affero General Public License # You should have received a copy of the GNU Affero General Public License
# along with weboob. If not, see <http://www.gnu.org/licenses/>. # along with weboob. If not, see <http://www.gnu.org/licenses/>.
from __future__ import print_function
import atexit import atexit
from cmd import Cmd from cmd import Cmd
@ -198,20 +199,20 @@ class ReplApplication(Cmd, ConsoleApplication):
except BackendNotGiven as e: except BackendNotGiven as e:
backend_name = None backend_name = None
while not backend_name: 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): 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, print('%s%d)%s %s%-15s%s %s' % (self.BOLD, index + 1, self.NC, self.BOLD, name, self.NC,
backend.DESCRIPTION) backend.DESCRIPTION))
i = self.ask('Select a backend to proceed with "%s"' % id) i = self.ask('Select a backend to proceed with "%s"' % id)
if not i.isdigit(): if not i.isdigit():
if not i in dict(e.backends): 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 continue
backend_name = i backend_name = i
else: else:
i = int(i) i = int(i)
if i < 0 or i > len(e.backends): 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 continue
backend_name = e.backends[i-1][0] backend_name = e.backends[i-1][0]
@ -405,12 +406,12 @@ class ReplApplication(Cmd, ConsoleApplication):
except CallErrors as e: except CallErrors as e:
self.bcall_errors_handler(e) self.bcall_errors_handler(e)
except BackendNotGiven as e: except BackendNotGiven as e:
print >>sys.stderr, 'Error: %s' % str(e) print('Error: %s' % str(e), file=sys.stderr)
except NotEnoughArguments as e: 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): except (KeyboardInterrupt, EOFError):
# ^C during a command process doesn't exit application. # ^C during a command process doesn't exit application.
print '\nAborted.' print('\nAborted.')
finally: finally:
self.flush() self.flush()
@ -422,12 +423,12 @@ class ReplApplication(Cmd, ConsoleApplication):
pass pass
def default(self, line): 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) cmd, arg, ignore = Cmd.parseline(self, line)
if cmd is not None: if cmd is not None:
names = set(name[3:] for name in self.get_names() if name.startswith('do_' + cmd)) names = set(name[3:] for name in self.get_names() if name.startswith('do_' + cmd))
if len(names) > 0: 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 return 2
def completenames(self, text, *ignored): def completenames(self, text, *ignored):
@ -561,7 +562,7 @@ class ReplApplication(Cmd, ConsoleApplication):
Quit the command line interpreter when ^D is pressed. 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 empty line for the next shell prompt to appear on the first column of the terminal
print print()
return self.do_quit(arg) return self.do_quit(arg)
def do_help(self, arg=None): 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) lines[0] = '%s%s%s' % (self.BOLD, lines[0], self.NC)
self.stdout.write('%s\n' % '\n'.join(lines)) self.stdout.write('%s\n' % '\n'.join(lines))
else: else:
print >>sys.stderr, 'Unknown command: "%s"' % arg print('Unknown command: "%s"' % arg, file=sys.stderr)
else: else:
cmds = self._parser.formatter.format_commands(self._parser.commands) cmds = self._parser.formatter.format_commands(self._parser.commands)
self.stdout.write('%s\n' % cmds) self.stdout.write('%s\n' % cmds)
@ -644,20 +645,20 @@ class ReplApplication(Cmd, ConsoleApplication):
if action in ('add', 'register'): if action in ('add', 'register'):
minfo = self.weboob.repositories.get_module_info(backend_name) minfo = self.weboob.repositories.get_module_info(backend_name)
if minfo is None: 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 return 1
else: else:
if not minfo.has_caps(self.CAPS): 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 return 1
else: else:
if backend_name not in [backend.name for backend in self.weboob.iter_backends()]: 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 return 1
if action in ('enable', 'disable', 'only', 'add', 'register', 'edit', 'remove'): if action in ('enable', 'disable', 'only', 'add', 'register', 'edit', 'remove'):
if not given_backend_names: 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 return 2
given_backends = set(backend for backend in self.weboob.iter_backends() if backend.name in given_backend_names) 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: try:
self.enabled_backends.remove(backend) self.enabled_backends.remove(backend)
except KeyError: except KeyError:
print >>sys.stderr, '%s is not enabled' % backend.name print('%s is not enabled' % backend.name, file=sys.stderr)
elif action == 'only': elif action == 'only':
self.enabled_backends = set() self.enabled_backends = set()
for backend in given_backends: for backend in given_backends:
@ -678,9 +679,9 @@ class ReplApplication(Cmd, ConsoleApplication):
elif action == 'list': elif action == 'list':
enabled_backends_names = set(backend.name for backend in self.enabled_backends) 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 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: if len(disabled_backends_names) > 0:
print 'Disabled: %s' % ', '.join(disabled_backends_names) print('Disabled: %s' % ', '.join(disabled_backends_names))
elif action == 'add': elif action == 'add':
for name in given_backend_names: for name in given_backend_names:
instname = self.add_backend(name) instname = self.add_backend(name)
@ -705,7 +706,7 @@ class ReplApplication(Cmd, ConsoleApplication):
self.unload_backends(backend.name) self.unload_backends(backend.name)
elif action == 'list-modules': elif action == 'list-modules':
modules = [] modules = []
print 'Modules list:' print('Modules list:')
for name, info in sorted(self.weboob.repositories.get_all_modules_info().iteritems()): for name, info in sorted(self.weboob.repositories.get_all_modules_info().iteritems()):
if not self.is_module_loadable(info): if not self.is_module_loadable(info):
continue continue
@ -719,14 +720,14 @@ class ReplApplication(Cmd, ConsoleApplication):
loaded = 2 loaded = 2
else: else:
loaded += 1 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: else:
print >>sys.stderr, 'Unknown action: "%s"' % action print('Unknown action: "%s"' % action, file=sys.stderr)
return 1 return 1
if len(self.enabled_backends) == 0: 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): def complete_logging(self, text, line, begidx, endidx):
levels = ('debug', 'info', 'warning', 'error', 'quiet', 'default') levels = ('debug', 'info', 'warning', 'error', 'quiet', 'default')
@ -760,15 +761,15 @@ class ReplApplication(Cmd, ConsoleApplication):
if logging.root.level == level: if logging.root.level == level:
current = label current = label
break break
print 'Current level: %s' % current print('Current level: %s' % current)
return return
levels = dict(levels) levels = dict(levels)
try: try:
level = levels[args[0]] level = levels[args[0]]
except KeyError: except KeyError:
print >>sys.stderr, 'Level "%s" does not exist.' % args[0] print('Level "%s" does not exist.' % args[0], file=sys.stderr)
print >>sys.stderr, 'Availables: %s' % ' '.join(levels.iterkeys()) print('Availables: %s' % ' '.join(levels.iterkeys()), file=sys.stderr)
return 2 return 2
else: else:
logging.root.setLevel(level) logging.root.setLevel(level)
@ -792,13 +793,13 @@ class ReplApplication(Cmd, ConsoleApplication):
try: try:
self.condition = ResultsCondition(line) self.condition = ResultsCondition(line)
except ResultsConditionError as e: except ResultsConditionError as e:
print >>sys.stderr, '%s' % e print('%s' % e, file=sys.stderr)
return 2 return 2
else: else:
if self.condition is None: if self.condition is None:
print 'No condition is set.' print('No condition is set.')
else: else:
print str(self.condition) print(str(self.condition))
def do_count(self, line): def do_count(self, line):
""" """
@ -819,7 +820,7 @@ class ReplApplication(Cmd, ConsoleApplication):
try: try:
count = int(line) count = int(line)
except ValueError: 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 return 2
else: else:
if count > 0: if count > 0:
@ -830,9 +831,9 @@ class ReplApplication(Cmd, ConsoleApplication):
self._is_default_count = False self._is_default_count = False
else: else:
if self.options.count is None: if self.options.count is None:
print 'Counting disabled.' print('Counting disabled.')
else: else:
print self.options.count print(self.options.count)
def complete_formatter(self, text, line, *ignored): def complete_formatter(self, text, line, *ignored):
formatters = self.formatters_loader.get_available_formatters() formatters = self.formatters_loader.get_available_formatters()
@ -871,17 +872,17 @@ class ReplApplication(Cmd, ConsoleApplication):
args = line.strip().split() args = line.strip().split()
if args: if args:
if args[0] == 'list': if args[0] == 'list':
print ', '.join(self.formatters_loader.get_available_formatters()) print(', '.join(self.formatters_loader.get_available_formatters()))
elif args[0] == 'option': elif args[0] == 'option':
if len(args) > 1: if len(args) > 1:
if len(args) == 2: if len(args) == 2:
if args[1] == 'header': 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': elif args[1] == 'keys':
print 'off' if self.options.no_keys else 'on' print('off' if self.options.no_keys else 'on')
else: else:
if args[2] not in ('on', 'off'): 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 return 2
else: else:
if args[1] == 'header': if args[1] == 'header':
@ -889,7 +890,7 @@ class ReplApplication(Cmd, ConsoleApplication):
elif args[1] == 'keys': elif args[1] == 'keys':
self.options.no_keys = True if args[2] == 'off' else False self.options.no_keys = True if args[2] == 'off' else False
else: 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 return 2
else: else:
if args[0] in self.formatters_loader.get_available_formatters(): if args[0] in self.formatters_loader.get_available_formatters():
@ -899,13 +900,13 @@ class ReplApplication(Cmd, ConsoleApplication):
self.commands_formatters = {} self.commands_formatters = {}
self.DEFAULT_FORMATTER = self.set_formatter(args[0]) self.DEFAULT_FORMATTER = self.set_formatter(args[0])
else: else:
print >>sys.stderr, 'Formatter "%s" is not available.\n' \ print('Formatter "%s" is not available.\n' \
'Available formatters: %s.' % (args[0], ', '.join(self.formatters_loader.get_available_formatters())) 'Available formatters: %s.' % (args[0], ', '.join(self.formatters_loader.get_available_formatters())), file=sys.stderr)
return 1 return 1
else: else:
print 'Default formatter: %s' % self.DEFAULT_FORMATTER print('Default formatter: %s' % self.DEFAULT_FORMATTER)
for key, klass in self.commands_formatters.iteritems(): 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): def do_select(self, line):
""" """
@ -922,7 +923,7 @@ class ReplApplication(Cmd, ConsoleApplication):
split = line.split() split = line.split()
self.selected_fields = split self.selected_fields = split
else: else:
print ' '.join(self.selected_fields) print(' '.join(self.selected_fields))
def complete_inspect(self, text, line, begidx, endidx): def complete_inspect(self, text, line, begidx, endidx):
return sorted(set(backend.name for backend in self.enabled_backends)) return sorted(set(backend.name for backend in self.enabled_backends))
@ -940,18 +941,18 @@ class ReplApplication(Cmd, ConsoleApplication):
else: else:
backend_name = line.strip() backend_name = line.strip()
if not backend_name: if not backend_name:
print >>sys.stderr, 'Please specify a backend name.' print('Please specify a backend name.', file=sys.stderr)
return 2 return 2
backends = set(backend for backend in self.enabled_backends if backend.name == backend_name) backends = set(backend for backend in self.enabled_backends if backend.name == backend_name)
if not backends: 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 return 1
backend = backends.pop() backend = backends.pop()
if not backend.browser: 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 return 1
if not backend.browser.page: 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 return 1
browser = backend.browser browser = backend.browser
data = browser.parser.tostring(browser.page.document) data = browser.parser.tostring(browser.page.document)
@ -959,7 +960,7 @@ class ReplApplication(Cmd, ConsoleApplication):
from webkit_mechanize_browser.browser import Browser from webkit_mechanize_browser.browser import Browser
from weboob.tools.inspect import Page from weboob.tools.inspect import Page
except ImportError: except ImportError:
print data print(data)
else: else:
page = Page(core=browser, data=data, uri=browser._response.geturl()) page = Page(core=browser, data=data, uri=browser._response.geturl())
browser = Browser(view=page.view) browser = Browser(view=page.view)
@ -1064,11 +1065,11 @@ class ReplApplication(Cmd, ConsoleApplication):
def _format_collection(self, collection, only): def _format_collection(self, collection, only):
if only is False or collection.basename in only: if only is False or collection.basename in only:
if collection.basename and collection.title: if collection.basename and collection.title:
print u'%s~ (%s) %s (%s)%s' % \ print(u'%s~ (%s) %s (%s)%s' % \
(self.BOLD, collection.basename, collection.title, collection.backend, self.NC) (self.BOLD, collection.basename, collection.title, collection.backend, self.NC))
else: else:
print u'%s~ (%s) (%s)%s' % \ print(u'%s~ (%s) (%s)%s' % \
(self.BOLD, collection.basename, collection.backend, self.NC) (self.BOLD, collection.basename, collection.backend, self.NC))
def _format_obj(self, obj, only): def _format_obj(self, obj, only):
@ -1106,7 +1107,7 @@ class ReplApplication(Cmd, ConsoleApplication):
if len(collections) == 1: if len(collections) == 1:
self.working_path.split_path = collections[0].split_path self.working_path.split_path = collections[0].split_path
else: 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() self.working_path.restore()
return 1 return 1
@ -1199,10 +1200,10 @@ class ReplApplication(Cmd, ConsoleApplication):
try: try:
self.formatter = self.formatters_loader.build_formatter(name) self.formatter = self.formatters_loader.build_formatter(name)
except FormatterLoadError as e: except FormatterLoadError as e:
print >>sys.stderr, '%s' % e print('%s' % e, file=sys.stderr)
if self.DEFAULT_FORMATTER == name: if self.DEFAULT_FORMATTER == name:
self.DEFAULT_FORMATTER = ReplApplication.DEFAULT_FORMATTER 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) self.formatter = self.formatters_loader.build_formatter(self.DEFAULT_FORMATTER)
name = self.DEFAULT_FORMATTER name = self.DEFAULT_FORMATTER
if self.options.no_header: if self.options.no_header:
@ -1235,9 +1236,9 @@ class ReplApplication(Cmd, ConsoleApplication):
try: try:
self.formatter.format(obj=result, selected_fields=fields, alias=alias) self.formatter.format(obj=result, selected_fields=fields, alias=alias)
except FieldNotFound as e: except FieldNotFound as e:
print >>sys.stderr, e print(e, file=sys.stderr)
except MandatoryFieldsNotFound as e: 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): def flush(self):
self.formatter.flush() self.formatter.flush()

View file

@ -18,6 +18,12 @@
# along with weboob. If not, see <http://www.gnu.org/licenses/>. # along with weboob. If not, see <http://www.gnu.org/licenses/>.
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 copy import copy
from httplib import BadStatusLine from httplib import BadStatusLine
@ -28,7 +34,6 @@ except ImportError:
raise ImportError('Please install python-mechanize') raise ImportError('Please install python-mechanize')
import os import os
import sys
import re import re
import tempfile import tempfile
from threading import RLock from threading import RLock
@ -288,7 +293,7 @@ class StandardBrowser(mechanize.Browser):
""" """
if self.responses_dirname is None: if self.responses_dirname is None:
self.responses_dirname = tempfile.mkdtemp(prefix='weboob_session_') 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): elif not os.path.isdir(self.responses_dirname):
os.makedirs(self.responses_dirname) os.makedirs(self.responses_dirname)
# get the content-type, remove optionnal charset part # get the content-type, remove optionnal charset part
@ -391,7 +396,7 @@ class StandardBrowser(mechanize.Browser):
value = [self.str(is_list.index(args[label]))] value = [self.str(is_list.index(args[label]))]
except ValueError as e: except ValueError as e:
if args[label]: 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 return
else: else:
value = [self.str(args[label])] value = [self.str(args[label])]

View file

@ -18,6 +18,8 @@
# along with weboob. If not, see <http://www.gnu.org/licenses/>. # along with weboob. If not, see <http://www.gnu.org/licenses/>.
from __future__ import print_function
try: try:
import sqlite3 as sqlite import sqlite3 as sqlite
except ImportError as e: except ImportError as e:
@ -40,7 +42,7 @@ class FirefoxCookieJar(CookieJar):
try: try:
db = sqlite.connect(database=self.sqlite_file, timeout=10.0) db = sqlite.connect(database=self.sqlite_file, timeout=10.0)
except sqlite.OperationalError as err: 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 None
return db return db

View file

@ -17,10 +17,13 @@
# You should have received a copy of the GNU Affero General Public License # You should have received a copy of the GNU Affero General Public License
# along with weboob. If not, see <http://www.gnu.org/licenses/>. # along with weboob. If not, see <http://www.gnu.org/licenses/>.
from __future__ import absolute_import from __future__ import absolute_import, print_function
import re import re
from urlparse import urlparse, urljoin try:
from urllib.parse import urlparse, urljoin
except ImportError:
from urlparse import urlparse, urljoin
import mimetypes import mimetypes
import os import os
import tempfile import tempfile
@ -157,7 +160,7 @@ class BaseBrowser(object):
def _save(self, response, warning=False, **kwargs): def _save(self, response, warning=False, **kwargs):
if self.responses_dirname is None: if self.responses_dirname is None:
self.responses_dirname = tempfile.mkdtemp(prefix='weboob_session_') 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): elif not os.path.isdir(self.responses_dirname):
os.makedirs(self.responses_dirname) os.makedirs(self.responses_dirname)

View file

@ -17,7 +17,10 @@
# along with weboob. If not, see <http://www.gnu.org/licenses/>. # along with weboob. If not, see <http://www.gnu.org/licenses/>.
import requests.cookies import requests.cookies
import cookielib try:
import cookielib
except ImportError:
import http.cookiejar as cookielib
__all__ = ['WeboobCookieJar'] __all__ = ['WeboobCookieJar']

View file

@ -26,6 +26,7 @@ import re
import lxml.html as html import lxml.html as html
from weboob.tools.misc import html2text from weboob.tools.misc import html2text
from weboob.tools.compat import basestring
from weboob.capabilities.base import empty from weboob.capabilities.base import empty
@ -258,7 +259,7 @@ class CleanDecimal(CleanText):
if self.replace_dots: if self.replace_dots:
text = text.replace('.','').replace(',','.') text = text.replace('.','').replace(',','.')
try: try:
return Decimal(re.sub(ur'[^\d\-\.]', '', text)) return Decimal(re.sub(r'[^\d\-\.]', '', text))
except InvalidOperation as e: except InvalidOperation as e:
return self.default_or_raise(e) return self.default_or_raise(e)
@ -388,7 +389,7 @@ class DateGuesser(Filter):
class Time(Filter): class Time(Filter):
klass = datetime.time klass = datetime.time
regexp = re.compile(ur'(?P<hh>\d+):?(?P<mm>\d+)(:(?P<ss>\d+))?') regexp = re.compile(r'(?P<hh>\d+):?(?P<mm>\d+)(:(?P<ss>\d+))?')
kwargs = {'hour': 'hh', 'minute': 'mm', 'second': 'ss'} kwargs = {'hour': 'hh', 'minute': 'mm', 'second': 'ss'}
def __init__(self, selector, default=_NO_DEFAULT): def __init__(self, selector, default=_NO_DEFAULT):
@ -407,7 +408,7 @@ class Time(Filter):
class Duration(Time): class Duration(Time):
klass = datetime.timedelta klass = datetime.timedelta
regexp = re.compile(ur'((?P<hh>\d+)[:;])?(?P<mm>\d+)[;:](?P<ss>\d+)') regexp = re.compile(r'((?P<hh>\d+)[:;])?(?P<mm>\d+)[;:](?P<ss>\d+)')
kwargs = {'hours': 'hh', 'minutes': 'mm', 'seconds': 'ss'} kwargs = {'hours': 'hh', 'minutes': 'mm', 'seconds': 'ss'}

View file

@ -19,18 +19,22 @@
from __future__ import absolute_import from __future__ import absolute_import
from urllib import unquote try:
from urllib.parse import unquote
except ImportError:
from urllib import unquote
import requests import requests
import re import re
import sys import sys
from copy import deepcopy from copy import deepcopy
from cStringIO import StringIO from io import BytesIO
import lxml.html as html import lxml.html as html
import lxml.etree as etree import lxml.etree as etree
from weboob.tools.json import json from weboob.tools.json import json
from weboob.tools.ordereddict import OrderedDict from weboob.tools.ordereddict import OrderedDict
from weboob.tools.regex_helper import normalize from weboob.tools.regex_helper import normalize
from weboob.tools.compat import basestring
from weboob.tools.log import getLogger from weboob.tools.log import getLogger
@ -527,7 +531,7 @@ class XMLPage(BasePage):
def __init__(self, browser, response, *args, **kwargs): def __init__(self, browser, response, *args, **kwargs):
super(XMLPage, self).__init__(browser, response, *args, **kwargs) super(XMLPage, self).__init__(browser, response, *args, **kwargs)
parser = etree.XMLParser(encoding=self.ENCODING or response.encoding) 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): class RawPage(BasePage):
@ -551,7 +555,7 @@ class HTMLPage(BasePage):
def __init__(self, browser, response, *args, **kwargs): def __init__(self, browser, response, *args, **kwargs):
super(HTMLPage, self).__init__(browser, response, *args, **kwargs) super(HTMLPage, self).__init__(browser, response, *args, **kwargs)
parser = html.HTMLParser(encoding=self.ENCODING or response.encoding) 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): def get_form(self, xpath='//form', name=None, nr=None):
""" """

37
weboob/tools/compat.py Normal file
View file

@ -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 <http://www.gnu.org/licenses/>.
__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

View file

@ -27,6 +27,7 @@ import traceback
import types import types
# keep compatibility # keep compatibility
from .date import local2utc, utc2local from .date import local2utc, utc2local
from .compat import unicode
__all__ = ['get_backtrace', 'get_bytes_size', 'html2text', 'iter_fields', __all__ = ['get_backtrace', 'get_bytes_size', 'html2text', 'iter_fields',