diff Generic/fiebdc.py @ 23:65e7ae0d0e63

GTK2 to GTK3
author Miguel Ángel Bárcena Rodríguez <miguelangel@obraencurso.es>
date Thu, 02 May 2019 16:31:17 +0200
parents f7e0cc58737f
children 189f8274aecd
line wrap: on
line diff
--- a/Generic/fiebdc.py	Tue Sep 30 17:16:50 2014 +0200
+++ b/Generic/fiebdc.py	Thu May 02 16:31:17 2019 +0200
@@ -3,7 +3,7 @@
 ## File fiebdc.py
 ## This file is part of pyArq-Presupuestos.
 ##
-## Copyright (C) 2010-2014 Miguel Ángel Bárcena Rodríguez
+## Copyright (C) 2010-2019 Miguel Ángel Bárcena Rodríguez
 ##                         <miguelangel@obraencurso.es>
 ##
 ## pyArq-Presupuestos is free software: you can redistribute it and/or modify
@@ -38,49 +38,45 @@
     
     Description:
         Reads and parses a fiebdc file
+        +-- __budget: budget ("base.Budget" object)
+        +-- __file_format: File format of the fiebdc file
+        +-- __format_list: List of file format that can be readed
+        +-- __character_sets_dict: Dictionary with the character sets supported
+        +-- __character_set: character_set of the file
+        +-  __generator: program which the file is created
+        +-- __cancel: Boolean value, True mean that the read process must stop
+        +-- __filename: The filename of the fiebdc file that is readed
+        +-- __pattern: re compiled pattern dict
+        +-- __statistics: Statistics object, records number
     Constructor:
         fiebdc.Read(filename=None, budget=None)
     Ancestry:
     +-- object
       +-- Read
     Atributes:
-        "__budget": budget ("base.Budget" object)
-        "__file_format": File format of the fiebdc file
-        "__format_list": List of file format that can be readed
-        "__character_sets_dict": Dictionary with the character sets supported
-        "__character_set": character_set of the file
-        "__generator": program which the file is created
-        "__cancel": Boolean value, True mean that the read process must stop
-        "__filename": The filename of the fiebdc file that is readed
-        "__pattern": re compiled pattern dict
-        "__statistics": Statistics object, records number
+        No public Atributes
     Methods:
-        __init__(self, filename=None, budget=None)
-        cancel(self)
-        eraseControlCharacters(self, string)
-        validateCode(self, code)
-        parseDate(self, date)
-        parseRecord(self,record)
-        _parseV(self, field_list)
-        _parseC(self, field_list)
-        _parseDY(self, field_list)
-        _parseMN(self, field_list)
-        _parseT(self, field_list)
-        _parseK(self, field_list)
-        _parseW(self, field_list)
-        _parseL(self, field_list)
-        _parseQ(self, field_list)
-        _parseJ(self, field_list)
-        _parseG(self, field_list)
-        _parseE(self, field_list)
-        _parseX(self, field_list)
-        _parseF(self, field_list)
-        readFile(self, budget=None, filename=None)
+        cancel()
+        eraseControlCharacters(string)
+        validateCode(code)
+        parseDate(date)
+        parseRecord(record)
+        readFile(budget=None, filename=None)
     """
     def __init__(self, filename=None, budget=None):
-        """def __init__(self, filename=None, budget=None)
+        """def __init__(filename=None, budget=None)
         
         Sets the instance attributes
+        __budget: budget ("base.Budget" object)
+        __file_format: File format of the fiebdc file
+        __format_list: List of file format that can be readed
+        __character_sets_dict: Dictionary with the character sets supported
+        __character_set: character_set of the file
+        __generator: program which the file is created
+        __cancel: Boolean value, True mean that the read process must stop
+        __filename: The filename of the fiebdc file that is readed
+        __pattern: re compiled pattern dict
+        __statistics: Statistics object, records number
         """
         self.__budget = budget
         self.__filename = filename
@@ -96,7 +92,7 @@
                                       "850" : "850",
                                       "437" : "cp437"}
         self.__file_format = "FIEBDC-3/2007"
-        self.__generator = globalVars.version
+        self.__generator = globalVars.name + " " + globalVars.version
         self.__character_set = "850"
         self.__pattern = {
             "control_tilde" : re.compile(u"((\r\n)| |\t)+~"),
@@ -121,14 +117,14 @@
         self.__statistics = Statistics()
 
     def cancel(self):
-        """def cancel(self)
+        """def cancel()
         
         Sets the "__cancel" attribute to True, It stops the read process.
         """
         self.__cancel = True
 
     def eraseControlCharacters(self, string):
-        """eraseControlCharacters(self,string)
+        """eraseControlCharacters(string)
         
         Return a copy of the string with the blank characters (32),
         tabs (9) and end of line (13 and 10) before of the separators
@@ -145,23 +141,23 @@
         return string
 
     def validateCode(self, code):
-        """validateCode(self, code)
+        """validateCode(code)
         
         Test if the code have invalid characters and try to erase it,
         if it is posible return a valid code else return a empty string.
         """
         if not isinstance(code, unicode):
-            print _("Invalid code, it must be a unicode string")
+            print(_("Invalid code, it must be a unicode string") )
             return u""
         # Valid chararcter: A-Z a-z 0-9 ñ Ñ . $ # % & _ 
         # "valid_code" : "[^A-Za-z0-9ñÑ.$#%&_]"
-        _ucode = self.__pattern["valid_code"].sub(u"", code)
+        _ucode = self.__pattern["valid_code"].sub(u"_", code)
         if _ucode != code:
             try:
-                print utils.mapping(_("The code '$1' have invalid characters."),
-                               (code.encode("utf8"),))
+                print(utils.mapping(_("The code '$1' have invalid characters, replaced by '$2'."),
+                               (code.encode("utf8"),_ucode.encode("utf8"))) )
             except:
-                print utils.mapping(_("The code '$1' have invalid characters and can not be encoded in utf8."), (code,))
+                print(utils.mapping(_("The code '$1' have invalid characters and can not be encoded in utf8."), (code,)) )
             
             if len(_ucode) == 0:
                 _normalize_code = ''.join((c for c in unicodedata.normalize('NFD', _ucode) if unicodedata.category(c) != 'Mn'))
@@ -173,25 +169,30 @@
                     _hexdigest_code = _hash_code.hexdigest()
                     _ucode = self.__pattern["valid_code"].sub(u"", _hexdigest_code)
             code = _ucode
+        if code == u"##":
+            # root code is an empty code : set to ROOT
+            return u"ROOT"
         # the lasts characters can not be <#> or <##>
         # <##> -> root record in FIEFDC-3
         # <#> -> chapter record in FIEFDC-3
         if len(code) > 0:
             while code[-1] == u"#":
                 code = code[:-1]
+                if len(code) == 0:
+                    return code
             if len(code) > 20:
                 code = code[:20]
             # only one charecter # % or &
             if sum([code.count(c) for c in u'#%&']) > 1:
-                print utils.mapping(_("The code '$1' contains special "\
-                                      "characters repeated."),(code.encode("utf8"),))
+                print(utils.mapping(_("The code '$1' contains special "\
+                                      "characters repeated."),(code.encode("utf8"),)) )
                 _i = min([code.find(c) for c in u'#%&'])
                 code = code[:_i+1] + \
                         self.__pattern["special_char"].sub(u"", code[_i+1:])
         return code
 
     def parseDate(self, date):
-        """parseDate(self, date)
+        """parseDate(date)
         
         date: in the format:
             uneven len: add a Leading 0
@@ -233,8 +234,8 @@
                 _d = 0
         return (_y, _m, _d)
 
-    def parseRecord(self,record):
-        """parseRecord(self,record)
+    def parseRecord(self, record, interface):
+        """parseRecord(record, interface)
         
         record: the record line readed from the file whith the format:
             type|field|field|subfield\subfield|...
@@ -317,6 +318,7 @@
             A: Labels
                 1- Record Code
                 2- <Label\>
+            interface:
         """
         # TODO:  ~L ~J RTF and HTML files
         # TODO:  test ~Q ~J ~G
@@ -331,13 +333,13 @@
             self._parseV(_field_list)
         elif _field_list[0] == u"C":
             self.__statistics.C += 1
-            self._parseC(_field_list)
+            self._parseC(_field_list, interface)
         elif _field_list[0] == u"D":
             self.__statistics.D += 1
-            self._parseDY(_field_list)
+            self._parseDY(_field_list, interface)
         elif _field_list[0] == u"Y":
             self.__statistics.Y += 1
-            self._parseDY(_field_list)
+            self._parseDY(_field_list, interface)
         elif _field_list[0] == u"M":
             self.__statistics.M += 1
             self._parseMN(_field_list)
@@ -386,10 +388,11 @@
             self.__statistics.A += 1
             self._parseA(_field_list)
         else:
+            print(utils.mapping(_("FIEBDC. Unknow record: $1"),(record[:100],)))
             self.__statistics.unknow += 1
 
     def _parseV(self, field_list):
-        """_parseV(self, field_list)
+        """_parseV(field_list)
         
         field_list: field list of the record
             0- V :Property and Version
@@ -404,11 +407,11 @@
             9- [Date budget certificate]
         """
         if self.__statistics.records != 1:
-            print utils.mapping(_("The 'V' record (Property and Version) "\
+            print(utils.mapping(_("The 'V' record (Property and Version) "\
                     "must be the first record in the file but it is the "\
-                    "number: $1"), (self.__statistics.records,))
-            print _("The default values were taken and this V record is "\
-                  "ignored")
+                    "number: $1"), (str(self.__statistics.records),)) )
+            print(_("The default values were taken and this V record is "\
+                  "ignored") )
             return
         # _____number of fields_____
         # Any INFORMATION after last field separator is ignored
@@ -441,7 +444,7 @@
         _file_format = _version_date[0]
         if _file_format in self.__format_list:
             self.__file_format = _file_format
-            print utils.mapping(_("FIEBDC format: $1"),(_file_format,))
+            print(utils.mapping(_("FIEBDC format: $1"),(_file_format,)) )
 
         if len(_version_date) > 1:
             _date = _version_date[1]
@@ -451,7 +454,7 @@
                     self.__budget.setDate(_parsed_date)
         # _____Generator_____
         # ignored field
-        print utils.mapping(_("FIEBDC file generated by $1"),(_generator,))
+        print(utils.mapping(_("FIEBDC file generated by $1"),(_generator,)) )
         # _____Header_Title_____
         _header_title = _header_title.split(u"\\")
         _header_title = [_title.strip() for _title in _header_title]
@@ -499,7 +502,7 @@
         self.__statistics.valid = self.__statistics.valid + 1
 
     def _parseK(self, field_list):
-        """_parseK(self, field_list)
+        """_parseK(field_list)
         
         field_list: field list of the record
             0- K: Coefficients
@@ -740,8 +743,8 @@
                                            (_decimal_index//13))
         self.__statistics.valid = self.__statistics.valid +1
 
-    def _parseC(self, field_list):
-        """_parseC(self, field_list)
+    def _parseC(self, field_list, interface):
+        """_parseC(field_list)
         
         field_list: field list of the record
             0- C: Record
@@ -774,9 +777,9 @@
         if len(_codes) > 0:
             # parse the hierarchy of the first code
             # hierarchy: 0->root, 1->Chapter/subchapter, 2->other
-            if len(_codes[0]) > 2 and _codes[0][-2:] == u"##":
+            if len(_codes[0]) > 1 and _codes[0][-2:] == u"##":
                 _hierarchy = 0
-            elif len(_codes[0]) > 1 and _codes[0][-1:] == u"#":
+            elif len(_codes[0]) > 0 and _codes[0][-1:] == u"#":
                 _hierarchy = 1
             else:
                 _hierarchy = 2
@@ -792,7 +795,7 @@
             _code = _codes[0]
             _synonyms = [synonym.encode("utf8") for synonym in _codes]
         else:
-            print _("Record C without a valid code")
+            print(_("Record C without a valid code") )
             return
         # _____Unit_____
         # nothing to do
@@ -804,6 +807,7 @@
             _dates = _dates[:-1]
         if len(_prices) > 0 and _prices[-1] == u"\\":
             _prices = _prices[:-1]
+        interface.updateGui()
         _dates = _dates.split(u"\\")
         _prices = _prices.split(u"\\")
         # number of prices = number of titles in "V" line
@@ -860,6 +864,7 @@
         #                    1 -> None,H
         #                    2 -> None,Q,%
         #                    3 -> None,MC,MCr,MM,MS,ME,MCu,Mal,ML,M
+        interface.updateGui()
         if _hierarchy == 0:
             if _type == u"OB":
                 _subtype = _type
@@ -868,8 +873,8 @@
                 _subtype = u""
                 _type = 0
             else:
-                print utils.mapping(_("Incorrect type ($1) in the code $2"),
-                      (_type.encode("utf8"), _code.encode("utf8")))
+                print(utils.mapping(_("Incorrect type ($1) in the code $2"),
+                      (_type.encode("utf8"), _code.encode("utf8"))) )
                 _type = 0
                 _subtype = u""
         elif _hierarchy == 1:
@@ -880,8 +885,8 @@
                 _subtype = u""
                 _type = 0
             else:
-                print utils.mapping(_("Incorrect type ($1) in the code $2"),
-                      (_type.encode("utf8"), _code.encode("utf8")))
+                print(utils.mapping(_("Incorrect type ($1) in the code $2"),
+                      (_type.encode("utf8"), _code.encode("utf8"))) )
                 _type = 0
                 _subtype = u""
         else:
@@ -908,8 +913,8 @@
                 _subtype = u""
                 _type = 0
             else:
-                print utils.mapping(_("Incorrect type ($1) in the code $2"),
-                      (_type.encode("utf8"), _code.encode("utf8")))
+                print(utils.mapping(_("Incorrect type ($1) in the code $2"),
+                      (_type.encode("utf8"), _code.encode("utf8"))) )
                 _type = 0
                 _subtype = u""
         self.__budget.setRecord(_code.encode("utf8"), _synonyms, _hierarchy,
@@ -917,8 +922,8 @@
             _prices, _dates, _type, _subtype.encode("utf8"))
         self.__statistics.valid = self.__statistics.valid + 1
     
-    def _parseDY(self, field_list):
-        """_parseDY(self, field_list)
+    def _parseDY(self, field_list, interface):
+        """_parseDY(field_list)
         
         field_list: field list of the record
             0- D or Y: DECOMPOSITION or ADD DECOMPOSITION
@@ -939,6 +944,7 @@
         _record_type = field_list[0]
         _code = self.delete_control_space(field_list[1])
         _children = self.delete_control_space(field_list[2])
+        interface.updateGui()
         # _____Code_____
         # "#" and "##" characters at the end of the code are erased
         # invalid characters are also erased
@@ -948,6 +954,7 @@
         _children = _children.split(u"\\")
         _children_list = [ ]
         _child_index = 0
+        interface.updateGui()
         while _child_index < len(_children)-3:
             # _____subfields_____
             _child_code = _children[_child_index]
@@ -960,22 +967,22 @@
                 try:
                     _factor = float(_factor)
                 except ValueError:
-                    print utils.mapping(_("ValueError loadig the "\
+                    print(utils.mapping(_("ValueError loadig the "\
                           "descomposition of the record $1, the factor "\
                           "of the child $2 must be a float number and "\
                           "can not be $3, seted default value 1.0"),
-                          (_code.encode("utf8"), _child_code.encode("utf8"), _factor.encode("utf8")))
+                          (_code.encode("utf8"), _child_code.encode("utf8"), _factor.encode("utf8"))) )
                     _factor = 1.0
             #____yield___
             if _yield != u"":
                 try:
                     _yield = float(_yield)
                 except ValueError:
-                    print utils.mapping(_("ValueError loading the "\
+                    print(utils.mapping(_("ValueError loading the "\
                           "descomposition of the record $1, the yield of "\
                           "the child $2, must be a float number and can"\
                           "not be $3,  seted default value 1.0"),
-                           (_code.encode("utf8"), _child_code.encode("utf8"), _factor.encode("utf8")))
+                           (_code.encode("utf8"), _child_code.encode("utf8"), _factor.encode("utf8"))) )
                     _yield = 1.0
             if _child_code != u"" and _code != u"":
                 _children_list.append([_child_code, _factor, _yield ])
@@ -986,10 +993,11 @@
             self.__budget.setTree(_code.encode("utf8"), _child_code.encode("utf8"), _position, _factor, 
                 _yield, "", "", "", "")
             _child_index = _child_index + 3
+            interface.updateGui()
         self.__statistics.valid = self.__statistics.valid +1
 
     def _parseT(self, field_list):
-        """_parseT(self, field_list)
+        """_parseT(field_list)
         
         field_list: field list of the record
             0- T: Text
@@ -1017,7 +1025,7 @@
         self.__statistics.valid = self.__statistics.valid + 1
 
     def _parseMN(self, field_list):
-        """_parseMN(self, field_list)
+        """_parseMN(field_list)
         
         field_list: field list of the record
             0- M or N: MEASURE or ADD MEASURE
@@ -1059,12 +1067,12 @@
             _child_code =  self.validateCode(_code_list[0])
             _parent_code = None
         else:
-            print utils.mapping(_("Invalid codes in $1 record, codes $2"),
-                  (_record_type.encode("utf8"), _codes.encode("utf8")))
+            print(utils.mapping(_("Invalid codes in $1 record, codes $2"),
+                  (_record_type.encode("utf8"), _codes.encode("utf8"))) )
             return
         if _child_code == u"":
-            print utils.mapping(_("Empty child code in $1 record, codes: "\
-                  "$2"), (_record_type.encode("utf8"), _codes.encode("utf8")))
+            print(utils.mapping(_("Empty child code in $1 record, codes: "\
+                  "$2"), (_record_type.encode("utf8"), _codes.encode("utf8"))) )
             return
         if _parent_code == None:
             # Empty parent code. No-estructured measures.
@@ -1083,8 +1091,8 @@
             try:
                 _path = int(_path)
             except ValueError:
-                print utils.mapping(_("Invalid path in $1 record, "\
-                      "codes $2"), (_record_type.encode("utf8"), _codes.encode("utf8")))
+                print(utils.mapping(_("Invalid path in $1 record, "\
+                      "codes $2"), (_record_type.encode("utf8"), _codes.encode("utf8"))) )
                 return
             if _path > 0:
                 _path -= 1
@@ -1094,9 +1102,9 @@
         try:
             _total = float(_total)
         except ValueError:
-            print utils.mapping(_("Invalid Total Measure value in $1 "\
+            print(utils.mapping(_("Invalid Total Measure value in $1 "\
                   "record, codes $2. Total fixed to 0."),
-                  (_record_type.encode("utf8"), _codes.encode("utf8")))
+                  (_record_type.encode("utf8"), _codes.encode("utf8"))) )
             _total = 0
         # _____Measure lines_____
         _lines = _lines.split(u"\\")
@@ -1115,9 +1123,9 @@
             if _linetype == 3:
                 # "formula": ".*[^0123456789\.()\+\-\*/\^abcdp ].*"
                 if self.__pattern["formula"].match(_comment):
-                    print utils.mapping(_("The comment is not a formula or "\
+                    print(utils.mapping(_("The comment is not a formula or "\
                           "its have invalid characters, in the $1 record, "\
-                          "codes $2"), (_record_type.encode("utf8"), _codes.encode("utf8")))
+                          "codes $2"), (_record_type.encode("utf8"), _codes.encode("utf8"))) )
                     return
                 else:
                     _formula = _comment.encode("utf8")
@@ -1141,8 +1149,8 @@
                 if _width != u"": _width = float(_width)
                 if _height != u"": _height = float(_height)
             except ValueError:
-                print utils.mapping(_("The measure values are not float "\
-                      "numbers, code $1"), (_codes.encode("utf8"),))
+                print(utils.mapping(_("The measure values are not float "\
+                      "numbers, code $1"), (_codes.encode("utf8"),)) )
                 return
             # Prevent subfield units remains empty.
             if (_units == u"" and (_length != u"" or _width != u""
@@ -1156,7 +1164,7 @@
         self.__statistics.valid = self.__statistics.valid + 1
 
     def _parseW(self, field_list):
-        """_parseW(self, field_list)
+        """_parseW(field_list)
         
         field_list: field list of the record
             0- W: Geografical field
@@ -1195,7 +1203,7 @@
         self.__statistics.valid = self.__statistics.valid +1
     
     def _parseL(self, field_list):
-        """_parseL(self, field_list)
+        """_parseL(field_list)
         
         field_list: field list of the record
             0- L: Sheet of Conditions 1
@@ -1259,7 +1267,7 @@
             _scodes_text = field_list[1]
             if _scodes_text == u"":
                 # TODO: rtf and html files
-                print "Html and rtf files not yet implemented in ~L record"
+                print("Html and rtf files not yet implemented in ~L record" )
             else:
                 # _____Section-code_Section-text_____
                 # last \ is erased
@@ -1288,7 +1296,7 @@
                 self.__statistics.valid = self.__statistics.valid +1
     
     def _parseQ(self, field_list):
-        """_parseQ(self, field_list)
+        """_parseQ(field_list)
         
         field_list: field list of the record
             0- Q: Sheet of Conditions 2
@@ -1349,7 +1357,7 @@
         self.__statistics.valid = self.__statistics.valid +1
     
     def _parseJ(self, field_list):
-        """_parseJ(self, field_list)
+        """_parseJ(field_list)
         
         field_list: field list of the record
             0- J: Sheet of Conditions 3
@@ -1374,13 +1382,13 @@
         _paragraph_text = field_list[1]
         if _paragraph_text == u"":
             # TODO: rtf and html files
-            print "Html and rtf files not yet implemented in ~J record"
+            print("Html and rtf files not yet implemented in ~J record" )
         else:
             self.__budget.setSheetParagraph(paragraph_code.encode("utf8"), paragraph_text.encode("utf8"))
             self.__statistics.valid = self.__statistics.valid +1
     
     def _parseG(self, field_list):
-        """_parseG(self, field_list)
+        """_parseG(field_list)
         
         field_list: field list of the record
             0- G: Grafic info
@@ -1412,7 +1420,7 @@
         _tested_grafic_file_list = []
         for _grafic_file in _grafic_file_list:
             _str_grafic_file = _grafic_file.encode("utf8")
-            _path = os.path.dirname(self.__filename)
+            _path = os.path.dirname(self.__filename).encode("utf8")
             _grafic_file_path = os.path.join(_path, _str_grafic_file)
             if os.path.exists(_grafic_file_path):
                 _tested_grafic_file_list.append(_grafic_file_path)
@@ -1441,15 +1449,15 @@
                 elif os.path.exists(_grafic_file_path_ll):
                     _tested_grafic_file_list.append(_grafic_file_path_ll)
                 else:
-                    print utils.mapping(_("The file $1 do not exist"),
-                        (_grafic_file_path,))
+                    print(utils.mapping(_("The file $1 do not exist"),
+                        (_grafic_file_path.decode("utf8"),)) )
         if len(_grafic_file_list) > 0:
             for _grafic_file in _tested_grafic_file_list:
                 self.__budget.addFile(_record_code.encode("utf8"), _grafic_file, "img", "")
             self.__statistics.valid = self.__statistics.valid +1
     
     def _parseE(self, field_list):
-        """_parseE(self, field_list)
+        """_parseE(field_list)
         
         field_list: field list of the record
             0- E: Company
@@ -1548,7 +1556,7 @@
         self.__statistics.valid = self.__statistics.valid +1
     
     def _parseX(self, field_list):
-        """_parseX(self, field_list)
+        """_parseX(field_list)
         
         field_list: field list of the record
             A)
@@ -1603,14 +1611,15 @@
         self.__statistics.valid = self.__statistics.valid +1
 
     def _parseF(self, field_list):
-        """_parseF(self, field_list)
+        """_parseF(field_list)
         
         field_list: field list of the record
             0- F: Files
             1- Record code
             2- { Type \ { Filenames; } \ [Description] }
         """
-
+        print("parseF")
+        print(field_list)
         # _____Number of fields_____
         # The record must have at least 3 fields
         if len(field_list) < 3:
@@ -1638,23 +1647,24 @@
             _files_list.extend[u""]*(3 - len(_files_list)%3)
         _file_index = 0
         _tested_files_list = []
+        print(_files_list)
         while _file_index < len(_files_list)-3:
             _type = _files_list[_file_index].replace(u" ",u"")
-##            _types = {
-##                "0": _("others"),
-##                "1": _("características técnicas y de fabricación"),
-##                "2": _("manual de colocación, uso y mantenimiento"),
-##                "3": _("certificado/s de elementos y sistemas"),
-##                "4": _("normativa y bibliografía"),
-##                "5": _("tarifa de precios"),
-##                "6": _("condiciones de venta"),
-##                "7": _("carta de colores"),
-##                "8": _("ámbito de aplicación y criterios selección"),
-##                "9": _("cálculo de elementos y sistemas"),
-##                "10": _("presentación, datos generales, objetivos, etc. de "\
-##                        "empresa"),
-##                "11": _("certificado/s de empresa"),
-##                "12": _("obras realizadas")}
+            ## _types = {
+            ##           "0": _("others"),
+            ##           "1": _("características técnicas y de fabricación"),
+            ##           "2": _("manual de colocación, uso y mantenimiento"),
+            ##           "3": _("certificado/s de elementos y sistemas"),
+            ##           "4": _("normativa y bibliografía"),
+            ##           "5": _("tarifa de precios"),
+            ##           "6": _("condiciones de venta"),
+            ##           "7": _("carta de colores"),
+            ##           "8": _("ámbito de aplicación y criterios selección"),
+            ##           "9": _("cálculo de elementos y sistemas"),
+            ##          "10": _("presentación, datos generales, objetivos, " \
+            ##                  "etc. de empresa"),
+            ##          "11": _("certificado/s de empresa"),
+            ##          "12": _("obras realizadas")}
             _types = [u"0", u"1", u"2", u"3", u"4", u"5", u"6", u"7", u"8", u"9", u"10",
                       u"11", u"12"]
             if not _type in _types:
@@ -1662,11 +1672,15 @@
             _filenames = _files_list[_file_index + 1]
             _description = _files_list[_file_index + 2]
             _file_index += 3
+            print(u"type: " + _type)
+            print(u"filenames: " + _filenames)
+            print(u"_description: " + _description)
             if len(_filenames) and _filenames[-1] == u";":
                 _files = _files[:-1]
-            _filenames_list = _files.split(u";")
+            _filenames_list = _filenames.split(u";")
+            
             _path = os.path.dirname(self.__filename)
-            for _filename in filenames_list:
+            for _filename in _filenames_list:
                 _file_path = os.path.join(_path, _filename.encode("utf8"))
                 if os.path.exists(_file_path):
                     _tested_files_list.append([_file_path, _type.encode("utf8"),
@@ -1700,15 +1714,15 @@
                         _tested_files_list.append([_file_path_ll, _type.encode("utf8"),
                                                    _description.encode("utf8")])
                     else:
-                        print utils.mapping(_("The file $1 do not exist"),
-                            (_file_path,))
+                        print(utils.mapping(_("The file $1 do not exist"),
+                            (_file_path,)) )
         if len(_tested_files_list) > 0:
-            for _file in _tested_file_list:
-                self.__budget.addFile(_record_code.encode("utf8"), _file[0], file[1], file[2])
+            for _file in _tested_files_list:
+                self.__budget.addFile(_record_code.encode("utf8"), _file[0], _file[1], _file[2])
         self.__statistics.valid = self.__statistics.valid +1
 
     def _parseB(self, field_list):
-        """_parseB(self, field_list)
+        """_parseB(field_list)
         
         field_list: field list of the record
             0- B: Change code
@@ -1737,7 +1751,7 @@
         self.__statistics.valid = self.__statistics.valid + 1
 
     def _parseA(self, field_list):
-        """_parseA(self, field_list)
+        """_parseA(field_list)
         
         field_list: field list of the record
             0- A: Labels
@@ -1774,7 +1788,7 @@
         self.__statistics.valid = self.__statistics.valid + 1
 
     def _parseP(self, field_list):
-        """_parseP(self, field_list)
+        """_parseP(field_list)
         
         field_list: Parametric record
             A) Global paremetric record
@@ -1806,14 +1820,14 @@
                     field_list = field_list[0:3]
                 field_list = field_list[1:]
                 if len(field_list) != 2:
-                    print _("PyArq hates parametric DLLs")
+                    print(_("PyArq hates parametric DLLs") )
                     return
         else:
             return
         # _____Description_____
         _description = field_list[1]
         if _description == u"":
-            print _("PyArq hates parametric DLLs")
+            print(_("PyArq hates parametric DLLs") )
             return
         # Adding last end of line
         _description = _description + u"\r\n"
@@ -1878,19 +1892,19 @@
                     # parse data
                     if len(_line) > 2 and _line[:2] == u"::":
                         # Delete spaces out " delimiter
-                        #print "__PRECIO__" + _line[2:]
+                        #print("__PRECIO__" + _line[2:])
                         pass
                     elif len(_line) > 2 and _line[:2] == u"%:":
                         # Delete spaces out " delimiter
-                        #print "__%AUX__" + _line[2:]
+                        #print("__%AUX__" + _line[2:])
                         pass
                     elif len(_line) > 3 and _line[:2] == u"%%:":
                         # Delete spaces out " delimiter
-                        #print "__%%AUX__" + _line[2:]
+                        #print("__%%AUX__" + _line[2:] )
                         pass
                     elif self.__pattern["var"].search(_line):
                         # Delete spaces out " delimiter
-                        #print "line =", _line
+                        #print( "line =", _line )
                         while _line.count(u'"') % 2 == 1 and \
                               index + _pass_line + 1 < len(_lines) -1:
                             _line = _line + _lines[index + _pass_line + 1]
@@ -1898,10 +1912,10 @@
                         _search = self.__pattern["var"].search(_line)
                         if _search is not None:
                             _var = _search.groups()[0] + u" = " + _search.groups()[1]
-                            #print "__VAR__" + str(_var)
+                            #print("__VAR__" + str(_var) )
                             pass
                         else:
-                            #print "no __VAR__", _line
+                            #print( "no __VAR__", _line )
                             pass
                     elif self.__pattern["descomposition"].search(_line):
                         # Delete spaces out " delimiter
@@ -1909,73 +1923,73 @@
                         _search = self.__pattern["descomposition"].search(_line)
                         if _search is not None:
                             _var = _search.groups()[0] + u":" + _search.groups()[1]
-                            #print "__Descomposición__" + str(_var)
+                            #print( "__Descomposición__" + str(_var) )
                             pass
                         else:
-                            #print "no __Descomposición__", _line
+                            #print("no __Descomposición__", _line )
                             pass
                     else:
-                        print "Parametric: code: " + _family_code.encode("utf8")
-                        print "******* Desconocido *** : " + _line
-                        if index-10 > 0: print "-11 :", _lines[index-11].encode("utf8")
-                        if index-10 > 0: print "-10 :", _lines[index-10].encode("utf8")
-                        if index-9 > 0: print "-9 :", _lines[index-9].encode("utf8")
-                        if index-8 > 0: print "-8 :", _lines[index-8].encode("utf8")
-                        if index-7 > 0: print "-7 :", _lines[index-7].encode("utf8")
-                        if index-6 > 0: print "-6 :", _lines[index-6].encode("utf8")
-                        if index-5 > 0: print "-5 :", _lines[index-5].encode("utf8")
-                        if index-4 > 0: print "-4 :", _lines[index-4].encode("utf8")
-                        if index-3 > 0: print "-3 :", _lines[index-3].encode("utf8")
-                        if index-2 > 0: print "-2 :", _lines[index-2].encode("utf8")
-                        if index-1 > 0: print "-1 :", _lines[index-1].encode("utf8")
-                        print "-0 :", _lines[index-0]
+                        print("Parametric: code: " + _family_code.encode("utf8") )
+                        print("******* Desconocido *** : " + _line )
+                        if index-10 > 0: print("-11 : " + _lines[index-11].encode("utf8") )
+                        if index-10 > 0: print("-10 : " + _lines[index-10].encode("utf8") )
+                        if index-9 > 0: print("-9 : " + _lines[index-9].encode("utf8") )
+                        if index-8 > 0: print("-8 : " + _lines[index-8].encode("utf8") )
+                        if index-7 > 0: print("-7 : " + _lines[index-7].encode("utf8") )
+                        if index-6 > 0: print("-6 : " + _lines[index-6].encode("utf8") )
+                        if index-5 > 0: print("-5 : " + _lines[index-5].encode("utf8") )
+                        if index-4 > 0: print("-4 : " + _lines[index-4].encode("utf8") )
+                        if index-3 > 0: print("-3 : " + _lines[index-3].encode("utf8") )
+                        if index-2 > 0: print("-2 : " + _lines[index-2].encode("utf8") )
+                        if index-1 > 0: print("-1 : " + _lines[index-1].encode("utf8") )
+                        print("-0 :" + _lines[index-0] )
                         pass
                 else:
                     _parameter_list = _line.split(u"\\")[1:-1]
                     if len(_parameter_list) >= 2:
                         if _parameter_list[0] == u"C" or \
                            _parameter_list[0] == u"COMENTARIO":
-                            #print "__COMENTARIO__" + _parameter_list[1]
+                            #print( "__COMENTARIO__" + _parameter_list[1])
                             self.__budget.setParametricSelectComment(
                                 _family_code.encode("utf8"), _parameter_list[1].encode("utf8"))
                         elif _parameter_list[0] == u"R" or \
                            _parameter_list[0] == u"RESUMEN":
-                            #print "__RESUMEN__" + _parameter_list[1]
+                            #print( "__RESUMEN__" + _parameter_list[1])
                             self.__budget.setParametricSummary(_family_code.encode("utf8"),
                                 _parameter_list[1].encode("utf8"))
                         elif _parameter_list[0] == u"T" or \
                            _parameter_list[0] == u"TEXTO":
-                            #print "__TEXTO__" + _parameter_list[1]
+                            #print( "__TEXTO__" + _parameter_list[1])
                             self.__budget.setParametricText(_family_code.encode("utf8"),
                                 _parameter_list[1].encode("utf8"))
                         elif _parameter_list[0] == u"P" or \
                            _parameter_list[0] == u"PLIEGO":
-                            #print "__PLIEGO__" + str(_parameter_list[1:])
+                            #print( "__PLIEGO__" + str(_parameter_list[1:]) )
                             pass
                         elif _parameter_list[0] == u"K" or \
                            _parameter_list[0] == u"CLAVES":
-                            #print "__CLAVES__" + str(_parameter_list[1:])
+                            #print( "__CLAVES__" + str(_parameter_list[1:]) )
                             pass
                         elif _parameter_list[0] == u"F" or \
                            _parameter_list[0] == u"COMERCIAL":
-                            #print "__COMERCIAL__" + str(_parameter_list[1:])
+                            #print( "__COMERCIAL__" + str(_parameter_list[1:]) )
                             pass
                         else:
-                            #print "==PARAMETRO==" + str(_parameter_list[:])
+                            #print( "==PARAMETRO==" + str(_parameter_list[:]) )
                             pass
                 _final_description = _final_description + _line + u"\r\n"
                 
-                #print _line
+                #print( _line )
         # Delete last empty line
         _description = _final_description[:-2]
         _lines = _description.split(u"\r\n")
         for _line in _lines:
             pass
-            #print _line
+            #print( _line )
         self.__statistics.valid = self.__statistics.valid + 1
 
     def readFile(self, budget=None, filename=None, interface=None):
-        """readFile(self, budget=None, filename=None)
+        """readFile(budget=None, filename=None)
         
         filename: the filename of the fiebdc file
         budget: base.obra object
@@ -1985,7 +1999,8 @@
                       readFile_progress(percent)
                       readFile_end()
                       readFile_cancel()
-        Return the budget objetc or None if the file can be readed
+                      updateGui()
+        Return  None
         """
         if not filename is None and not budget is None:
             self.__filename = filename
@@ -2002,14 +2017,19 @@
         try:
             _file =  open(self.__filename, 'r')
         except IOError:
-            print utils.mapping("IOError: $1", (self.__filename,))
+            print( utils.mapping("IOError: $1", (self.__filename,)) )
+            return None
+        _filesize = float(os.path.getsize(self.__filename))
+        if _filesize == 0.0:
+            print( utils.mapping("Empty File: $1", (self.__filename,)) )
+            # Todo: Create empty budget
             return None
         self.__budget.filename = self.__filename
         interface.readFile_send_message(utils.mapping(_("Loading file $1"),
                          (self.__filename,)))
-        _filesize = float(os.path.getsize(self.__filename))
         interface.readFile_progress(_file.tell() / _filesize)
         _buffer = _file.read(1000)
+        interface.updateGui()
         # set codepage from V record
         _record_list = _buffer.split("~")
         registro_V = _record_list[1]
@@ -2043,6 +2063,7 @@
                   "Not 'V' record in File! Default character encoding: "\
                   "$1"), (self.__character_set,)))
         _buffer = unicode(_buffer, self.__character_set)
+        interface.updateGui()
         # Any INFORMATION between the beginning of the file and the
         # beginning of the first registry “~” is ignored
         #"after_first_tilde" : "^[^~]*~"
@@ -2056,11 +2077,12 @@
             _record_list = _buffer.split(u"~")
             # The last record can be incomplete unless it is the last one of
             # the file
-            if len(_record_list) > 1:
+            #if len(_record_list) > 1:
+            if (_file.tell() / _filesize) != 1.0:
                 # not the end
                 _last_record = _record_list.pop()
             else:
-                # the end record
+                # The last record
                 # The blank characters (32), tabs (9) and end of line
                 # (13 and 10) at the end of the file are ignored.
                 #"end_control" : "((\r\n)| |\t)+$"
@@ -2070,11 +2092,14 @@
             for record in _record_list:
                 if self.__cancel:
                     break
-                self.parseRecord(record)
+                self.parseRecord(record, interface)
+                interface.updateGui()
             interface.readFile_progress(_file.tell() / _filesize)
             _buffer2 = _file.read(100000)
+            interface.updateGui()
             _buffer2 = unicode(_buffer2, self.__character_set)
             _buffer = _last_record + _buffer2
+            interface.updateGui()
         _file.close()
         if self.__cancel:
             interface.readFile_cancel()
@@ -2084,22 +2109,22 @@
             if self.__statistics.O > 0:
                 interface.readFile_send_message(
                     utils.mapping(_("$1 unsuported record type O: "\
-                    "Comercial Relationship"), (self.__statistics.O,)))
+                    "Comercial Relationship"), (str(self.__statistics.O,))))
             if self.__statistics.valid == 0:
                 interface.readFile_send_message(_("This file is not a valid FIBDC3 file"))
                 return None
             interface.readFile_end()
-            self._testBudget(self.__budget)
-            return self.__budget
+            self._testBudget(self.__budget, interface)
+            return None
 
-    def _testBudget(self, budget):
-        """testBudget(self,budget)
+    def _testBudget(self, budget, interface):
+        """testBudget(budget)
         
         budget: base.obra object
         Test and repair budget object after read it from bc3 file
         """
         # TODO: more to do here
-        print _("Testing budget ...")
+        print( _("Testing budget ...") )
         # Add price to records without price
         _iter = budget.iter()
         _titlelist = budget.getTitleList()[1]
@@ -2117,7 +2142,8 @@
                     _root = budget.getRecord(budget.getRoot())
                     _price = [0.0, _root.getDate(_len_prices + _index)]
                     budget.addPriceToRecord(_price,_record)
-        print _("End Test")
+            interface.updateGui()
+        print( _("End Test") )
 
     def delete_control_space(self, text):
         text = self.delete_control(text)
@@ -2141,6 +2167,7 @@
     +-- object
       +-- Interface
     Atributes:
+        "endSuccessfully": True/False
         "__progress": The progress percentage
         "__statistics": The record statistics 
     Methods:
@@ -2150,11 +2177,13 @@
         readFile_set_statistics(statistics)
         readFile_end()
         readFile_cancel()
+        updateGui()
         
     """
     def __init__(self):
         self.__progress = 0.0
         self.__statistics = Statistics()
+        self.endSuccessfully = False
 
     def readFile_set_statistics(self, statistics):
         """readFile_set_statistics(statistics)
@@ -2170,9 +2199,9 @@
         
         message: mesage from readFile method
         
-        print message
+        print( message )
         """
-        print message
+        print( message )
 
     def readFile_progress(self, percent):
         """progress(percent)
@@ -2188,14 +2217,26 @@
         
         The readFile method end successfully
         """
-        print self.__statistics
+        self.endSuccessfully == True
+        print(self.__statistics)
+        print("progreso = " + str(self.__progress))
 
     def readFile_cancel(self):
         """readFile_cancel()
         
         The readFile method is canceled
         """
-        print _("Process terminated")
+        self.endSuccessfully == False
+        print( _("Process terminated") )
+        print("progreso = " + str(self.__progress))
+
+    def updateGui(self):
+        """updateGui(self)
+        
+        Some interfaces need update gui while doing some time intensive
+        computation. Do it here.
+        """
+        pass
 
 class Statistics(object):
     """fiebdc.Statistics
@@ -2264,10 +2305,14 @@
             self.time = 0.0
 
     def __str__(self):
+        return self.str().encode("utf8")
+
+    def str(self):
+
         return utils.mapping(_("Time to load: $1 seconds"),
                 (("%.2f" %(self.time)),)) + "\n" + \
                utils.mapping(_("Records/Valid Records: $1/$2"), 
-               (self.records, self.valid)) + "\n" +\
+               (str(self.records), str(self.valid))) + "\n" +\
                "V: %s\n" %(self.V,) + \
                "C: %s\n" %(self.C,) + \
                "D: %s\n" %(self.D,) + \