Skip to content

Enhancement request: allow importer inheritance in CSVMeta #183

@Forrest-T

Description

@Forrest-T

The comment in importers/csvbase.py says "The CSV Importer class needs to inherit from beangulp.Importer". The implementation assumes direct inheritance, but I think we can support indirect inheritance fairly easily.

I ran into this limitation when I tried to model multiple accounts at the same bank with inheritance, which all share the same schema:

class MyBankCSVImporter(csvbase.Importer):
    '''Base class for the CSV schema used by my bank'''
    date = csvbase.Date("Date", "%m/%d/%Y")
    # CSV schema...

class MyBankCSVImporter_Checking(MyBankCSVImporter):
    '''Import data for checking account'''
    def identify(self, filename: str):
        return "checking_1234" in os.path.basename(filename)

class MyBankCSVImporter_Visa(MyBankCSVImporter):
    '''Import data for visa card ending in 5678'''
    def identify(self, filename: str):
        return "visa_5678" in os.path.basename(filename)

CSVReader's read(...) function uses self.columns.items() to dynamically generate a 'Row' type. For the derived classes like MyBankCSVImporter_Checking, self.columns is an empty dictionary because CSVMeta only considers data members added by the most-derived class.

My proposal would be that CSVMeta class should merge the columns added by the base class(es) in between dct and beangulp.Importer. What do you think?

 class CSVMeta(abc.ABCMeta):                                                
     """A metaclass that extracts column specifications from class members  
     and stores them in a columns dictionary keyed by the member name."""   
     def __new__(mcs, name, bases, dct):                                    
         columns = {}                                                       
         others = {}
+        for b in bases:
+            if issubclass(b, beangulp.Importer) and b != beangulp.Importer:
+                columns = b.columns | columns
         for key, value in dct.items():                                     
             if isinstance(value, Column):                                  
                 columns[key] = value                                       
                 continue                                                   
             others[key] = value                                            
         others['columns'] = columns                                        
         return super().__new__(mcs, name, bases, others)                   

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions