bnporc.py 5.74 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
#!/usr/bin/env python2.5
# -*- coding: utf-8 -*-

"""
Copyright(C) 2009  Romain Bignon

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, version 3 of the License.

This program 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 General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

"""

from __future__ import with_statement

import sys, tty, termios
import os
from types import MethodType
from optparse import OptionParser
from ConfigParser import SafeConfigParser, NoSectionError

from bnporc.browser import BNPorc
31
from bnporc.error import LoginError, AccountNotFound
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51

class Application:

    CONFIG_FILE = '%s/.bnporc' % os.path.expanduser("~")

    def __init__(self):
        self.bnp = BNPorc()

    def getparser(self):

        config = SafeConfigParser()

        login = ''
        try:
            config.read(self.CONFIG_FILE)
            login = config.get('auth', 'login')
        except (NoSectionError, ValueError), e:
            pass

        parser = OptionParser(usage="%prog [options] <command> [args ...]")
52 53
        parser.add_option('-l', '--login', help="account ID", type="str", default=login)
        parser.add_option('-p', '--password', help="account password", type="str")
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
        return parser

    def prompt_password(self, prompt):
        sys.stdout.write(prompt)

        attr = termios.tcgetattr(sys.stdin)
        tty.setcbreak(sys.stdin)

        line = sys.stdin.readline().split('\n')[0]

        termios.tcsetattr(sys.stdin, termios.TCSAFLUSH, attr)
        sys.stdout.write('\n')

        return line

    def main(self, argv):
        parser = self.getparser()
        options, arguments = parser.parse_args()
        if not options.login or not arguments:
            parser.print_help()
            sys.exit(1)

76
        self.options = options
77

78
        return self.command(arguments[0], *arguments[1:])
79

80
    def login(func):
81
        def inc(self, *args, **kwargs):
82 83
            if not self.options.password:
                self.options.password = self.prompt_password('Password: ')
84

85 86 87
            if not self.options.password.isdigit():
                print >>sys.stderr, 'Error: please enter a numeric password'
                return 1
88

89 90 91 92 93 94 95 96 97 98 99
            config = SafeConfigParser()
            config.add_section('auth')
            config.set('auth', 'login', self.options.login)
            with open(self.CONFIG_FILE, 'wb') as configfile:
                config.write(configfile)

            try:
                self.bnp.login(self.options.login, self.options.password)
            except LoginError, err:
                print >>sys.stderr, 'Error: %s' % err
                return 1
100
            return func(self, *args, **kwargs)
101 102

        return inc
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118

    def getMethods(self, prefix):
        services = {}
        for attrname in dir(self):
            if not attrname.startswith(prefix):
                continue
            attr = getattr(self, attrname)
            if not isinstance(attr, MethodType):
                continue
            name = attrname[len(prefix):]
            services[name] = attr
        return services

    def command(self, command, *args):
        commands = self.getMethods('command_')
        if not command in commands:
119
            print >>sys.stderr, "No such command: %s" % command
120 121
            self.command_help()
            return 1
122
        try:
123
            return commands[command](*args)
124 125
        except TypeError, e:
            try:
126
                print >>sys.stderr, "Command %s takes %s arguments" % (command, int(str(e).split(' ')[3]) - 1)
127
            except:
128 129
                print >>sys.stderr, '%s' % e
            return 1
130

131 132 133 134
    def command_help(self):
        print 'Available commands are:'
        print '      list            List every available accounts'
        print '      coming <ID>     Display all future operations'
Romain Bignon's avatar
Romain Bignon committed
135
        print 'BNPorc v0.1 is a free software. Copyright(C) 2009 Romain Bignon'
136 137

    @login
138
    def command_list(self):
139
        accounts = self.bnp.get_accounts_list()
140

141 142
        print '               ID   Account                    Balance        Coming  '
        print '+-----------------+---------------------+--------------+-------------+'
143

144
        for account in accounts:
145 146 147 148
            print '%17s   %-20s   %11.2f   %11.2f' % (account.id,
                                                        account.label,
                                                        account.balance,
                                                        account.coming)
149 150 151

        return 0

152
    @login
153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
    def command_coming(self, id):
        try:
            account = self.bnp.get_account(int(id))
        except AccountNotFound:
            print >>sys.stderr, "Error: account %s not found" % id
            return 1
        except ValueError:
            print >>sys.stderr, "Error: account ID might be an integer"
            return 1

        operations = self.bnp.get_coming_operations(account)
        print '      Date   Label                                                     Amount  '
        print '+----------+----------------------------------------------------+-------------+'

        for operation in operations:
            print '  %8s   %-50s   %11.2f' % (operation.date,
                                              operation.label,
                                              operation.amount)
171
        return 0
172

173 174 175 176 177
if __name__ == '__main__':
    app = Application()
    sys.exit(app.main(sys.argv))