Changeset 1240 for pykota/trunk/pykota
- Timestamp:
- 12/27/03 17:49:25 (20 years ago)
- Location:
- pykota/trunk/pykota
- Files:
-
- 14 modified
Legend:
- Unmodified
- Added
- Removed
-
pykota/trunk/pykota/accounter.py
r1239 r1240 22 22 # 23 23 # $Log$ 24 # Revision 1. 8 2003/12/27 15:43:36uid6746725 # S avannah is back online...24 # Revision 1.9 2003/12/27 16:49:25 uid67467 25 # Should be ok now. 26 26 # 27 27 # Revision 1.7 2003/11/25 23:46:40 jalet … … 144 144 return action 145 145 146 def computeJobSize(self) : 147 """Must be overriden in children classes.""" 148 raise RuntimeError, "AccounterBase.computeJobSize() must be overriden !" 149 150 146 151 def openAccounter(kotafilter) : 147 152 """Returns a connection handle to the appropriate accounter.""" … … 152 157 raise PyKotaAccounterError, _("Unsupported accounter backend %s") % backend 153 158 else : 154 return getattr(accounterbackend, "Accounter")(kotafilter, args)159 return accounterbackend.Accounter(kotafilter, args) -
pykota/trunk/pykota/accounters/external.py
r1239 r1240 22 22 # 23 23 # $Log$ 24 # Revision 1.1 1 2003/12/27 15:43:36uid6746725 # S avannah is back online...24 # Revision 1.12 2003/12/27 16:49:25 uid67467 25 # Should be ok now. 26 26 # 27 27 # Revision 1.10 2003/11/23 19:01:36 jalet -
pykota/trunk/pykota/accounters/querying.py
r1239 r1240 22 22 # 23 23 # $Log$ 24 # Revision 1. 9 2003/12/27 15:43:36uid6746725 # S avannah is back online...24 # Revision 1.10 2003/12/27 16:49:25 uid67467 25 # Should be ok now. 26 26 # 27 27 # Revision 1.8 2003/11/21 14:28:46 jalet … … 70 70 """Returns the printer's internal page counter.""" 71 71 global MAXTRIES, TIMETOSLEEP 72 for i in range(MAXTRIES) : 72 self.filter.logdebug("Reading printer's internal page counter...") 73 for dummy in range(MAXTRIES) : 73 74 try : 74 75 counter = self.requester.getPrinterPageCounter(self.filter.printerhostname) … … 82 83 break 83 84 time.sleep(TIMETOSLEEP) 85 self.filter.logdebug("Printer's internal page counter value is : %s" % str(counter)) 84 86 return counter 85 87 -
pykota/trunk/pykota/accounters/stupid.py
r1239 r1240 22 22 # 23 23 # $Log$ 24 # Revision 1. 9 2003/12/27 15:43:36uid6746725 # S avannah is back online...24 # Revision 1.10 2003/12/27 16:49:25 uid67467 25 # Should be ok now. 26 26 # 27 27 # Revision 1.8 2003/11/23 19:01:37 jalet -
pykota/trunk/pykota/logger.py
r1218 r1240 22 22 # 23 23 # $Log$ 24 # Revision 1.11 2003/12/27 16:49:25 uid67467 25 # Should be ok now. 26 # 24 27 # Revision 1.10 2003/11/25 22:37:22 jalet 25 28 # Small code move … … 69 72 __str__ = __repr__ 70 73 71 def openLogger( pykotatool,backend) :74 def openLogger(backend) : 72 75 """Returns the appropriate logger subsystem object.""" 73 76 try : … … 76 79 raise PyKotaLoggingError, _("Unsupported logging subsystem %s") % backend 77 80 else : 78 return getattr(loggingbackend, "Logger")()81 return loggingbackend.Logger() -
pykota/trunk/pykota/reporter.py
r1239 r1240 22 22 # 23 23 # $Log$ 24 # Revision 1. 5 2003/12/27 15:43:36uid6746725 # S avannah is back online...24 # Revision 1.6 2003/12/27 16:49:25 uid67467 25 # Should be ok now. 26 26 # 27 27 # Revision 1.4 2003/12/02 14:40:21 jalet … … 41 41 # 42 42 # 43 44 from mx import DateTime 43 45 44 46 class PyKotaReporterError(Exception): … … 96 98 datelimit = "DENY" 97 99 reached = "+B" 100 elif balance <= self.tool.config.getPoorMan() : 101 datelimit = "WARNING" 102 reached = "?B" 98 103 else : 99 104 datelimit = "" 100 105 reached = "-B" 101 106 else : 102 if quota.DateLimit is not None : 107 if (quota.HardLimit is not None) and (pagecounter >= quota.HardLimit) : 108 datelimit = "DENY" 109 elif (quota.HardLimit is None) and (quota.SoftLimit is not None) and (pagecounter >= quota.SoftLimit) : 110 datelimit = "DENY" 111 elif quota.DateLimit is not None : 103 112 now = DateTime.now() 104 113 datelimit = DateTime.ISO.ParseDateTime(quota.DateLimit) 105 114 if now >= datelimit : 106 115 datelimit = "DENY" 107 elif (quota.HardLimit is not None) and (pagecounter >= quota.HardLimit) :108 datelimit = "DENY"109 elif (quota.HardLimit is None) and (quota.SoftLimit is not None) and (pagecounter >= quota.SoftLimit) :110 datelimit = "DENY"111 116 else : 112 117 datelimit = "" … … 124 129 raise PyKotaReporterError, _("Unsupported reporter backend %s") % reporttype 125 130 else : 126 return getattr(reporterbackend, "Reporter")(tool, printers, ugnames, isgroup)131 return reporterbackend.Reporter(tool, printers, ugnames, isgroup) -
pykota/trunk/pykota/reporters/html.py
r1239 r1240 22 22 # 23 23 # $Log$ 24 # Revision 1. 2 2003/12/27 15:43:36uid6746725 # S avannah is back online...24 # Revision 1.3 2003/12/27 16:49:25 uid67467 25 # Should be ok now. 26 26 # 27 27 # Revision 1.1 2003/12/02 14:41:17 jalet … … 56 56 for (group, grouppquota) in self.tool.storage.getPrinterGroupsAndQuotas(printer, self.ugnames) : 57 57 oddeven += 1 58 if oddeven % 1:58 if oddeven % 2 : 59 59 oddevenclass = "odd" 60 60 else : 61 61 oddevenclass = "even" 62 (pages, money, name, reached, soft, hard, balance, datelimit, lifepagecounter, lifetimepaid) = self.getQuota(group, grouppquota)62 (pages, money, name, reached, pagecounter, soft, hard, balance, datelimit, lifepagecounter, lifetimepaid) = self.getQuota(group, grouppquota) 63 63 self.report.append('<tr class="%s">%s</tr>' % (oddevenclass, "".join(["<td>%s</td>" % h for h in (name, reached, pagecounter, soft, hard, balance, datelimit or " ", lifepagecounter, lifetimepaid)]))) 64 64 total += pages … … 68 68 for (user, userpquota) in self.tool.storage.getPrinterUsersAndQuotas(printer, self.ugnames) : 69 69 oddeven += 1 70 if oddeven % 1:70 if oddeven % 2 : 71 71 oddevenclass = "odd" 72 72 else : -
pykota/trunk/pykota/reporters/text.py
r1235 r1240 22 22 # 23 23 # $Log$ 24 # Revision 1.7 2003/12/27 16:49:25 uid67467 25 # Should be ok now. 26 # 24 27 # Revision 1.6 2003/12/02 14:40:21 jalet 25 28 # Some code refactoring. … … 45 48 # 46 49 47 from mx import DateTime48 49 50 from pykota.reporter import BaseReporter, PyKotaReporterError 50 51 … … 68 69 self.report.append('-' * len(header)) 69 70 for (group, grouppquota) in self.tool.storage.getPrinterGroupsAndQuotas(printer, self.ugnames) : 70 (pages, money, name, reached, soft, hard, balance, datelimit, lifepagecounter, lifetimepaid) = self.getQuota(group, grouppquota)71 (pages, money, name, reached, pagecounter, soft, hard, balance, datelimit, lifepagecounter, lifetimepaid) = self.getQuota(group, grouppquota) 71 72 self.report.append("%-9.9s %s %7i %7s %7s %10s %-10.10s %8i %10s" % (name, reached, pagecounter, soft, hard, balance, datelimit, lifepagecounter, lifetimepaid)) 72 73 total += pages -
pykota/trunk/pykota/requester.py
r1219 r1240 22 22 # 23 23 # $Log$ 24 # Revision 1.11 2003/12/27 16:49:25 uid67467 25 # Should be ok now. 26 # 24 27 # Revision 1.10 2003/11/25 23:46:40 jalet 25 28 # Don't try to verify if module name is valid, Python does this better than us. … … 75 78 raise PyKotaRequesterError, _("Unsupported requester backend %s") % backend 76 79 else : 77 return getattr(requesterbackend, "Requester")(printername, args)80 return requesterbackend.Requester(printername, args) -
pykota/trunk/pykota/storage.py
r1219 r1240 22 22 # 23 23 # $Log$ 24 # Revision 1.29 2003/12/27 16:49:25 uid67467 25 # Should be ok now. 26 # 24 27 # Revision 1.28 2003/11/25 23:46:40 jalet 25 28 # Don't try to verify if module name is valid, Python does this better than us. … … 248 251 self.HardLimit = None 249 252 self.DateLimit = None 253 self.ParentPrintersUserPQuota = (user.Exists and printer.Exists and parent.getParentPrintersUserPQuota(self)) or [] 250 254 251 255 def setDateLimit(self, datelimit) : … … 268 272 def increasePagesUsage(self, nbpages) : 269 273 """Increase the value of used pages and money.""" 270 if nbpages :271 jobprice = (float(self.Printer.PricePerPage or 0.0) * nbpages) + float(self.Printer.PricePerJob or 0.0)272 newpagecounter = int(self.PageCounter or 0) + nbpages273 newlifepagecounter = int(self.LifePageCounter or 0) + nbpages274 self.parent.beginTransaction()275 try:276 if jobprice : # optimization : don't access the database if unneeded.277 self.User.consumeAccountBalance(jobprice)278 self.parent.writeUserPQuotaPagesCounters(self, newpagecounter, newlifepagecounter)279 except PyKotaStorageError, msg :280 self.parent.rollbackTransaction()281 raise PyKotaStorageError, msg282 else :283 self.parent.commitTransaction()284 self.PageCounter = newpagecounter285 self.LifePageCounter = newlifepagecounter274 jobprice = (float(self.Printer.PricePerPage or 0.0) * nbpages) + float(self.Printer.PricePerJob or 0.0) 275 self.parent.beginTransaction() 276 try : 277 if nbpages : 278 self.User.consumeAccountBalance(jobprice) 279 for upq in [ self ] + self.ParentPrintersUserPQuota : 280 newpagecounter = int(upq.PageCounter or 0) + nbpages 281 newlifepagecounter = int(upq.LifePageCounter or 0) + nbpages 282 self.parent.writeUserPQuotaPagesCounters(upq, newpagecounter, newlifepagecounter) 283 upq.PageCounter = newpagecounter 284 upq.LifePageCounter = newlifepagecounter 285 except PyKotaStorageError, msg : 286 self.parent.rollbackTransaction() 287 raise PyKotaStorageError, msg 288 else : 289 self.parent.commitTransaction() 286 290 287 291 class StorageGroupPQuota(StorageObject) : … … 344 348 self.tool.logdebug("Caching enabled.") 345 349 self.caches = { "USERS" : {}, "GROUPS" : {}, "PRINTERS" : {}, "USERPQUOTAS" : {}, "GROUPPQUOTAS" : {}, "JOBS" : {}, "LASTJOBS" : {} } 350 351 def close(self) : 352 """Must be overriden in children classes.""" 353 raise RuntimeError, "BaseStorage.close() must be overriden !" 346 354 347 355 def __del__(self) : … … 441 449 return user.Groups 442 450 451 def getParentPrintersUserPQuota(self, userpquota) : 452 """Returns all user print quota on the printer and its parents.""" 453 upquotas = [ ] 454 for printer in self.getParentPrinters(userpquota.Printer) : 455 upquotas.append(self.getUserPQuota(userpquota.User, printer)) 456 return upquotas 457 443 458 def openConnection(pykotatool) : 444 459 """Returns a connection handle to the appropriate Quota Storage Database.""" … … 454 469 admin = backendinfo["storageadmin"] or backendinfo["storageuser"] 455 470 adminpw = backendinfo["storageadminpw"] or backendinfo["storageuserpw"] 456 return getattr(storagebackend, "Storage")(pykotatool, host, database, admin, adminpw)471 return storagebackend.Storage(pykotatool, host, database, admin, adminpw) 457 472 -
pykota/trunk/pykota/storages/ldapstorage.py
r1228 r1240 22 22 # 23 23 # $Log$ 24 # Revision 1.41 2003/12/27 16:49:25 uid67467 25 # Should be ok now. 26 # 24 27 # Revision 1.40 2003/11/29 22:02:14 jalet 25 28 # Don't try to retrieve the user print quota information if current printer … … 166 169 # 167 170 171 import types 168 172 import time 169 173 import md5 … … 211 215 return md5.md5("%s" % time.time()).hexdigest() 212 216 217 def normalizeFields(self, fields) : 218 """Ensure all items are lists.""" 219 for (k, v) in fields.items() : 220 if type(v) not in (types.TupleType, types.ListType) : 221 if not v : 222 del fields[k] 223 else : 224 fields[k] = [ v ] 225 return fields 226 213 227 def beginTransaction(self) : 214 228 """Starts a transaction.""" … … 237 251 def doAdd(self, dn, fields) : 238 252 """Adds an entry in the LDAP directory.""" 253 fields = self.normalizeFields(fields) 239 254 try : 240 255 self.tool.logdebug("QUERY : ADD(%s, %s)" % (dn, str(fields))) … … 255 270 def doModify(self, dn, fields, ignoreold=1) : 256 271 """Modifies an entry in the LDAP directory.""" 272 fields = self.normalizeFields(fields) 257 273 try : 258 274 oldentry = self.doSearch("objectClass=*", base=dn, scope=ldap.SCOPE_BASE) … … 545 561 return groupsandquotas 546 562 563 def getParentPrinters(self, printer) : 564 """Get all the printer groups this printer is a member of.""" 565 pgroups = [] 566 result = self.doSearch("(&(objectClass=pykotaPrinter)(uniqueMember=%s))" % printer.ident, ["pykotaPrinterName"], base=self.info["printerbase"]) 567 if result : 568 for (printerid, fields) in result : 569 parentprinter = self.getPrinter(fields.get("pykotaPrinterName")[0]) 570 if parentprinter.Exists : 571 pgroups.append(parentprinter) 572 return pgroups 573 547 574 def addPrinter(self, printername) : 548 575 """Adds a printer to the quota storage, returns it.""" … … 679 706 """Sets the date limit permanently for a user print quota.""" 680 707 fields = { 681 "pykotaDateLimit" : "%04i-%02i-%02i %02i:%02i:%02i" % (datelimit.year, datelimit.month, datelimit.day, datelimit.hour, datelimit.minute, datelimit.second),708 "pykotaDateLimit" : datelimit, 682 709 } 683 710 return self.doModify(userpquota.ident, fields) … … 686 713 """Sets the date limit permanently for a group print quota.""" 687 714 fields = { 688 "pykotaDateLimit" : "%04i-%02i-%02i %02i:%02i:%02i" % (datelimit.year, datelimit.month, datelimit.day, datelimit.hour, datelimit.minute, datelimit.second),715 "pykotaDateLimit" : datelimit, 689 716 } 690 717 return self.doModify(grouppquota.ident, fields) -
pykota/trunk/pykota/storages/pgstorage.py
r1228 r1240 22 22 # 23 23 # $Log$ 24 # Revision 1.25 2003/12/27 16:49:25 uid67467 25 # Should be ok now. 26 # 24 27 # Revision 1.24 2003/11/29 22:02:14 jalet 25 28 # Don't try to retrieve the user print quota information if current printer … … 392 395 return groupsandquotas 393 396 397 def getParentPrinters(self, printer) : 398 """Get all the printer groups this printer is a member of.""" 399 pgroups = [] 400 result = self.doSearch("SELECT printername FROM printergroupsmembers JOIN printers ON groupid=id WHERE printerid=%s;" % self.doQuote(printer.ident)) 401 if result : 402 for record in result : 403 parentprinter = self.getPrinter(record.get("printername")) 404 if parentprinter.Exists : 405 pgroups.append(parentprinter) 406 return pgroups 407 394 408 def addPrinter(self, printername) : 395 409 """Adds a printer to the quota storage, returns it.""" … … 468 482 self.doModify("INSERT INTO jobhistory (userid, printerid, jobid, pagecounter, action, jobsize, jobprice, filename, title, copies, options) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)" % (self.doQuote(user.ident), self.doQuote(printer.ident), self.doQuote(jobid), self.doQuote(pagecounter), self.doQuote(action), self.doQuote(jobsize), self.doQuote(jobprice), self.doQuote(filename), self.doQuote(title), self.doQuote(copies), self.doQuote(options))) 469 483 else : 470 self.doModify("INSERT INTO jobhistory (userid, printerid, jobid, pagecounter, action, filename, title, copies, options) VALUES (%s, %s, %s, %s, %s )" % (self.doQuote(user.ident), self.doQuote(printer.ident), self.doQuote(jobid), self.doQuote(pagecounter), self.doQuote(action), self.doQuote(filename), self.doQuote(title), self.doQuote(copies), self.doQuote(options)))484 self.doModify("INSERT INTO jobhistory (userid, printerid, jobid, pagecounter, action, filename, title, copies, options) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s)" % (self.doQuote(user.ident), self.doQuote(printer.ident), self.doQuote(jobid), self.doQuote(pagecounter), self.doQuote(action), self.doQuote(filename), self.doQuote(title), self.doQuote(copies), self.doQuote(options))) 471 485 else : 472 486 # here we explicitly want to reset jobsize to NULL if needed -
pykota/trunk/pykota/tool.py
r1229 r1240 22 22 # 23 23 # $Log$ 24 # Revision 1.65 2003/12/27 16:49:25 uid67467 25 # Should be ok now. 26 # 27 # Revision 1.65 2003/12/06 08:14:38 jalet 28 # Added support for CUPS device uris which contain authentication information. 29 # 24 30 # Revision 1.64 2003/11/29 22:03:17 jalet 25 31 # Some code refactoring work. New code is not used at this time. … … 288 294 self.documentation = doc 289 295 self.config = config.PyKotaConfig("/etc/pykota") 290 self.logger = logger.openLogger(self , self.config.getLoggingBackend())296 self.logger = logger.openLogger(self.config.getLoggingBackend()) 291 297 self.debug = self.config.getDebug() 292 298 self.storage = storage.openConnection(self) … … 574 580 self.sendMessageToAdmin(adminmail, _("Print Quota"), adminmessage) 575 581 if mailto in [ "BOTH", "USER", "EXTERNAL" ] : 582 message = self.config.getHardWarn(printer.Name) 576 583 for user in self.storage.getGroupMembers(group) : 577 584 if mailto != "EXTERNAL" : 578 self.sendMessageToUser(admin, adminmail, user, _("Print Quota Exceeded"), self.config.getHardWarn(printer.Name))585 self.sendMessageToUser(admin, adminmail, user, _("Print Quota Exceeded"), message) 579 586 else : 580 587 self.externalMailTo(arguments, action, user, printer, message) … … 599 606 """Checks a user quota and send him a message if quota is exceeded on current printer.""" 600 607 user = userpquota.User 601 printer = userpquota.Printer 602 admin = self.config.getAdmin(printer.Name) 603 adminmail = self.config.getAdminMail(printer.Name) 604 (mailto, arguments) = self.config.getMailTo(printer.Name) 605 action = self.checkUserPQuota(userpquota) 606 if action.startswith("POLICY_") : 607 action = action[7:] 608 if action == "DENY" : 609 adminmessage = _("Print Quota exceeded for user %s on printer %s") % (user.Name, printer.Name) 610 self.logger.log_message(adminmessage) 611 if mailto in [ "BOTH", "USER", "EXTERNAL" ] : 612 message = self.config.getHardWarn(printer.Name) 613 if mailto != "EXTERNAL" : 614 self.sendMessageToUser(admin, adminmail, user, _("Print Quota Exceeded"), message) 615 else : 616 self.externalMailTo(arguments, action, user, printer, message) 617 if mailto in [ "BOTH", "ADMIN" ] : 618 self.sendMessageToAdmin(adminmail, _("Print Quota"), adminmessage) 619 elif action == "WARN" : 620 adminmessage = _("Print Quota low for user %s on printer %s") % (user.Name, printer.Name) 621 self.logger.log_message(adminmessage) 622 if mailto in [ "BOTH", "USER", "EXTERNAL" ] : 623 if user.LimitBy and (user.LimitBy.lower() == "balance") : 624 message = self.config.getPoorWarn() 625 else : 626 message = self.config.getSoftWarn(printer.Name) 627 if mailto != "EXTERNAL" : 628 self.sendMessageToUser(admin, adminmail, user, _("Print Quota Low"), message) 629 else : 630 self.externalMailTo(arguments, action, user, printer, message) 631 if mailto in [ "BOTH", "ADMIN" ] : 632 self.sendMessageToAdmin(adminmail, _("Print Quota"), adminmessage) 633 return action 608 actions = [] 609 for upq in [userpquota] + userpquota.ParentPrintersUserPQuota : 610 printer = upq.Printer 611 admin = self.config.getAdmin(printer.Name) 612 adminmail = self.config.getAdminMail(printer.Name) 613 (mailto, arguments) = self.config.getMailTo(printer.Name) 614 self.logdebug("Checking quota for user %s on printer %s" % (upq.User.Name, printer.Name)) 615 action = self.checkUserPQuota(upq) 616 self.logdebug("Result is %s" % action) 617 if action.startswith("POLICY_") : 618 action = action[7:] 619 if action == "DENY" : 620 adminmessage = _("Print Quota exceeded for user %s on printer %s") % (user.Name, printer.Name) 621 self.logger.log_message(adminmessage) 622 if mailto in [ "BOTH", "USER", "EXTERNAL" ] : 623 message = self.config.getHardWarn(printer.Name) 624 if mailto != "EXTERNAL" : 625 self.sendMessageToUser(admin, adminmail, user, _("Print Quota Exceeded"), message) 626 else : 627 self.externalMailTo(arguments, action, user, printer, message) 628 if mailto in [ "BOTH", "ADMIN" ] : 629 self.sendMessageToAdmin(adminmail, _("Print Quota"), adminmessage) 630 elif action == "WARN" : 631 adminmessage = _("Print Quota low for user %s on printer %s") % (user.Name, printer.Name) 632 self.logger.log_message(adminmessage) 633 if mailto in [ "BOTH", "USER", "EXTERNAL" ] : 634 if user.LimitBy and (user.LimitBy.lower() == "balance") : 635 message = self.config.getPoorWarn() 636 else : 637 message = self.config.getSoftWarn(printer.Name) 638 if mailto != "EXTERNAL" : 639 self.sendMessageToUser(admin, adminmail, user, _("Print Quota Low"), message) 640 else : 641 self.externalMailTo(arguments, action, user, printer, message) 642 if mailto in [ "BOTH", "ADMIN" ] : 643 self.sendMessageToAdmin(adminmail, _("Print Quota"), adminmessage) 644 actions.append(action) 645 if "DENY" in actions : 646 self.logdebug("Final result is %s" % action) 647 return "DENY" 648 elif "WARN" in actions : 649 self.logdebug("Final result is %s" % action) 650 return "WARN" 651 else : 652 self.logdebug("Final result is %s" % action) 653 return "ALLOW" 634 654 635 655 class PyKotaFilterOrBackend(PyKotaTool) : … … 651 671 self.username = self.username.lower() 652 672 self.preserveinputfile = self.inputfile 673 # 674 # Export internal data to the environment 675 os.environ["PYKOTAUSERNAME"] = str(self.username) 676 os.environ["PYKOTAPRINTERNAME"] = str(self.printername) 677 os.environ["PYKOTACOPIES"] = str(self.copies) 678 os.environ["PYKOTATITLE"] = str(self.title) 679 os.environ["PYKOTAOPTIONS"] = str(self.options) 680 os.environ["PYKOTAFILENAME"] = str(self.inputfile) 681 # 682 # And opens the correct accounter 653 683 self.accounter = accounter.openAccounter(self) 654 684 … … 683 713 while destination.startswith("/") : 684 714 destination = destination[1:] 715 checkauth = destination.split("@", 1) 716 if len(checkauth) == 2 : 717 destination = checkauth[1] 685 718 printerhostname = destination.split("/")[0].split(":")[0] 686 719 return ("CUPS", \ … … 737 770 was returned by the external command. 738 771 """ 739 for passnumberin range(1, 3) :772 for dummy in range(1, 3) : 740 773 printer = self.storage.getPrinter(self.printername) 741 774 user = self.storage.getUser(self.username) -
pykota/trunk/pykota/version.py
r1239 r1240 22 22 # 23 23 24 __version__ = "1.16alpha 17_unofficial"24 __version__ = "1.16alpha20_unofficial" 25 25 26 26 __doc__ = """PyKota : a complete Printing Quota Solution for CUPS and LPRng."""