Skip to content

Commit a358c55

Browse files
committed
[REF] refactor code, now the row is a simple object that can be accessible with a dict (this is needed for the next step "merging 05 row in 04" fix regex missing \n at the end of line, add type G_ALL as label can have a various character
1 parent 0f74743 commit a358c55

File tree

3 files changed

+52
-92
lines changed

3 files changed

+52
-92
lines changed

cfonb/parser/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
# cfonb shortcuts
22
from cfonb.parser.common import Row, ParsingError,\
3-
G__, G_N, G_N_, G_A, G_A_, G_AN, G_AN_, G_AMT
3+
G__, G_N, G_N_, G_A, G_A_, G_AN, G_AN_, G_AMT, G_ALL

cfonb/parser/common.py

Lines changed: 9 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@
1919
# cfonb amount rule
2020
G_AMT = r'(\d{13}[{}A-R]{1})'
2121

22+
# all
23+
G_ALL = r'(.{%d})'
24+
2225

2326
class ParsingError(Exception):
2427
"""Simple parsing Exception for the module.
@@ -45,54 +48,26 @@ class Row(object):
4548
"""Generic row object to manage bank file parsing, compare and reading.
4649
"""
4750

48-
def __init__(self):
49-
"""Empty all at start.
50-
"""
51-
self.empty()
52-
53-
def empty(self):
54-
"""Initializes values to their default values.
55-
"""
56-
self.line_nb = None
57-
self.__list = dict()
58-
self.__dict = dict()
59-
self.__obj = None
60-
self.__db_id = None
61-
62-
def parse(self, re, keys, line, line_nb=None):
51+
def __init__(self, re, keys, line):
6352
"""Parses flat line according re rules, line and additional info.
6453

6554
:param re: regular expression to match with
6655
:param keys: keys values to build dict and object variables for the row
6756
:param line: the flat line to be parsed
68-
:param line_nb: optional info to keep index in the original file
6957
"""
7058
# do re match
7159
match = re.match(line)
7260
# re check
7361
if match is None:
74-
self.empty()
7562
raise ParsingError('line is invalid: "%s"' % line)
7663
else:
77-
self.line_nb = line_nb
78-
self.__list = list(match.groups())
79-
self.__dict = dict(zip(keys, self.__list))
80-
self.__obj = Obj(**self.__dict)
81-
82-
def as_list(self):
83-
return self.__list
84-
85-
def as_dict(self):
86-
return self.__dict
87-
88-
def as_obj(self):
89-
return self.__obj
64+
self.__dict__ = dict(zip(keys, list(match.groups())))
9065

91-
def __str__(self) :
92-
return str(self.__dict)
66+
def __getitem__(self, attr):
67+
return getattr(self, attr)
9368

94-
def __eq__(self, other) :
95-
return self.__dict == other.__dict
69+
def __setitem__(self, attr, value):
70+
return setattr(self, attr, value)
9671

9772

9873
def parse_amount(amount_str, nb_of_dec):

cfonb/parser/statement.py

Lines changed: 42 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77

88
HEAD_RE = re.compile(
9-
r'^%(a)s%(b)s%(c)s%(d)s%(e)s%(f)s%(g)s%(h)s%(i)s%(j)s%(k)s%(l)s%(m)s$'
9+
r'^%(a)s%(b)s%(c)s%(d)s%(e)s%(f)s%(g)s%(h)s%(i)s%(j)s%(k)s%(l)s%(m)s\n$'
1010
% {
1111
'a': '(01)', # record code
1212
'b': parser.G_N % 5, # bank code
@@ -59,17 +59,8 @@
5959
]
6060

6161

62-
def parse_head(line):
63-
# init row
64-
row = parser.Row()
65-
# set row data
66-
row.parse(HEAD_RE, HEAD_KEYS, line)
67-
# return initialized row
68-
return row
69-
70-
7162
CONTENT_4_RE = re.compile(
72-
r'^%(a)s%(b)s%(c)s%(d)s%(e)s%(f)s%(g)s%(h)s%(i)s%(j)s%(k)s%(l)s%(m)s%(n)s%(o)s%(p)s%(q)s%(r)s%(s)s$'
63+
r'^%(a)s%(b)s%(c)s%(d)s%(e)s%(f)s%(g)s%(h)s%(i)s%(j)s%(k)s%(l)s%(m)s%(n)s%(o)s%(p)s%(q)s%(r)s%(s)s\n$'
7364
% {
7465
'a': '(04)', # record code
7566
'b': parser.G_N % 5, # bank code
@@ -83,9 +74,10 @@ def parse_head(line):
8374
'j': parser.G_N % 6, # operation date
8475
'k': parser.G_N_ % 2, # reject code
8576
'l': parser.G_N % 6, # value date
86-
'm': parser.G_AN_ % 31, # label
77+
'm': parser.G_ALL % 31, # label
8778
'n': parser.G_AN_ % 2, # _
88-
'o': parser.G_N % 7, # reference
79+
'o': parser.G_AN % 7, # reference in CFONB norme it's G_N
80+
# but in the real world it's an G_AN
8981
'p': parser.G_AN_ % 1, # exempt code
9082
'q': parser.G_AN_ % 1, # _
9183
'r': parser.G_AMT, # amount
@@ -140,31 +132,23 @@ def parse_head(line):
140132
]
141133

142134

143-
def parse_content_4(line):
144-
# init row
145-
row = parser.Row()
146-
# set row data
147-
row.parse(CONTENT_4_RE, CONTENT_4_KEYS, line)
148-
# return initialized row
149-
return row
150-
151135

152136
CONTENT_5_RE = re.compile(
153-
r'^%(a)s%(b)s%(c)s%(d)s%(e)s%(f)s%(g)s%(h)s%(i)s%(j)s%(k)s%(l)s%(m)s%(n)s$'
137+
r'^%(a)s%(b)s%(c)s%(d)s%(e)s%(f)s%(g)s%(h)s%(i)s%(j)s%(k)s%(l)s%(m)s%(n)s\n$'
154138
% {
155139
'a': '(05)', # record code
156140
'b': parser.G_N % 5, # bank code
157141
'c': parser.G_AN % 4, # internal code
158142
'd': parser.G_N % 5, # desk code
159143
'e': parser.G_A_ % 3, # currency code
160144
'f': parser.G_N_ % 1, # nb of decimal
161-
'g': parser.G__ % 1, # _
145+
'g': parser.G_AN_ % 1, # _
162146
'h': parser.G_AN % 11, # account nb
163147
'i': parser.G_AN % 2, # operation code
164148
'j': parser.G_N % 6, # operation date
165149
'k': parser.G__ % 5, # _
166150
'l': parser.G_AN % 3, # qualifier
167-
'm': parser.G_AN % 70, # additional info
151+
'm': parser.G_ALL % 70, # additional info
168152
'n': parser.G__ % 2, # _
169153
}
170154
)
@@ -206,20 +190,10 @@ def parse_content_4(line):
206190
]
207191

208192

209-
def parse_content_5(line):
210-
"""NOT TESTED
211-
"""
212-
# init row
213-
row = parser.Row()
214-
# set row data
215-
row.parse(CONTENT_5_RE, CONTENT_5_KEYS, line)
216-
# return initialized row
217-
return row
218-
219193

220194

221195
FOOT_RE = re.compile(
222-
r'^%(a)s%(b)s%(c)s%(d)s%(e)s%(f)s%(g)s%(h)s%(i)s%(j)s%(k)s%(l)s%(m)s$'
196+
r'^%(a)s%(b)s%(c)s%(d)s%(e)s%(f)s%(g)s%(h)s%(i)s%(j)s%(k)s%(l)s%(m)s\n$'
223197
% {
224198
'a': '(07)', # record code
225199
'b': parser.G_N % 5, # bank code
@@ -272,14 +246,6 @@ def parse_content_5(line):
272246
]
273247

274248

275-
def parse_footer(line):
276-
# init row
277-
row = parser.Row()
278-
# set row data
279-
row.parse(FOOT_RE, FOOT_KEYS, line)
280-
# return initialized row
281-
return row
282-
283249

284250
class Statement(object):
285251
"""Satement file parser and container. Parse file object to corresponding
@@ -292,25 +258,44 @@ def __init__(self):
292258
self.footer = None
293259
self.lines = list()
294260

261+
def parse_header(self, line):
262+
self.header = parser.Row(HEAD_RE, HEAD_KEYS, line)
263+
264+
def parse_footer(self, line):
265+
self.footer = parser.Row(FOOT_RE, FOOT_KEYS, line)
266+
267+
def parse_content_4(self, line):
268+
# init row
269+
row = parser.Row(CONTENT_4_RE, CONTENT_4_KEYS, line)
270+
# return initialized row
271+
return row
272+
273+
def parse_content_5(self, line):
274+
"""NOT TESTED
275+
"""
276+
# init row
277+
row = parser.Row(CONTENT_5_RE, CONTENT_5_KEYS, line)
278+
# return initialized row
279+
return row
280+
281+
295282
def parse(self, file_obj):
296283
file_lines = file_obj.readlines()
297284
# header and footer
298-
self.header = parser.Row()
299-
self.header.parse(HEAD_RE, HEAD_KEYS, file_lines[0])
300-
self.footer = parser.Row()
301-
self.footer.parse(FOOT_RE, FOOT_KEYS, file_lines[-1])
285+
self.parse_header(file_lines.pop(0))
286+
self.parse_footer(file_lines.pop())
287+
302288
# content
303-
for i, l in enumerate(file_lines[1:-1]):
289+
for index, line in enumerate(file_lines):
304290
# parse line
305-
row = parser.Row()
306-
if CONTENT_4_RE.match(l):
307-
row.parse(CONTENT_4_RE, CONTENT_4_KEYS, l, line_nb=i)
308-
elif CONTENT_5_RE.match(l):
309-
row.parse(CONTENT_5_RE, CONTENT_5_KEYS, l, line_nb=i)
291+
if CONTENT_4_RE.match(line):
292+
row = self.parse_content_4(line)
293+
elif CONTENT_5_RE.match(line):
294+
row = self.parse_content_5(line)
310295
else:
311-
raise parser.ParsingError('line %s is invalid: "%s"' % (i, l))
296+
if line[0:2] in ['01', '07']:#we don't take care of subtotal
297+
continue
298+
else:
299+
raise parser.ParsingError('line %s is invalid: "%s"' % (index, line))
312300
# update content
313301
self.lines.append(row)
314-
315-
316-

0 commit comments

Comments
 (0)