csvsimple
Very basic CSV utility for Python.
|
00001 ## @package base 00002 # This file contains the implementation of the basic CSV class. 00003 00004 import re 00005 import collections 00006 import sys 00007 00008 if sys.version_info < (3, 0): 00009 raise RuntimeError("Module CSV requires Python 3.0 or greater!") 00010 00011 __all__ = ['Csv'] 00012 00013 00014 ## This class handles CSV data. 00015 # 00016 # This class "partially" implements the following interfaces: 00017 # <ul> 00018 # <li>Sequence.</li> 00019 # <li>Mutable Mapping.</li> 00020 # </ul> 00021 # 00022 # <pre> 00023 # <code> 00024 # csv = Csv(['id', 'first name', 'last name']) 00025 # csv.add([1, 'John', 'Carter']) 00026 # csv.add([2, 'John', 'Dupond']) 00027 # csv.add([3, 'John', 'XXXX']) 00028 # print ("%d" % len(csv)) 00029 # record = csv[1] 00030 # del self.csv[1] 00031 # 00032 # # Print all first names. 00033 # for record in csv: print (csv.getValue(record, 'first name')) 00034 # 00035 # # Get all columns' names. 00036 # v = [] 00037 # for c in csv.keys(): v.append(c) 00038 # 00039 # # name: one column's name. 00040 # # value: all values for this column. 00041 # v = [] 00042 # for name, value in csv.items(): v.append([name, value]) 00043 # 00044 # # v[0]: all value for column "id" 00045 # # v[1]: all value for column "first name" 00046 # # v[2]: all value for column "last name" 00047 # v = [] 00048 # for value in csv.values(): v.append(value) 00049 # </code> 00050 # </pre> 00051 # 00052 # @remark See example on https://github.com/denis-beurive/csvsimple/tree/master/examples 00053 00054 class Csv: 00055 00056 # ----------------------------------------------------------------- 00057 # Class' methods. 00058 # ----------------------------------------------------------------- 00059 00060 ## Default records' formater. 00061 # @param in_record Record to convert into string. 00062 # @param in_header List of columns' names that defines the CSV's structure. 00063 # @return The method returns a string that represents the given record. 00064 # @remark See example on https://github.com/denis-beurive/csvsimple/tree/master/examples 00065 @staticmethod 00066 def __formater(in_record, in_header): 00067 r = [] 00068 for i in range(0, len(in_header)): 00069 name = in_header[i] 00070 value = in_record[i] 00071 s = "%s: %s" % (name.rjust(20), value) 00072 r.append(s) 00073 return "\n".join(r) 00074 00075 00076 ## Return the default records' formater. 00077 # @return The method returns the default records' formater. 00078 # @remark See example on https://github.com/denis-beurive/csvsimple/tree/master/examples 00079 @staticmethod 00080 def getDefaultFormater(): 00081 return Csv.__formater; 00082 00083 # ----------------------------------------------------------------- 00084 # Class' attributes. 00085 # ----------------------------------------------------------------- 00086 00087 ## Triggers selection via simple equality. This value is used by the method select(). 00088 EQUALITY = 1 00089 ## Triggers selection via pattern matching. This value is used by the method select(). 00090 MATCH = 2 00091 ## Triggers selection via function execution. This value is used by the method select(). 00092 EXECUTE = 3 00093 00094 # ----------------------------------------------------------------- 00095 # Constructor. 00096 # ----------------------------------------------------------------- 00097 00098 ## Create a CSV container. 00099 # @param in_header This list contains the names of the columns that define the CSV structure. 00100 # @remark See example on https://github.com/denis-beurive/csvsimple/tree/master/examples 00101 def __init__(self, in_header): 00102 # Check for duplicated columns' names. 00103 c = collections.Counter(in_header) 00104 for column, count in c.items(): 00105 if count > 1: raise RuntimeError('Duplicated columns "%s"!' % column) 00106 00107 # Create instance's attributes. 00108 self.__positions = {} # Association between columns' names and values' positions. 00109 self.__header = in_header # Names of columns. 00110 self.__count = len(in_header) # Number of columns. 00111 self.__records = [] # List of list. 00112 self.__index = 0 # Used for the iterator. 00113 self.__format = Csv.getDefaultFormater() # Default values for string conversion. 00114 00115 # Build the association between columns' names and values' positions. 00116 pos = 0 00117 for name in in_header: 00118 self.__positions[name] = pos 00119 pos += 1 00120 00121 # ----------------------------------------------------------------- 00122 # Public instance's methods. 00123 # ----------------------------------------------------------------- 00124 00125 ## Add a record to the CSV container. 00126 # @param in_record This list contains the values to add. 00127 # @remark See example on https://github.com/denis-beurive/csvsimple/tree/master/examples 00128 def add(self, in_record): 00129 # Make sure that the number of values is correct. 00130 if not len(in_record) == self.__count: raise RuntimeError('Invalid number of values for record (found %d, expected %d)' % (len(in_record), self.__count)) 00131 self.__records.append(in_record) 00132 00133 ## Clear the CVS container. 00134 # @remark See example on https://github.com/denis-beurive/csvsimple/tree/master/examples 00135 def void(self): self.__records = [] 00136 00137 00138 ## Select records fro the CSV container. 00139 # @param in_criterias This dictionary contains selections' criterions. 00140 # <ul> 00141 # <li>Dictionary's key : the name of a column.</li> 00142 # <li>Dictionary's value: this value can be : a simple value, a regular expression or a functioin. 00143 # The type of value depends on the value of parameter "in_action".</li> 00144 # </ul> 00145 # If this parameter is not specified, then the method returns all the records in the container. 00146 # @param in_action This parameter defines the selection's method. 00147 # Three methods are available : 00148 # <ul> 00149 # <li>Csv.EQUALITY (1): Simple equality. 00150 # Dictionary's values must be simple values.</li> 00151 # <li>Csv.MATCH (2): Pattern matching. 00152 # Dictionary's values must be regular expressions.</li> 00153 # <li>Csv.EXECUTE (3): Execution of code. 00154 # Dictionary's values must be functions. 00155 # Function's signature is: def myFuntion(in_value)</li> 00156 # </ul> 00157 # @return The method returns a lust of records. 00158 # @remark See example on https://github.com/denis-beurive/csvsimple/tree/master/examples 00159 def select(self, in_criterias=None, in_action=1): 00160 if in_criterias is None: return self.__records; 00161 res = [] 00162 for record in self.__records: 00163 r = True 00164 for key, value in in_criterias.items(): 00165 if not key in self.__header: raise RuntimeError('Unexpected name (%s) for criteria!' % key) 00166 record_value = record[self.__position(key)] 00167 00168 # Simple comparaison. 00169 if in_action == Csv.EQUALITY: 00170 if not value == record_value: 00171 r = False 00172 break 00173 else: 00174 # Matching. 00175 if in_action == Csv.MATCH: 00176 reg = re.compile(value) 00177 if not re.match(reg, record_value): 00178 r = False 00179 break 00180 else: 00181 # Verify through function's execution. 00182 if in_action == Csv.EXECUTE: 00183 if not value(record_value): 00184 r = False 00185 break 00186 else: 00187 raise RuntimeError('Invalid select method (%d)!' % in_action) 00188 if r: res.append(record) 00189 return res 00190 00191 ## Set a function used to print records. 00192 # @param in_formatter Function with the following signature: def myFunction(in_record, in_header) 00193 # This function must return a string. 00194 # @remark See example on https://github.com/denis-beurive/csvsimple/tree/master/examples 00195 def setFormater(self, in_formatter): 00196 self.__format = in_formatter 00197 00198 ## Return the function used to print records. 00199 # @return Te method returns the function used to print records. 00200 # @remark See example on https://github.com/denis-beurive/csvsimple/tree/master/examples 00201 def getFormater(self): 00202 return self.__format 00203 00204 ## This method returns a list of strings. Each string represents a record. 00205 # @return The method returns a list of strings. Each string represents a record. 00206 # @remark See example on https://github.com/denis-beurive/csvsimple/tree/master/examples 00207 def strs(self): 00208 result = [] 00209 for record in self.__records: 00210 # print ("==> %s" % self.__format(record, self.__header)) 00211 result.append(self.__format(record, self.__header)) 00212 return result 00213 00214 ## Get the value of a given column, for a given record. 00215 # @param in_record The record. 00216 # @param in_column_name Name of the column. 00217 # @return The method returns the value for the given column. 00218 # @remark See example on https://github.com/denis-beurive/csvsimple/tree/master/examples 00219 def getValue(self, in_record, in_column_name): 00220 return in_record[self.__position(in_column_name)] 00221 00222 # ----------------------------------------------------------------- 00223 # Sequence's interface. 00224 # ----------------------------------------------------------------- 00225 00226 def __iter__(self): return self 00227 00228 def __next__(self): 00229 if self.__index < len(self.__records): 00230 self.__index += 1 00231 return self.__records[self.__index-1] 00232 else: 00233 self.__index = 0 00234 raise StopIteration 00235 00236 def __len__(self): return len(self.__records) 00237 00238 def __getitem__(self, in_index): 00239 return self.__records[in_index] 00240 00241 def __setitem__(self, in_index, in_value): 00242 self.__records[in_index] = in_value 00243 00244 def __delitem__(self, in_index): 00245 del self.__records[in_index] 00246 00247 # ----------------------------------------------------------------- 00248 # Mapping's interface 00249 # ----------------------------------------------------------------- 00250 00251 def keys(self): 00252 return self.__header 00253 00254 def items(self): 00255 v = [] 00256 for name in self.__header: 00257 r = [] 00258 for record in self.__records: r.append(record[self.__position(name)]) 00259 v.append([name, r]) 00260 return v 00261 00262 def values(self): 00263 v = [] 00264 for name in self.__header: 00265 r = [] 00266 for record in self.__records: r.append(record[self.__position(name)]) 00267 v.append(r) 00268 return v 00269 00270 # ----------------------------------------------------------------- 00271 # Other methods 00272 # ----------------------------------------------------------------- 00273 00274 def __str__(self): 00275 return "\n".join(self.strs()) 00276 00277 # ----------------------------------------------------------------- 00278 # Private instance's methods. 00279 # ----------------------------------------------------------------- 00280 00281 def __position(self, in_name): 00282 return self.__positions[in_name] 00283 00284