Changeset 3413 for pykota/trunk/pykota/dumper.py
- Timestamp:
- 09/27/08 22:02:37 (16 years ago)
- Files:
-
- 1 modified
Legend:
- Unmodified
- Added
- Removed
-
pykota/trunk/pykota/dumper.py
r3411 r3413 8 8 # the Free Software Foundation, either version 3 of the License, or 9 9 # (at your option) any later version. 10 # 10 # 11 11 # This program is distributed in the hope that it will be useful, 12 12 # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 14 # GNU General Public License for more details. 15 # 15 # 16 16 # You should have received a copy of the GNU General Public License 17 17 # along with this program. If not, see <http://www.gnu.org/licenses/>. … … 32 32 try : 33 33 import jaxml 34 except ImportError : 34 except ImportError : 35 35 sys.stderr.write("The jaxml Python module is not installed. XML output is disabled.\n") 36 36 sys.stderr.write("Download jaxml from http://www.librelogiciel.com/software/ or from your Debian archive of choice\n") 37 37 hasJAXML = False 38 else : 38 else : 39 39 hasJAXML = True 40 40 … … 45 45 from pykota.errors import PyKotaToolError, PyKotaCommandLineError 46 46 47 class DumPyKota(PyKotaTool) : 47 class DumPyKota(PyKotaTool) : 48 48 """A class for dumpykota.""" 49 49 validdatatypes = { u"history" : N_("History"), … … 54 54 u"gpquotas" : N_("Users Groups Print Quotas"), 55 55 u"payments" : N_("History of Payments"), 56 u"pmembers" : N_("Printers Groups Membership"), 56 u"pmembers" : N_("Printers Groups Membership"), 57 57 u"umembers" : N_("Users Groups Membership"), 58 58 u"billingcodes" : N_("Billing Codes"), … … 64 64 u"xml" : N_("eXtensible Markup Language"), 65 65 u"cups" : N_("CUPS' page_log"), 66 } 66 } 67 67 validfilterkeys = [ "username", 68 68 "groupname", … … 71 71 "hostname", 72 72 "billingcode", 73 "jobid", 73 "jobid", 74 74 "start", 75 75 "end", … … 78 78 """Print Quota Data Dumper.""" 79 79 self.adminOnly(restricted) 80 80 81 81 datatype = options.data 82 82 if datatype not in self.validdatatypes.keys() : 83 83 raise PyKotaCommandLineError, _("Invalid data type '%(datatype)s', see help.") % locals() 84 84 85 85 orderby = options.orderby or [] 86 86 if orderby : … … 91 91 or ((field[0] in ("+", "-")) and field[1:].isalpha()) : 92 92 orderby.append(field) 93 else : 93 else : 94 94 logerr(_("Skipping invalid ordering statement '%(field)s'") % locals()) 95 95 96 96 extractonly = {} 97 if datatype == u"all" : 97 if datatype == u"all" : 98 98 if (options.format != u"xml") or options.sum or arguments : 99 99 self.printInfo(_("Dumping all PyKota's datas forces format to XML, and disables --sum and filters."), "warn") 100 100 options.format = u"xml" 101 101 options.sum = None 102 else : 102 else : 103 103 for filterexp in arguments : 104 104 if filterexp.strip() : … … 107 107 filterkey = filterkey.encode("ASCII", "replace").lower() 108 108 if filterkey not in self.validfilterkeys : 109 raise ValueError 110 except ValueError : 109 raise ValueError 110 except ValueError : 111 111 raise PyKotaCommandLineError, _("Invalid filter value '%(filterexp)s', see help.") % locals() 112 else : 112 else : 113 113 extractonly.update({ filterkey : filtervalue }) 114 114 115 115 format = options.format 116 116 if (format not in self.validformats.keys()) \ … … 118 118 and ((datatype != u"history") or options.sum)) : 119 119 raise PyKotaCommandLineError, _("Invalid format '%(format)s', see help.") % locals() 120 120 121 121 if (format == u"xml") and not hasJAXML : 122 122 raise PyKotaToolError, _("XML output is disabled because the jaxml module is not available.") 123 124 if datatype not in (u"payments", u"history") : 125 if options.sum : 123 124 if datatype not in (u"payments", u"history") : 125 if options.sum : 126 126 raise PyKotaCommandLineError, _("Invalid data type '%(datatype)s' for --sum command line option, see help.") % locals() 127 if extractonly.has_key(u"start") or extractonly.has_key(u"end") : 127 if extractonly.has_key(u"start") or extractonly.has_key(u"end") : 128 128 self.printInfo(_("Invalid filter for the '%(datatype)s' data type.") % locals(), "warn") 129 129 try : 130 130 del extractonly[u"start"] 131 except KeyError : 131 except KeyError : 132 132 pass 133 133 try : 134 134 del extractonly[u"end"] 135 except KeyError : 135 except KeyError : 136 136 pass 137 137 138 138 retcode = 0 139 nbentries = 0 139 nbentries = 0 140 140 mustclose = False 141 141 outfname = options.output.strip().encode(sys.getfilesystemencoding()) 142 if outfname == "-" : 142 if outfname == "-" : 143 143 self.outfile = sys.stdout 144 else : 144 else : 145 145 self.outfile = open(outfname, "w") 146 146 mustclose = True 147 148 if datatype == u"all" : 147 148 if datatype == u"all" : 149 149 # NB : order does matter to allow easier or faster restore 150 150 allentries = [] … … 152 152 "billingcodes", "umembers", "upquotas", \ 153 153 "gpquotas", "payments", "history" ] 154 neededdatatypes = datatypes[:] 154 neededdatatypes = datatypes[:] 155 155 for datatype in datatypes : 156 156 entries = getattr(self.storage, "extract%s" % datatype.title())(extractonly) # We don't care about ordering here … … 158 158 nbentries += len(entries) 159 159 allentries.append(entries) 160 else : 160 else : 161 161 neededdatatypes.remove(datatype) 162 162 retcode = self.dumpXml(allentries, neededdatatypes) 163 else : 163 else : 164 164 datatype = datatype.encode("ASCII") 165 165 format = format.encode("ASCII") … … 168 168 nbentries = len(entries) 169 169 retcode = getattr(self, "dump%s" % format.title())([self.summarizeDatas(entries, datatype, extractonly, options.sum)], [datatype]) 170 170 171 171 if mustclose : 172 172 self.outfile.close() 173 if not nbentries : 173 if not nbentries : 174 174 os.remove(options.output) 175 175 176 176 return retcode 177 178 def summarizeDatas(self, entries, datatype, extractonly, sum=0) : 177 178 def summarizeDatas(self, entries, datatype, extractonly, sum=0) : 179 179 """Transforms the datas into a summarized view (with totals). 180 180 181 181 If sum is false, returns the entries unchanged. 182 """ 182 """ 183 183 if not sum : 184 184 return entries 185 else : 185 else : 186 186 headers = entries[0] 187 187 nbheaders = len(headers) … … 190 190 for i in range(nbheaders) : 191 191 fieldnumber[headers[i]] = i 192 192 193 193 if datatype == "payments" : 194 194 totalize = [ ("amount", float) ] 195 195 keys = [ "username" ] 196 196 else : # elif datatype == "history" 197 totalize = [ ("jobsize", int), 197 totalize = [ ("jobsize", int), 198 198 ("jobprice", float), 199 199 ("jobsizebytes", int), … … 202 202 ] 203 203 keys = [ k for k in ("username", "printername", "hostname", "billingcode") if k in extractonly.keys() ] 204 204 205 205 newentries = [ headers ] 206 206 sortedentries = entries[1:] … … 222 222 for k in keys : 223 223 summary[fieldnumber[k]] = prevkeys[k] 224 for k in totals.keys() : 224 for k in totals.keys() : 225 225 summary[fieldnumber[k]] = totals[k]["convert"](totals[k]["value"]) 226 226 newentries.append(summary) 227 for k in totals.keys() : 227 for k in totals.keys() : 228 228 totals[k]["value"] = totals[k]["convert"](entry[fieldnumber[k]]) 229 else : 230 for k in totals.keys() : 229 else : 230 for k in totals.keys() : 231 231 totals[k]["value"] += totals[k]["convert"](entry[fieldnumber[k]] or 0.0) 232 232 for k in keys : … … 235 235 for k in keys : 236 236 summary[fieldnumber[k]] = prevkeys[k] 237 for k in totals.keys() : 237 for k in totals.keys() : 238 238 summary[fieldnumber[k]] = totals[k]["convert"](totals[k]["value"]) 239 239 newentries.append(summary) 240 240 return newentries 241 242 def dumpWithSeparator(self, separator, allentries) : 241 242 def dumpWithSeparator(self, separator, allentries) : 243 243 """Dumps datas with a separator.""" 244 244 for entries in allentries : … … 252 252 if value is None : 253 253 strvalue = '"None"' # Double quotes around None to prevent spreadsheet from failing 254 else : 254 else : 255 255 strvalue = str(value) 256 256 line.append(strvalue) 257 257 try : 258 258 self.outfile.write("%s\n" % separator.join(line)) 259 except IOError, msg : 259 except IOError, msg : 260 260 self.printInfo("%s : %s" % (_("PyKota data dumper failed : I/O error"), msg), "error") 261 261 return -1 262 return 0 263 264 def dumpCsv(self, allentries, dummy) : 262 return 0 263 264 def dumpCsv(self, allentries, dummy) : 265 265 """Dumps datas with a comma as the separator.""" 266 266 return self.dumpWithSeparator(",", allentries) 267 268 def dumpSsv(self, allentries, dummy) : 267 268 def dumpSsv(self, allentries, dummy) : 269 269 """Dumps datas with a comma as the separator.""" 270 270 return self.dumpWithSeparator(";", allentries) 271 272 def dumpTsv(self, allentries, dummy) : 271 272 def dumpTsv(self, allentries, dummy) : 273 273 """Dumps datas with a comma as the separator.""" 274 274 return self.dumpWithSeparator("\t", allentries) 275 276 def dumpCups(self, allentries, dummy) : 275 276 def dumpCups(self, allentries, dummy) : 277 277 """Dumps history datas as CUPS' page_log format.""" 278 278 months = [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ] … … 282 282 for i in range(len(fieldnames)) : 283 283 fields[fieldnames[i]] = i 284 sortindex = fields["jobdate"] 284 sortindex = fields["jobdate"] 285 285 entries = entries[1:] 286 286 entries.sort(lambda m, n, si=sortindex : cmp(m[si], n[si])) 287 for entry in entries : 287 for entry in entries : 288 288 printername = entry[fields["printername"]] 289 289 username = entry[fields["username"]] … … 305 305 for pagenum in range(1, jobsize+1) : 306 306 line = "%s %s %s [%s] %s %s %s %s" % (printername, username, jobid, jobdate, pagenum, copies, billingcode, hostname) 307 self.outfile.write("%s\n" % line.encode(self.charset, 307 self.outfile.write("%s\n" % line.encode(self.charset, 308 308 "replace")) 309 return 0 310 309 return 0 310 311 311 def dumpXml(self, allentries, datatypes) : 312 312 """Dumps datas as XML.""" … … 326 326 { "'" : "'", \ 327 327 '"' : """ }) 328 except AttributeError : 328 except AttributeError : 329 329 strvalue = str(value) 330 330 # We use 'str' instead of 'unicode' below to be compatible 331 331 # with older releases of PyKota. 332 # The XML dump will contain UTF-8 encoded strings, 332 # The XML dump will contain UTF-8 encoded strings, 333 333 #�not unicode strings anyway. 334 334 x.attribute(strvalue, \ 335 335 type=type(value).__name__.replace("unicode", "str"), \ 336 336 name=header) 337 x._pop() 338 x._pop() 337 x._pop() 338 x._pop() 339 339 x._output(self.outfile) 340 return 0 340 return 0