rewrite of the formatters system

This commit is contained in:
Romain Bignon 2012-04-03 22:40:18 +02:00
commit fc849995f4
22 changed files with 441 additions and 580 deletions

View file

@ -23,7 +23,7 @@ import sys
from weboob.capabilities.bank import ICapBank, Account, Transaction
from weboob.tools.application.repl import ReplApplication
from weboob.tools.application.formatters.iformatter import IFormatter
from weboob.tools.application.formatters.iformatter import IFormatter, PrettyFormatter
__all__ = ['Boobank']
@ -32,22 +32,16 @@ __all__ = ['Boobank']
class QifFormatter(IFormatter):
MANDATORY_FIELDS = ('id', 'date', 'raw', 'amount', 'category')
count = 0
def start_format(self, **kwargs):
self.output(u'!type:Bank')
def flush(self):
self.count = 0
def format_dict(self, item):
result = u''
if self.count == 0:
result += u'!type:Bank\n'
result += u'D%s\n' % item['date'].strftime('%d/%m/%y')
result += u'T%s\n' % item['amount']
if item['category']:
result += u'N%s\n' % item['category']
result += u'M%s\n' % item['raw']
def format_obj(self, obj, alias):
result = u'D%s\n' % obj.date.strftime('%d/%m/%y')
result += u'T%s\n' % obj.amount
if obj.category:
result += u'N%s\n' % obj.category
result += u'M%s\n' % obj.raw
result += u'^\n'
self.count += 1
return result
@ -55,110 +49,78 @@ class TransactionsFormatter(IFormatter):
MANDATORY_FIELDS = ('date', 'label', 'amount')
TYPES = ['', 'Transfer', 'Order', 'Check', 'Deposit', 'Payback', 'Withdrawal', 'Card', 'Loan', 'Bank']
count = 0
def start_format(self, **kwargs):
self.output(' Date Category Label Amount ')
self.output('------------+------------+---------------------------------------------------+-----------')
def flush(self):
if self.count < 1:
return
self.count = 0
def format_dict(self, item):
self.count += 1
result = u''
if self.count == 1:
result += ' Date Category Label Amount \n'
result += '------------+------------+---------------------------------------------------+-----------\n'
if item['category']:
_type = item['category']
def format_obj(self, obj, alias):
if hasattr(obj, 'category') and obj.category:
_type = obj.category
else:
try:
_type = self.TYPES[item['type']]
except IndexError:
_type = self.TYPES[obj.type]
except (IndexError,AttributeError):
_type = ''
label = item['label']
if not label:
label = item['raw']
result += ' %-10s %-12s %-50s %10.2f' % (item['date'].strftime('%Y-%m-%d'), _type, label[:50], item['amount'])
return result
label = obj.label
if not label and hasattr(obj, 'raw'):
label = obj.raw
return ' %-10s %-12s %-50s %10.2f' % (obj.date.strftime('%Y-%m-%d'), _type[:12], label[:50], obj.amount)
class TransferFormatter(IFormatter):
MANDATORY_FIELDS = ('id', 'date', 'origin', 'recipient', 'amount')
def flush(self):
pass
def format_dict(self, item):
result = u'------- Transfer %s -------\n' % item['id']
result += u'Date: %s\n' % item['date']
result += u'Origin: %s\n' % item['origin']
result += u'Recipient: %s\n' % item['recipient']
result += u'Amount: %.2f\n' % item['amount']
def format_obj(self, obj, alias):
result = u'------- Transfer %s -------\n' % obj.fillud
result += u'Date: %s\n' % obj.date
result += u'Origin: %s\n' % obj.origin
result += u'Recipient: %s\n' % obj.recipient
result += u'Amount: %.2f\n' % obj.amount
return result
class RecipientListFormatter(IFormatter):
class RecipientListFormatter(PrettyFormatter):
MANDATORY_FIELDS = ('id', 'label')
count = 0
def start_format(self, **kwargs):
self.output('Available recipients:')
def flush(self):
self.count = 0
def format_dict(self, item):
self.count += 1
if self.interactive:
backend = item['id'].split('@', 1)[1]
id = '#%d (%s)' % (self.count, backend)
else:
id = item['id']
return u'%s %-30s %s %s' % (self.BOLD, id, self.NC, item['label'])
def get_title(self, obj):
return obj.label
class AccountListFormatter(IFormatter):
MANDATORY_FIELDS = ('id', 'label', 'balance', 'coming')
count = 0
tot_balance = Decimal(0)
tot_coming = Decimal(0)
def flush(self):
if self.count < 1:
return
def start_format(self, **kwargs):
self.output(' %s Account Balance Coming ' % ((' ' * 15) if not self.interactive else ''))
self.output('------------------------------------------%s+----------+----------' % (('-' * 15) if not self.interactive else ''))
result = u'------------------------------------------%s+----------+----------\n' % (('-' * 15) if not self.interactive else '')
result += u'%s Total %8s %8s' % ((' ' * 15) if not self.interactive else '',
'%.2f' % self.tot_balance, '%.2f' % self.tot_coming)
self.after_format(result)
def format_obj(self, obj, alias):
if alias is not None:
id = '#%s (%s)' % (alias, obj.backend)
else:
id = obj.fullid
result = (u' %s%-' + (u'15' if alias is not None else '30') + u's%s %-25s %8s %8s') % \
(self.BOLD, id, self.NC,
obj.label, '%.2f' % obj.balance, '%.2f' % (obj.coming or Decimal(0.0)))
self.tot_balance += obj.balance
if obj.coming:
self.tot_coming += obj.coming
return result
def flush(self):
self.output(u'------------------------------------------%s+----------+----------' % (('-' * 15) if not self.interactive else ''))
self.output(u'%s Total %8s %8s' % ((' ' * 15) if not self.interactive else '',
'%.2f' % self.tot_balance, '%.2f' % self.tot_coming))
self.tot_balance = Decimal(0)
self.tot_coming = Decimal(0)
self.count = 0
def format_dict(self, item):
self.count += 1
if self.interactive:
backend = item['id'].split('@', 1)[1]
id = '#%d (%s)' % (self.count, backend)
else:
id = item['id']
result = u''
if self.count == 1:
result += ' %s Account Balance Coming \n' % ((' ' * 15) if not self.interactive else '')
result += '------------------------------------------%s+----------+----------\n' % (('-' * 15) if not self.interactive else '')
result += (u' %s%-' + (u'15' if self.interactive else '30') + u's%s %-25s %8s %8s') % \
(self.BOLD, id, self.NC,
item['label'], '%.2f' % item['balance'], '%.2f' % (item['coming'] or Decimal(0.0)))
self.tot_balance += item['balance']
if item['coming']:
self.tot_coming += item['coming']
return result
class Boobank(ReplApplication):
@ -219,6 +181,7 @@ class Boobank(ReplApplication):
account = backend.get_account(id)
return backend.iter_history(account)
self.start_format()
for backend, operation in self.do(do, backends=names):
self.format(operation)
self.flush()
@ -241,6 +204,7 @@ class Boobank(ReplApplication):
account = backend.get_account(id)
return backend.iter_coming(account)
self.start_format(id=id)
for backend, operation in self.do(do, backends=names):
self.format(operation)
self.flush()
@ -273,9 +237,10 @@ class Boobank(ReplApplication):
self.set_formatter('recipient_list')
self.set_formatter_header(u'Available recipients')
names = (backend_name_from,) if backend_name_from is not None else None
self.start_format()
for backend, recipient in self.do('iter_transfer_recipients', id_from, backends=names):
self.format(recipient)
self.add_object(recipient)
self.cached_format(recipient)
self.flush()
return 0
@ -295,6 +260,7 @@ class Boobank(ReplApplication):
names = (backend_name,) if backend_name is not None else None
self.start_format()
for backend, transfer in self.do('transfer', id_from, id_to, amount, reason, backends=names):
self.format(transfer)
self.flush()

View file

@ -22,30 +22,17 @@ import sys
from weboob.capabilities.bill import ICapBill, Detail, Subscription
from weboob.tools.application.repl import ReplApplication
from weboob.tools.application.formatters.iformatter import IFormatter
from weboob.tools.application.formatters.iformatter import PrettyFormatter
__all__ = ['Boobill']
class SubscriptionsFormatter(IFormatter):
class SubscriptionsFormatter(PrettyFormatter):
MANDATORY_FIELDS = ('id', 'label')
count = 0
def flush(self):
self.count = 0
def format_dict(self, item):
self.count += 1
if self.interactive:
backend = item['id'].split('@', 1)[1]
id = '#%d (%s)' % (self.count, backend)
else:
id = item['id']
return u'%s%s%s %s' % (self.BOLD, id, self.NC, item['label'])
def get_title(self, obj):
return obj.label
class Boobill(ReplApplication):
APPNAME = 'boobill'
@ -72,9 +59,9 @@ class Boobill(ReplApplication):
List subscriptions
"""
self.start_format()
for backend, subscription in self.do('iter_subscription'):
self.add_object(subscription)
self.format(subscription)
self.cached_format(subscription)
self.flush()
def do_details(self, id):
@ -90,15 +77,15 @@ class Boobill(ReplApplication):
return 2
names = (backend_name,) if backend_name is not None else None
def do(backend):
return backend.get_details(id)
# XXX: should be generated by backend?
# XXX: should be generated by backend? -Flo
# XXX: no, but you should do it in a specific formatter -romain
mysum = Detail()
mysum.label = "Sum"
mysum.infos = "Generated by boobill"
mysum.price = 0.
for backend, detail in self.do(do, backends=names):
self.start_format()
for backend, detail in self.do('get_details', id, backends=names):
self.format(detail)
mysum.price = detail.price + mysum.price
@ -118,10 +105,8 @@ class Boobill(ReplApplication):
return 2
names = (backend_name,) if backend_name is not None else None
def do(backend):
return backend.iter_history(id)
for backend, history in self.do(do, backends=names):
self.start_format()
for backend, history in self.do('iter_history', id, backends=names):
self.format(history)
self.flush()
@ -129,7 +114,7 @@ class Boobill(ReplApplication):
"""
bills Id
Get the list of bills documents for subscription
Get the list of bills documents for subscription
id is the identifier of the backend
"""
@ -139,10 +124,8 @@ class Boobill(ReplApplication):
return 2
names = (backend_name,) if backend_name is not None else None
def do(backend):
return backend.iter_bills(id)
for backend, date in self.do(do, backends=names):
self.start_format()
for backend, date in self.do('iter_bills', id, backends=names):
self.format(date)
self.flush()
@ -150,7 +133,7 @@ class Boobill(ReplApplication):
"""
download Id [FILENAME]
download the bill
download the bill
id is the identifier of the bill (hint: try bills command)
FILENAME is where to write the file. If FILENAME is '-',
the file is written to stdout.
@ -178,5 +161,3 @@ class Boobill(ReplApplication):
print >>sys.stderr, 'Unable to write bill in "%s": %s' % (dest, e)
return 1
return

View file

@ -35,50 +35,48 @@ __all__ = ['Boobmsg']
class XHtmlFormatter(IFormatter):
def flush(self):
pass
MANDATORY_FIELDS = ('title', 'date', 'sender', 'signature', 'content')
def format_dict(self, item):
def format_obj(self, obj, alias):
result = "<div>\n"
result += "<h1>%s</h1>" % (item['title'])
result += "<h1>%s</h1>" % (obj.title)
result += "<dl>"
result += "<dt>Date</dt><dd>%s</dd>" % (item['date'])
result += "<dt>Sender</dt><dd>%s</dd>" % (item['sender'])
result += "<dt>Signature</dt><dd>%s</dd>" % (item['signature'])
result += "<dt>Date</dt><dd>%s</dd>" % (obj.date)
result += "<dt>Sender</dt><dd>%s</dd>" % (obj.sender)
result += "<dt>Signature</dt><dd>%s</dd>" % (obj.signature)
result += "</dl>"
result += "<div>%s</div>" % (item['content'])
result += "<div>%s</div>" % (obj.content)
result += "</div>\n"
return result
class MessageFormatter(IFormatter):
def flush(self):
pass
MANDATORY_FIELDS = ('title', 'date', 'sender', 'signature', 'content')
def format_dict(self, item):
def format_obj(self, obj, alias):
result = u'%sTitle:%s %s\n' % (self.BOLD,
self.NC, item['title'])
self.NC, obj.title)
result += u'%sDate:%s %s\n' % (self.BOLD,
self.NC, item['date'])
self.NC, obj.date)
result += u'%sFrom:%s %s\n' % (self.BOLD,
self.NC, item['sender'])
if item['receivers']:
self.NC, obj.sender)
if hasattr(obj, 'receivers') and obj.receivers:
result += u'%sTo:%s %s\n' % (self.BOLD,
self.NC,
', '.join(item['receivers']))
', '.join(obj.receivers))
if item['flags'] & Message.IS_HTML:
content = html2text(item['content'])
if obj.flags & Message.IS_HTML:
content = html2text(obj.content)
else:
content = item['content']
content = obj.content
result += '\n%s' % content
if item['signature']:
if item['flags'] & Message.IS_HTML:
signature = html2text(item['signature'])
if obj.signature:
if obj.flags & Message.IS_HTML:
signature = html2text(obj.signature)
else:
signature = item['signature']
signature = obj.signature
result += '\n-- \n%s' % signature
return result
@ -92,36 +90,34 @@ class MessagesListFormatter(IFormatter):
def flush(self):
self.count = 0
def format_dict(self, item):
def format_obj(self, obj, alias):
if not self._list_messages:
return self.format_dict_thread(item)
return self.format_dict_thread(obj, alias)
else:
return self.format_dict_messages(item)
return self.format_dict_messages(obj, alias)
def format_dict_thread(self, item):
def format_dict_thread(self, obj, alias):
self.count += 1
if self.interactive:
backend = item['id'].split('@', 1)[1]
result = u'%s* (%d) %s (%s)%s' % (self.BOLD,
self.count,
item['title'], backend,
self.NC)
self.count,
obj.title, obj.backend,
self.NC)
else:
result = u'%s* (%s) %s%s' % (self.BOLD, item['id'],
item['title'],
self.NC)
if item['date']:
result += u'\n %s' % item['date']
result = u'%s* (%s) %s%s' % (self.BOLD, obj.id,
obj.title,
self.NC)
if obj.date:
result += u'\n %s' % obj.date
return result
def format_dict_messages(self, item):
backend = item['id'].split('@', 1)[1]
if item['flags'] == Thread.IS_THREADS:
def format_dict_messages(self, obj, alias):
if obj.flags == Thread.IS_THREADS:
depth = 0
else:
depth = -1
result = self.format_message(backend, item['root'], depth)
result = self.format_message(obj.backend, obj.root, depth)
return result
def format_message(self, backend, message, depth=0):
@ -187,25 +183,25 @@ class ProfileFormatter(IFormatter):
result += u'\t' * level + u'%-20s %s\n' % (node.label + ':', value)
return result
def format_dict(self, item):
result = u'Nickname: %s\n' % item['name']
if item['status'] & Contact.STATUS_ONLINE:
def format_obj(self, obj):
result = u'Nickname: %s\n' % obj.name
if obj.status & Contact.STATUS_ONLINE:
s = 'online'
elif item['status'] & Contact.STATUS_OFFLINE:
elif obj.status & Contact.STATUS_OFFLINE:
s = 'offline'
elif item['status'] & Contact.STATUS_AWAY:
elif obj.status & Contact.STATUS_AWAY:
s = 'away'
else:
s = 'unknown'
result += u'Status: %s (%s)\n' % (s, item['status_msg'])
result += u'Status: %s (%s)\n' % (s, obj.status_msg)
result += u'Photos:\n'
for name, photo in item['photos'].iteritems():
for name, photo in obj.photos.iteritems():
result += u'\t%s%s\n' % (photo, ' (hidden)' if photo.hidden else '')
result += u'Profile:\n'
for head in item['profile'].itervalues():
for head in obj.profile.itervalues():
result += self.print_node(head)
result += u'Description:\n'
for s in item['summary'].split('\n'):
for s in obj.summary.split('\n'):
result += u'\t%s\n' % s
return result
@ -439,7 +435,7 @@ class Boobmsg(ReplApplication):
def do_photos(self, id):
"""
profile ID
photos ID
Display photos of a profile
"""

View file

@ -19,33 +19,20 @@
from weboob.capabilities.library import ICapBook, Book
from weboob.tools.application.repl import ReplApplication
from weboob.tools.application.formatters.iformatter import IFormatter
from weboob.tools.application.formatters.iformatter import PrettyFormatter
import sys
__all__ = ['Boobooks']
class RentedListFormatter(IFormatter):
class RentedListFormatter(PrettyFormatter):
MANDATORY_FIELDS = ('id', 'date', 'author', 'name', 'late')
RED = ''
count = 0
def flush(self):
self.count = 0
def format_dict(self, item):
self.count += 1
if self.interactive:
backend = item['id'].split('@', 1)[1]
id = '#%d (%s)' % (self.count, backend)
else:
id = item['id']
s = u'%s%s%s %s%s (%s)' % (self.BOLD, id, self.NC, item['author'], item['name'], item['date'])
if item['late']:
def get_title(self, obj):
s = u'%s%s (%s)' % (obj.author, obj.name, obj.date)
if obj.late:
s += u' %sLATE!%s' % (self.RED, self.NC)
return s

View file

@ -23,7 +23,7 @@ import sys
from weboob.capabilities.bugtracker import ICapBugTracker, Query, Update, Project, Issue
from weboob.tools.application.repl import ReplApplication
from weboob.tools.application.formatters.iformatter import IFormatter
from weboob.tools.application.formatters.iformatter import IFormatter, PrettyFormatter
from weboob.tools.misc import html2text
@ -33,28 +33,25 @@ __all__ = ['BoobTracker']
class IssueFormatter(IFormatter):
MANDATORY_FIELDS = ('id', 'project', 'title', 'body', 'author')
def flush(self):
pass
def format_dict(self, item):
result = u'%s%s - #%s - %s%s\n' % (self.BOLD, item['project'].name, item['id'], item['title'], self.NC)
result += '\n%s\n\n' % item['body']
result += 'Author: %s (%s)\n' % (item['author'].name, item['creation'])
if item['status']:
result += 'Status: %s\n' % item['status'].name
if item['version']:
result += 'Version: %s\n' % item['version'].name
if item['category']:
result += 'Category: %s\n' % item['category']
if item['assignee']:
result += 'Assignee: %s\n' % (item['assignee'].name)
if item['attachments']:
def format_obj(self, obj, alias):
result = u'%s%s - #%s - %s%s\n' % (self.BOLD, obj.project.name, obj.fullid, obj.title, self.NC)
result += '\n%s\n\n' % obj.body
result += 'Author: %s (%s)\n' % (obj.author.name, obj.creation)
if hasattr(obj, 'status') and obj.status:
result += 'Status: %s\n' % obj.status.name
if hasattr(obj, 'version') and obj.version:
result += 'Version: %s\n' % obj.version.name
if hasattr(obj, 'category') and obj.category:
result += 'Category: %s\n' % obj.category
if hasattr(obj, 'assignee') and obj.assignee:
result += 'Assignee: %s\n' % (obj.assignee.name)
if hasattr(obj, 'attachments') and obj.attachments:
result += '\nAttachments:\n'
for a in item['attachments']:
for a in obj.attachments:
result += '* %s%s%s <%s>\n' % (self.BOLD, a.filename, self.NC, a.url)
if item['history']:
if hasattr(obj, 'history') and obj.history:
result += '\nHistory:\n'
for u in item['history']:
for u in obj.history:
result += '* %s%s - %s%s\n' % (self.BOLD, u.date, u.author.name, self.NC)
for change in u.changes:
result += ' - %s%s%s: %s -> %s\n' % (self.BOLD, change.field, self.NC, change.last, change.new)
@ -62,20 +59,15 @@ class IssueFormatter(IFormatter):
result += html2text(u.message)
return result
class IssuesListFormatter(IFormatter):
class IssuesListFormatter(PrettyFormatter):
MANDATORY_FIELDS = ('id', 'project', 'status', 'title', 'category')
count = 0
def get_title(self, obj):
return '%s - [%s] %s' % (obj.project.name, obj.status.name, obj.title)
def flush(self):
self.count = 0
pass
def get_description(self, obj):
return obj.category
def format_dict(self, item):
self.count += 1
result = u'%s* (%s) %s - [%s] %s%s\n' % (self.BOLD, item['id'], item['project'].name, item['status'].name, item['title'], self.NC)
result += ' %s' % (item['category'])
return result
class BoobTracker(ReplApplication):
APPNAME = 'boobtracker'

View file

@ -25,7 +25,7 @@ import sys
from weboob.capabilities.pricecomparison import ICapPriceComparison
from weboob.tools.misc import html2text
from weboob.tools.application.repl import ReplApplication
from weboob.tools.application.formatters.iformatter import IFormatter
from weboob.tools.application.formatters.iformatter import IFormatter, PrettyFormatter
__all__ = ['Comparoob']
@ -34,55 +34,46 @@ __all__ = ['Comparoob']
class PriceFormatter(IFormatter):
MANDATORY_FIELDS = ('id', 'cost', 'currency', 'shop', 'product')
def flush(self):
pass
def format_dict(self, item):
if item['message']:
message = item['message']
def format_obj(self, obj, alias):
if hasattr(obj, 'message') and obj.message:
message = obj.message
else:
message = '%s (%s)' % (item['shop'].name, item['shop'].location)
message = u'%s (%s)' % (obj.shop.name, obj.shop.location)
result = u'%s%s%s\n' % (self.BOLD, message, self.NC)
result += 'ID: %s\n' % item['id']
result += 'Product: %s\n' % item['product'].name
result += 'Cost: %s%s\n' % (item['cost'], item['currency'])
if item['date']:
result += 'Date: %s\n' % item['date'].strftime('%Y-%m-%d')
result += u'ID: %s\n' % obj.fullid
result += u'Product: %s\n' % obj.product.name
result += u'Cost: %s%s\n' % (obj.cost, obj.currency)
if hasattr(obj, 'date') and obj.date:
result += u'Date: %s\n' % obj.date.strftime('%Y-%m-%d')
result += '\n%sShop:%s\n' % (self.BOLD, self.NC)
result += '\tName: %s\n' % item['shop'].name
if item['shop'].location:
result += '\tLocation: %s\n' % item['shop'].location
if item['shop'].info:
result += '\n\t' + html2text(item['shop'].info).replace('\n', '\n\t').strip()
result += u'\n%sShop:%s\n' % (self.BOLD, self.NC)
result += u'\tName: %s\n' % obj.shop.name
if obj.shop.location:
result += u'\tLocation: %s\n' % obj.shop.location
if obj.shop.info:
result += u'\n\t' + html2text(obj.shop.info).replace('\n', '\n\t').strip()
return result
class PricesFormatter(IFormatter):
MANDATORY_FIELDS = ('id', 'cost', 'currency', 'shop')
class PricesFormatter(PrettyFormatter):
MANDATORY_FIELDS = ('id', 'cost', 'currency')
count = 0
def flush(self):
self.count = 0
def format_dict(self, item):
self.count += 1
if item['message']:
message = item['message']
def get_title(self, obj):
if hasattr(obj, 'message') and obj.message:
message = obj.message
elif hasattr(obj, 'shop') and obj.shop:
message = '%s (%s)' % (obj.shop.name, obj.shop.location)
else:
message = '%s (%s)' % (item['shop'].name, item['shop'].location)
return u'%s%s' % (obj.cost, obj.currency)
return u'%s%s - %s' % (obj.cost, obj.currency, message)
def get_description(self, obj):
if obj.date:
return obj.date.strftime('%Y-%m-%d')
if self.interactive:
backend = item['id'].split('@', 1)[1]
result = u'%s* (%d) %s%s - %s (%s)%s' % (self.BOLD, self.count, item['cost'], item['currency'], message, backend, self.NC)
else:
result = u'%s* (%s) %s%s - %s%s' % (self.BOLD, item['id'], item['cost'], item['currency'], message, self.NC)
if item['date']:
result += ' %s' % item['date'].strftime('%Y-%m-%d')
return result
class Comparoob(ReplApplication):
APPNAME = 'comparoob'
@ -113,9 +104,10 @@ class Comparoob(ReplApplication):
return 1
self.change_path([u'prices'])
self.start_format()
for backend, price in self.do('iter_prices', product):
self.add_object(price)
self.format(price)
self.cached_format(price)
self.flush()
def complete_info(self, text, line, *ignored):
args = line.split(' ')
@ -131,5 +123,7 @@ class Comparoob(ReplApplication):
if not price:
print >>sys.stderr, 'Price not found: %s' % _id
return 3
self.start_format()
self.format(price)
self.flush()

View file

@ -22,7 +22,7 @@ import sys
from weboob.capabilities.housing import ICapHousing, Query
from weboob.tools.application.repl import ReplApplication
from weboob.tools.application.formatters.iformatter import IFormatter
from weboob.tools.application.formatters.iformatter import IFormatter, PrettyFormatter
__all__ = ['Flatboob']
@ -31,58 +31,47 @@ __all__ = ['Flatboob']
class HousingFormatter(IFormatter):
MANDATORY_FIELDS = ('id', 'title', 'cost', 'currency', 'area', 'date', 'text')
def flush(self):
pass
def format_obj(self, obj, alias):
result = u'%s%s%s\n' % (self.BOLD, obj.title, self.NC)
result += 'ID: %s\n' % obj.fullid
result += 'Cost: %s%s\n' % (obj.cost, obj.currency)
result += u'Area: %s\n' % (obj.area)
if obj.date:
result += 'Date: %s\n' % obj.date.strftime('%Y-%m-%d')
result += 'Phone: %s\n' % obj.phone
if hasattr(obj, 'location') and obj.location:
result += 'Location: %s\n' % obj.location
if hasattr(obj, 'station') and obj.station:
result += 'Station: %s\n' % obj.station
def format_dict(self, item):
result = u'%s%s%s\n' % (self.BOLD, item['title'], self.NC)
result += 'ID: %s\n' % item['id']
result += 'Cost: %s%s\n' % (item['cost'], item['currency'])
result += u'Area: %s\n' % (item['area'])
if item['date']:
result += 'Date: %s\n' % item['date'].strftime('%Y-%m-%d')
result += 'Phone: %s\n' % item['phone']
if item['location']:
result += 'Location: %s\n' % item['location']
if item['station']:
result += 'Station: %s\n' % item['station']
if item['photos']:
if hasattr(obj, 'photos') and obj.photos:
result += '\n%sPhotos%s\n' % (self.BOLD, self.NC)
for photo in item['photos']:
for photo in obj.photos:
result += ' * %s\n' % photo.url
result += '\n%sDescription%s\n' % (self.BOLD, self.NC)
result += item['text']
result += obj.text
if item['details']:
if hasattr(obj, 'details') and obj.details:
result += '\n\n%sDetails%s\n' % (self.BOLD, self.NC)
for key, value in item['details'].iteritems():
for key, value in obj.details.iteritems():
result += ' %s: %s\n' % (key, value)
return result
class HousingListFormatter(IFormatter):
class HousingListFormatter(PrettyFormatter):
MANDATORY_FIELDS = ('id', 'title', 'cost', 'text')
count = 0
def get_title(self, obj):
return '%s%s - %s' % (obj.cost, obj.currency, obj.title)
def flush(self):
self.count = 0
pass
def format_dict(self, item):
self.count += 1
if self.interactive:
backend = item['id'].split('@', 1)[1]
result = u'%s* (%d) %s%s - %s (%s)%s\n' % (self.BOLD, self.count, item['cost'], item['currency'], item['title'], backend, self.NC)
else:
result = u'%s* (%s) %s%s - %s%s\n' % (self.BOLD, item['id'], item['cost'], item['currency'], item['title'], self.NC)
result += ' '
if item['date']:
result += '%s - ' % item['date'].strftime('%Y-%m-%d')
result += item['text']
def get_description(self, obj):
result = u''
if hasattr(obj, 'date') and obj.date:
result += '%s - ' % obj.date.strftime('%Y-%m-%d')
result += obj.text
return result
class Flatboob(ReplApplication):
APPNAME = 'flatboob'
VERSION = '0.c'
@ -148,9 +137,9 @@ class Flatboob(ReplApplication):
query.nb_rooms = self.ask_int('Enter number of rooms')
self.change_path([u'housings'])
self.start_format()
for backend, housing in self.do('search_housings', query):
self.add_object(housing)
self.format(housing)
self.cached_format(housing)
self.flush()
def ask_int(self, txt):
@ -173,5 +162,7 @@ class Flatboob(ReplApplication):
if not housing:
print >>sys.stderr, 'Housing not found: %s' % _id
return 3
self.start_format()
self.format(housing)
self.flush()

View file

@ -24,33 +24,26 @@ import os
from re import search, sub
from weboob.tools.application.repl import ReplApplication
from weboob.capabilities.base import NotLoaded
from weboob.capabilities.base import empty
from weboob.capabilities.gallery import ICapGallery, BaseGallery, BaseImage
from weboob.tools.application.formatters.iformatter import IFormatter
from weboob.tools.application.formatters.iformatter import PrettyFormatter
__all__ = ['Galleroob']
class GalleryListFormatter(IFormatter):
class GalleryListFormatter(PrettyFormatter):
MANDATORY_FIELDS = ('id', 'title')
count = 0
def get_title(self, obj):
s = obj.title
if hasattr(obj, 'cardinality') and not empty(obj.cardinality):
s += u' (%d pages)' % obj.cardinality
return s
def flush(self):
self.count = 0
def format_dict(self, item):
result = u'%s* (%s) %s%s' % (
ReplApplication.BOLD,
item['id'],
item['title'],
ReplApplication.NC)
if item['cardinality'] is not NotLoaded:
result += u' (%d pages)' % item['cardinality']
if item['description'] is not NotLoaded:
result += u'\n %-70s' % item['description']
return result
def get_description(self, obj):
if hasattr(obj, 'description') and obj.description:
return obj.description
class Galleroob(ReplApplication):
@ -76,11 +69,11 @@ class Galleroob(ReplApplication):
print >>sys.stderr, 'This command takes an argument: %s' % self.get_command_help('search', short=True)
return 2
self.set_formatter_header(u'Search pattern: %s' % pattern)
for backend, gallery in self.do('search_gallery',
pattern=pattern, max_results=self.options.count):
self.add_object(gallery)
self.format(gallery)
self.start_format(pattern=pattern)
for backend, gallery in self.do('search_gallery', pattern=pattern,
max_results=self.options.count):
self.cached_format(gallery)
self.flush()
def do_download(self, line):
"""
@ -159,5 +152,7 @@ class Galleroob(ReplApplication):
if not gallery:
print >>sys.stderr, 'Gallery not found: %s' % _id
return 3
self.start_format()
self.format(gallery)
self.flush()

View file

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
# Copyright(C) 2010-2011 Romain Bignon
# Copyright(C) 2010-2012 Romain Bignon
#
# This file is part of weboob.
#
@ -21,44 +21,36 @@
import sys
from weboob.capabilities.radio import ICapRadio, Radio
from weboob.capabilities.base import NotLoaded
from weboob.capabilities.base import empty
from weboob.tools.application.repl import ReplApplication
from weboob.tools.application.media_player import InvalidMediaPlayer, MediaPlayer, MediaPlayerNotFound
from weboob.tools.application.formatters.iformatter import IFormatter
from weboob.tools.application.formatters.iformatter import PrettyFormatter
__all__ = ['Radioob']
class RadioListFormatter(IFormatter):
class RadioListFormatter(PrettyFormatter):
MANDATORY_FIELDS = ('id', 'title', 'description')
count = 0
def flush(self):
self.count = 0
pass
def get_title(self, obj):
return obj.title
def format_dict(self, item):
self.count += 1
if self.interactive:
backend = item['id'].split('@', 1)[1]
result = u'%s* (%d) %s (%s)%s\n' % (ReplApplication.BOLD, self.count, item['title'], backend, ReplApplication.NC)
else:
result = u'%s* (%s) %s%s\n' % (ReplApplication.BOLD, item['id'], item['title'], ReplApplication.NC)
result += ' %-30s' % item['description']
if item['current'] is not NotLoaded:
if item['current'].artist:
result += ' (Current: %s - %s)' % (item['current'].artist, item['current'].title)
def get_description(self, obj):
result = '%-30s' % obj.description
if hasattr(obj, 'current') and not empty(obj.current):
if obj.current.artist:
result += ' (Current: %s - %s)' % (obj.current.artist, obj.current.title)
else:
result += ' (Current: %s)' % item['current'].title
result += ' (Current: %s)' % obj.current.title
return result
class Radioob(ReplApplication):
APPNAME = 'radioob'
VERSION = '0.c'
COPYRIGHT = 'Copyright(C) 2010-2011 Romain Bignon'
COPYRIGHT = 'Copyright(C) 2010-2012 Romain Bignon'
DESCRIPTION = 'Console application allowing to search for web radio stations, listen to them and get information ' \
'like the current song.'
CAPS = ICapRadio

View file

@ -29,23 +29,18 @@ __all__ = ['Translaboob']
class TranslationFormatter(IFormatter):
MANDATORY_FIELDS = ('id', 'text')
def flush(self):
pass
def format_dict(self, item):
backend = item['id'].split('@', 1)[1]
result = u'%s* %s%s\n\t%s' % (self.BOLD, backend, self.NC, item['text'].replace('\n', '\n\t'))
return result
def format_obj(self, obj, alias):
return u'%s* %s%s\n\t%s' % (self.BOLD, obj.backend, self.NC, obj.text.replace('\n', '\n\t'))
class XmlTranslationFormatter(IFormatter):
MANDATORY_FIELDS = ('id', 'lang_src', 'lang_dst', 'text')
MANDATORY_FIELDS = ('id', 'text')
def flush(self):
pass
def start_format(self, **kwargs):
if 'source' in kwargs:
self.output('<source>\n%s\n</source>' % kwargs['source'])
def format_dict(self, item):
backend = item['id'].split('@', 1)[1]
return u'<translation %s>\n%s\n</translation>' % (backend, item['text'])
def format_obj(self, obj, alias):
return u'<translation %s>\n%s\n</translation>' % (obj.backend, obj.text)
class Translaboob(ReplApplication):
APPNAME = 'translaboob'
@ -74,5 +69,7 @@ class Translaboob(ReplApplication):
if not text or text == '-':
text = self.acquire_input()
self.start_format(source=text)
for backend, translation in self.do('translate', lan_from, lan_to, text):
self.format(translation)
self.flush()

View file

@ -27,35 +27,25 @@ from weboob.capabilities.video import ICapVideo, BaseVideo
from weboob.capabilities.base import empty
from weboob.tools.application.repl import ReplApplication
from weboob.tools.application.media_player import InvalidMediaPlayer, MediaPlayer, MediaPlayerNotFound
from weboob.tools.application.formatters.iformatter import IFormatter
from weboob.tools.application.formatters.iformatter import PrettyFormatter
__all__ = ['Videoob']
class VideoListFormatter(IFormatter):
class VideoListFormatter(PrettyFormatter):
MANDATORY_FIELDS = ('id', 'title', 'duration', 'date')
count = 0
def get_title(self, obj):
return obj.title
def flush(self):
self.count = 0
pass
def format_dict(self, item):
self.count += 1
if self.interactive:
backend = item['id'].split('@', 1)[1]
result = u'%s* (%d) %s (%s)%s\n' % (self.BOLD, self.count, item['title'], backend, self.NC)
else:
result = u'%s* (%s) %s%s\n' % (self.BOLD, item['id'], item['title'], self.NC)
result += ' %s' % (item['duration'] if item['duration'] else item['date'])
if not empty(item['author']):
result += ' - %s' % item['author']
if not empty(item['rating']):
result += u' (%s/%s)' % (item['rating'], item['rating_max'])
def get_description(self, obj):
result = '%s' % (obj.duration or obj.date)
if hasattr(obj, 'author') and not empty(obj.author):
result += u' - %s' % obj.author
if hasattr(obj, 'rating') and not empty(obj.rating):
result += u' (%s/%s)' % (obj.rating, obj.rating_max)
return result
class Videoob(ReplApplication):
APPNAME = 'videoob'
VERSION = '0.c'
@ -180,6 +170,8 @@ class Videoob(ReplApplication):
if not video:
print >>sys.stderr, 'Video not found: %s' % _id
return 3
self.start_format()
self.format(video)
self.flush()
@ -216,10 +208,9 @@ class Videoob(ReplApplication):
print >>sys.stderr, 'This command takes an argument: %s' % self.get_command_help('search', short=True)
return 2
self.set_formatter_header(u'Search pattern: %s' % pattern)
self.change_path([u'search'])
self.start_format(pattern=pattern)
for backend, video in self.do('search_videos', pattern=pattern, nsfw=self.nsfw,
max_results=self.options.count):
self.add_object(video)
self.format(video)
self.cached_format(video)
self.flush()

View file

@ -133,5 +133,8 @@ class WebContentEdit(ReplApplication):
backend_names = (backend_name,) if backend_name is not None else self.enabled_backends
_id = _id.encode('utf-8')
self.start_format()
for backend, revision in self.do('iter_revisions', _id, max_results=self.options.count, backends=backend_names):
self.format(revision)
self.flush()

View file

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
# Copyright(C) 2010-2011 Romain Bignon
# Copyright(C) 2010-2012 Romain Bignon
#
# This file is part of weboob.
#
@ -23,7 +23,7 @@ import sys
from weboob.capabilities.torrent import ICapTorrent, MagnetOnly
from weboob.tools.application.repl import ReplApplication
from weboob.tools.application.formatters.iformatter import IFormatter
from weboob.tools.application.formatters.iformatter import IFormatter, PrettyFormatter
from weboob.core import CallErrors
@ -40,52 +40,39 @@ def sizeof_fmt(num):
class TorrentInfoFormatter(IFormatter):
MANDATORY_FIELDS = ('id', 'name', 'size', 'seeders', 'leechers', 'url', 'files', 'description')
def flush(self):
pass
def format_dict(self, item):
result = u'%s%s%s\n' % (self.BOLD, item['name'], self.NC)
result += 'ID: %s\n' % item['id']
result += 'Size: %s\n' % sizeof_fmt(item['size'])
result += 'Seeders: %s\n' % item['seeders']
result += 'Leechers: %s\n' % item['leechers']
result += 'URL: %s\n' % item['url']
if item['magnet']:
result += 'Magnet URL: %s\n' % item['magnet']
if item['files']:
def format_obj(self, obj, alias):
result = u'%s%s%s\n' % (self.BOLD, obj.name, self.NC)
result += 'ID: %s\n' % obj.fullid
result += 'Size: %s\n' % sizeof_fmt(obj.size)
result += 'Seeders: %s\n' % obj.seeders
result += 'Leechers: %s\n' % obj.leechers
result += 'URL: %s\n' % obj.url
if hasattr(obj, 'magnet') and obj.magnet:
result += 'Magnet URL: %s\n' % obj.magnet
if obj.files:
result += '\n%sFiles%s\n' % (self.BOLD, self.NC)
for f in item['files']:
for f in obj.files:
result += ' * %s\n' % f
result += '\n%sDescription%s\n' % (self.BOLD, self.NC)
result += item['description']
result += obj.description
return result
class TorrentListFormatter(IFormatter):
class TorrentListFormatter(PrettyFormatter):
MANDATORY_FIELDS = ('id', 'name', 'size', 'seeders', 'leechers')
count = 0
def get_title(self, obj):
return obj.name
def flush(self):
self.count = 0
pass
def format_dict(self, item):
self.count += 1
if self.interactive:
backend = item['id'].split('@', 1)[1]
result = u'%s* (%d) %s (%s)%s\n' % (self.BOLD, self.count, item['name'], backend, self.NC)
else:
result = u'%s* (%s) %s%s\n' % (self.BOLD, item['id'], item['name'], self.NC)
size = sizeof_fmt(item['size'])
result += ' %10s (Seed: %2d / Leech: %2d)' % (size, item['seeders'], item['leechers'])
return result
def get_description(self, obj):
size = sizeof_fmt(obj.size)
return '%10s (Seed: %2d / Leech: %2d)' % (size, obj.seeders, obj.leechers)
class Weboorrents(ReplApplication):
APPNAME = 'weboorrents'
VERSION = '0.c'
COPYRIGHT = 'Copyright(C) 2010-2011 Romain Bignon'
COPYRIGHT = 'Copyright(C) 2010-2012 Romain Bignon'
DESCRIPTION = 'Console application allowing to search for torrents on various trackers ' \
'and download .torrent files.'
CAPS = ICapTorrent
@ -107,19 +94,15 @@ class Weboorrents(ReplApplication):
Get information about a torrent.
"""
_id, backend_name = self.parse_id(id)
found = 0
for backend, torrent in self.do('get_torrent', _id, backends=backend_name):
if torrent:
self.format(torrent)
found = 1
if not found:
print >>sys.stderr, 'Torrent "%s" not found' % id
torrent = self.get_object(id, 'get_torrent')
if not torrent:
print >>sys.stderr, 'Torrent not found: %s' % id
return 3
else:
self.flush()
self.start_format()
self.format(torrent)
self.flush()
def complete_getfile(self, text, line, *ignored):
args = line.split(' ', 2)
@ -178,8 +161,8 @@ class Weboorrents(ReplApplication):
self.change_path([u'search'])
if not pattern:
pattern = None
self.set_formatter_header(u'Search pattern: %s' % pattern if pattern else u'Latest torrents')
self.start_format(pattern=pattern)
for backend, torrent in self.do('iter_torrents', pattern=pattern):
self.add_object(torrent)
self.format(torrent)
self.cached_format(torrent)
self.flush()

View file

@ -17,62 +17,43 @@
# You should have received a copy of the GNU Affero General Public License
# along with weboob. If not, see <http://www.gnu.org/licenses/>.
from datetime import datetime
from weboob.capabilities.weather import ICapWeather
from weboob.capabilities.gauge import ICapWaterLevel
from weboob.tools.application.repl import ReplApplication
from weboob.tools.application.formatters.iformatter import IFormatter
from weboob.tools.application.formatters.iformatter import IFormatter, PrettyFormatter
__all__ = ['WetBoobs']
class ForecastsFormatter(IFormatter):
MANDATORY_FIELDS = ('id', 'date', 'low', 'high', 'unit')
def flush(self):
pass
def format_dict(self, item):
result = u'%s* %-15s%s (%s°%s - %s°%s)' % (self.BOLD, '%s:' % item['date'], self.NC, item['low'], item['unit'], item['high'], item['unit'])
if 'text' in item and item['text']:
result += ' %s' % item['text']
def format_obj(self, obj, alias):
result = u'%s* %-15s%s (%s°%s - %s°%s)' % (self.BOLD, '%s:' % obj.date, self.NC, obj.low, obj.unit, obj.high, obj.unit)
if hasattr(obj, 'text') and obj.text:
result += ' %s' % obj.text
return result
class CurrentFormatter(IFormatter):
MANDATORY_FIELDS = ('id', 'date', 'temp')
def flush(self):
pass
def format_dict(self, item):
if isinstance(item['date'], datetime):
date = item['date'].strftime('%y-%m-%d %H:%M:%S')
else:
date = item['date']
result = u'%s%s%s: %s' % (self.BOLD, date, self.NC, item['temp'])
if 'unit' in item and item['unit']:
result += u'°%s' % item['unit']
if 'text' in item and item['text']:
result += u' - %s' % item['text']
def format_obj(self, obj, alias):
result = u'%s%s%s: %s' % (self.BOLD, obj.date, self.NC, obj.temp)
if hasattr(obj, 'unit') and obj.unit:
result += u'°%s' % obj.unit
if hasattr(obj, 'text') and obj.text:
result += u' - %s' % obj.text
return result
class CitiesFormatter(IFormatter):
class CitiesFormatter(PrettyFormatter):
MANDATORY_FIELDS = ('id', 'name')
count = 0
def flush(self):
self.count = 0
def get_title(self, obj):
return obj.name
def format_dict(self, item):
self.count += 1
if self.interactive:
backend = item['id'].split('@', 1)[1]
result = u'%s* (%d) %s (%s)%s' % (self.BOLD, self.count, item['name'], backend, self.NC)
else:
result = u'%s* (%s) %s%s' % (self.BOLD, item['id'], item['name'], self.NC)
return result
class WetBoobs(ReplApplication):
APPNAME = 'wetboobs'
@ -97,9 +78,9 @@ class WetBoobs(ReplApplication):
Search cities.
"""
self.change_path(['cities'])
self.start_format()
for backend, city in self.do('iter_city_search', pattern, caps=ICapWeather):
self.add_object(city)
self.format(city)
self.cached_format(city)
self.flush()
def complete_current(self, text, line, *ignored):
@ -115,6 +96,8 @@ class WetBoobs(ReplApplication):
"""
city, = self.parse_command_args(line, 1, 1)
_id, backend_name = self.parse_id(city)
self.start_format()
for backend, current in self.do('get_current', _id, backends=backend_name, caps=ICapWeather):
if current:
self.format(current)
@ -133,6 +116,8 @@ class WetBoobs(ReplApplication):
"""
city, = self.parse_command_args(line, 1, 1)
_id, backend_name = self.parse_id(city)
self.start_format()
for backend, forecast in self.do('iter_forecast', _id, backends=backend_name, caps=ICapWeather):
self.format(forecast)
self.flush()
@ -144,9 +129,9 @@ class WetBoobs(ReplApplication):
List all rivers. If PATTERN is specified, search on a pattern.
"""
self.change_path([u'gauges'])
self.start_format()
for backend, gauge in self.do('iter_gauges', pattern or None, caps=ICapWaterLevel):
self.add_object(gauge)
self.format(gauge)
self.cached_format(gauge)
self.flush()
def complete_gauge(self, text, line, *ignored):
@ -162,6 +147,8 @@ class WetBoobs(ReplApplication):
"""
gauge, = self.parse_command_args(line, 1, 1)
_id, backend_name = self.parse_id(gauge)
self.start_format()
for backend, measure in self.do('iter_gauge_history', _id, backends=backend_name, caps=ICapWaterLevel):
self.format(measure)
self.flush()
@ -179,6 +166,8 @@ class WetBoobs(ReplApplication):
"""
gauge, = self.parse_command_args(line, 1, 1)
_id, backend_name = self.parse_id(gauge)
self.start_format()
for backend, measure in self.do('get_last_measure', _id, backends=backend_name, caps=ICapWaterLevel):
self.format(measure)
self.flush()

View file

@ -230,7 +230,7 @@ class BaseApplication(object):
return version
def _do_complete_obj(self, backend, fields, obj):
if fields:
if fields is None or len(fields) > 0:
try:
backend.fillobj(obj, fields)
except ObjectNotAvailable, e:

View file

@ -28,15 +28,18 @@ class CSVFormatter(IFormatter):
def __init__(self, field_separator=u';'):
IFormatter.__init__(self)
self.field_separator = field_separator
self.count = 0
self.started = False
def flush(self):
pass
self.started = False
def format_obj(self, obj, alias):
item = self.to_dict(obj)
def format_dict(self, item):
result = u''
if self.count == 0:
if not self.started:
result += self.field_separator.join(item.iterkeys()) + '\n'
self.count += 1
self.started = True
result += self.field_separator.join(unicode(v) for v in item.itervalues())
return result

View file

@ -47,7 +47,7 @@ else:
finally:
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
from weboob.capabilities.base import CapBaseObject, FieldNotFound
from weboob.capabilities.base import CapBaseObject
from weboob.tools.ordereddict import OrderedDict
from weboob.tools.application.console import ConsoleApplication
@ -78,10 +78,9 @@ class IFormatter(object):
BOLD = property(get_bold)
NC = property(get_nc)
def __init__(self, display_keys=True, display_header=True, return_only=False, outfile=sys.stdout):
def __init__(self, display_keys=True, display_header=True, outfile=sys.stdout):
self.display_keys = display_keys
self.display_header = display_header
self.return_only = return_only
self.interactive = False
self.print_lines = 0
self.termrows = 0
@ -94,7 +93,7 @@ class IFormatter(object):
else:
self.termrows = int(subprocess.Popen('stty size', shell=True, stdout=subprocess.PIPE).communicate()[0].split()[0])
def after_format(self, formatted):
def output(self, formatted):
if self.outfile != sys.stdout:
with open(self.outfile, "a+") as outfile:
outfile.write(formatted.encode('utf-8'))
@ -113,47 +112,45 @@ class IFormatter(object):
print line
self.print_lines += 1
def build_id(self, v, backend_name):
return u'%s@%s' % (unicode(v), backend_name)
def start_format(self, **kwargs):
pass
def flush(self):
raise NotImplementedError()
pass
def format(self, obj, selected_fields=None):
def format(self, obj, selected_fields=None, alias=None):
"""
Format an object to be human-readable.
An object has fields which can be selected.
If the object provides an iter_fields() method, the formatter will
call it. It can be used to specify the fields order.
@param obj [object] object to format
@param selected_fields [tuple] fields to display. If None, all fields are selected
@return a string of the formatted object
:param obj: object to format
:type obj: CapBaseObject
:param selected_fields: fields to display. If None, all fields are selected
:type selected_fields: tuple
:param alias: an alias to use instead of the object's ID
:type alias: unicode
"""
assert isinstance(obj, (dict, CapBaseObject, tuple)), 'Object is unexpected type "%r"' % obj
assert isinstance(obj, CapBaseObject), 'Object is unexpected type "%r"' % obj
if isinstance(obj, dict):
item = obj
elif isinstance(obj, tuple):
item = OrderedDict([(k, v) for k, v in obj])
else:
item = self.to_dict(obj, selected_fields)
if item is None:
return None
if selected_fields is not None and not '*' in selected_fields:
obj = obj.copy()
for name, value in obj.iter_fields():
if not name in selected_fields:
delattr(obj, name)
if self.MANDATORY_FIELDS:
missing_fields = set(self.MANDATORY_FIELDS) - set(item.keys())
missing_fields = set(self.MANDATORY_FIELDS) - set([name for name, value in obj.iter_fields()])
if missing_fields:
raise MandatoryFieldsNotFound(missing_fields)
formatted = self.format_dict(item=item)
formatted = self.format_obj(obj, alias)
if formatted:
self.after_format(formatted)
self.output(formatted)
return formatted
def format_dict(self, item):
def format_obj(self, obj, alias=None):
"""
Format an object to be human-readable.
Format a dict to be human-readable. The dict is already simplified
if user provides selected fields.
Called by format().
@ -164,31 +161,37 @@ class IFormatter(object):
"""
raise NotImplementedError()
def set_header(self, string):
if self.display_header:
print string.encode('utf-8')
def to_dict(self, obj, selected_fields=None):
def iter_select(d):
if selected_fields is None or '*' in selected_fields:
fields = d.iterkeys()
else:
fields = selected_fields
for key in fields:
try:
value = d[key]
except KeyError:
raise FieldNotFound(obj, key)
yield key, value
def to_dict(self, obj):
def iter_decorate(d):
for key, value in d:
if key == 'id' and obj.backend is not None:
value = self.build_id(value, obj.backend)
value = obj.fullid
yield key, value
fields_iterator = obj.iter_fields()
d = OrderedDict(iter_decorate(fields_iterator))
return OrderedDict((k, v) for k, v in iter_select(d))
return OrderedDict(iter_decorate(fields_iterator))
class PrettyFormatter(IFormatter):
def format_obj(self, obj, alias):
title = self.get_title(obj)
desc = self.get_description(obj)
if desc is None:
title = '%s%s%s' % (self.NC, title, self.BOLD)
if alias is not None:
result = u'%s* (%s) %s (%s)%s' % (self.BOLD, alias, title, obj.backend, self.NC)
else:
result = u'%s* (%s) %s%s' % (self.BOLD, obj.fullid, title, self.NC)
if desc is not None:
result += u'\n\t%s' % desc
return result
def get_title(self, obj):
raise NotImplementedError()
def get_description(self, obj):
return None

View file

@ -34,14 +34,12 @@ class MultilineFormatter(IFormatter):
def flush(self):
pass
def format_dict(self, item):
def format_obj(self, obj, alias):
item = self.to_dict(obj)
result = u'\n'.join(u'%s%s' % (
(u'%s%s' % (k, self.key_value_separator) if self.display_keys else ''), v)
for k, v in item.iteritems() if (v is not NotLoaded and v is not NotAvailable))
if len(item) > 1:
result += self.after_item
return result
def set_header(self, string):
if self.display_header:
print string.encode('utf-8')

View file

@ -30,10 +30,8 @@ class SimpleFormatter(IFormatter):
self.field_separator = field_separator
self.key_value_separator = key_value_separator
def flush(self):
pass
def format_dict(self, item):
def format_obj(self, obj, alias):
item = self.to_dict(obj)
return self.field_separator.join(u'%s%s' % (
(u'%s%s' % (k, self.key_value_separator) if self.display_keys else ''), v)
for k, v in item.iteritems())

View file

@ -31,18 +31,18 @@ __all__ = ['TableFormatter', 'HTMLTableFormatter']
class TableFormatter(IFormatter):
HTML = False
def __init__(self, display_keys=True, return_only=False):
IFormatter.__init__(self, display_keys=display_keys, return_only=return_only)
def __init__(self):
IFormatter.__init__(self)
self.queue = []
self.keys = None
self.header = None
def after_format(self, formatted):
if self.keys is None:
self.keys = formatted.keys()
self.queue.append(formatted.values())
def flush(self):
s = self.get_formatted_table()
if s is not None:
print s.encode('utf-8')
def get_formatted_table(self):
if len(self.queue) == 0:
return
@ -80,14 +80,14 @@ class TableFormatter(IFormatter):
self.queue = []
if self.return_only:
return s
else:
print s.encode('utf-8')
return s
def format_dict(self, item):
# format is done in self.flush() by prettytable
return item
def format_obj(self, obj, alias):
item = self.to_dict(obj)
if self.keys is None:
self.keys = item.keys()
self.queue.append(item.values())
def set_header(self, string):
self.header = string

View file

@ -43,11 +43,8 @@ class WebBrowser(gtk.Window):
class WebkitGtkFormatter(HTMLTableFormatter):
def __init__(self):
HTMLTableFormatter.__init__(self, return_only=True)
def flush(self):
table_string = HTMLTableFormatter.flush(self)
table_string = self.get_formatted_table()
js_filepaths = []
js_filepaths.append(get_javascript('jquery'))
js_filepaths.append(get_javascript('tablesorter'))

View file

@ -264,9 +264,9 @@ class ReplApplication(Cmd, ConsoleApplication):
kwargs['backends'] = self.enabled_backends if backends is None else backends
kwargs['condition'] = self.condition
fields = self.selected_fields
if fields == '$direct':
if '$direct' in fields:
fields = []
elif fields == '$full':
elif '$full' in fields:
fields = None
return self.weboob.do(self._do_complete, self.options.count, fields, function, *args, **kwargs)
@ -405,7 +405,7 @@ class ReplApplication(Cmd, ConsoleApplication):
if self.options.select:
self.selected_fields = self.options.select.split(',')
else:
self.selected_fields = '$direct'
self.selected_fields = ['$direct']
if self.options.condition:
self.condition = ResultsCondition(self.options.condition)
@ -800,15 +800,9 @@ class ReplApplication(Cmd, ConsoleApplication):
line = line.strip()
if line:
split = line.split()
if len(split) == 1 and split[0] in ('$direct', '$full'):
self.selected_fields = split[0]
else:
self.selected_fields = split
self.selected_fields = split
else:
if isinstance(self.selected_fields, basestring):
print self.selected_fields
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))
@ -864,11 +858,12 @@ class ReplApplication(Cmd, ConsoleApplication):
# We have an argument, let's ch to the directory before the ls
self.working_path.cd1(path)
self.objects, collections = self._fetch_objects(objs=self.COLLECTION_OBJECTS)
objects, collections = self._fetch_objects(objs=self.COLLECTION_OBJECTS)
for obj in self.objects:
self.start_format()
for obj in objects:
if isinstance(obj, CapBaseObject):
self.format(obj)
self.cached_format(obj)
else:
print obj
@ -1012,14 +1007,24 @@ class ReplApplication(Cmd, ConsoleApplication):
return name
def set_formatter_header(self, string):
self.formatter.set_header(string)
pass
def format(self, result):
def start_format(self, **kwargs):
self.formatter.start_format(**kwargs)
def cached_format(self, obj):
self.add_object(obj)
alias = None
if self.interactive:
alias = '%s' % len(self.objects)
self.format(obj, alias=alias)
def format(self, result, alias=None):
fields = self.selected_fields
if fields in ('$direct', '$full'):
if '$direct' in fields or '$full' in fields:
fields = None
try:
self.formatter.format(obj=result, selected_fields=fields)
self.formatter.format(obj=result, selected_fields=fields, alias=alias)
except FieldNotFound, e:
print >>sys.stderr, e
except MandatoryFieldsNotFound, e: