Show
Ignore:
Timestamp:
09/27/08 22:02:37 (16 years ago)
Author:
jerome
Message:

Removed unnecessary spaces at EOL.

Location:
pykota/trunk/pykota/storages
Files:
6 modified

Legend:

Unmodified
Added
Removed
  • pykota/trunk/pykota/storages/__init__.py

    r3411 r3413  
    88# the Free Software Foundation, either version 3 of the License, or 
    99# (at your option) any later version. 
    10 #  
     10# 
    1111# This program is distributed in the hope that it will be useful, 
    1212# but WITHOUT ANY WARRANTY; without even the implied warranty of 
    1313# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
    1414# GNU General Public License for more details. 
    15 #  
     15# 
    1616# You should have received a copy of the GNU General Public License 
    1717# along with this program.  If not, see <http://www.gnu.org/licenses/>. 
  • pykota/trunk/pykota/storages/ldapstorage.py

    r3411 r3413  
    88# the Free Software Foundation, either version 3 of the License, or 
    99# (at your option) any later version. 
    10 #  
     10# 
    1111# This program is distributed in the hope that it will be useful, 
    1212# but WITHOUT ANY WARRANTY; without even the implied warranty of 
    1313# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
    1414# GNU General Public License for more details. 
    15 #  
     15# 
    1616# You should have received a copy of the GNU General Public License 
    1717# along with this program.  If not, see <http://www.gnu.org/licenses/>. 
     
    2323"""This module defines a class to access to an LDAP database backend. 
    2424 
    25 My IANA assigned number, for  
    26 "Conseil Internet & Logiciels Libres, Jerome Alet"  
     25My IANA assigned number, for 
     26"Conseil Internet & Logiciels Libres, Jerome Alet" 
    2727is 16868. Use this as a base to extend the LDAP schema. 
    2828""" 
     
    4242                           StorageJob, StorageLastJob, StorageUserPQuota, \ 
    4343                           StorageGroupPQuota, StorageBillingCode 
    44                             
    45 from pykota.utils import *                            
     44 
     45from pykota.utils import * 
    4646 
    4747try : 
    4848    import ldap 
    4949    import ldap.modlist 
    50 except ImportError :     
     50except ImportError : 
    5151    raise PyKotaStorageError, "This python version (%s) doesn't seem to have the python-ldap module installed correctly." % sys.version.split()[0] 
    52 else :     
     52else : 
    5353    try : 
    5454        from ldap.cidict import cidict 
    55     except ImportError :     
     55    except ImportError : 
    5656        import UserDict 
    5757        sys.stderr.write("ERROR: PyKota requires a newer version of python-ldap. Workaround activated. Please upgrade python-ldap !\n") 
    5858        class cidict(UserDict.UserDict) : 
    5959            pass # Fake it all, and don't care for case insensitivity : users who need it will have to upgrade. 
    60      
     60 
    6161class Storage(BaseStorage) : 
    6262    def __init__(self, pykotatool, host, dbname, user, passwd) : 
     
    6868        self.savedpasswd = passwd 
    6969        self.secondStageInit() 
    70          
    71     def secondStageInit(self) :     
     70 
     71    def secondStageInit(self) : 
    7272        """Second stage initialisation.""" 
    7373        BaseStorage.__init__(self, self.savedtool) 
     
    7777            try : 
    7878                self.tool.logdebug("Trying to open database (host=%s, dbname=%s, user=%s)..." % (self.savedhost, self.saveddbname, self.saveduser)) 
    79                 self.database = ldap.initialize(self.savedhost)  
     79                self.database = ldap.initialize(self.savedhost) 
    8080                if self.info["ldaptls"] : 
    8181                    # we want TLS 
     
    8585                self.database.simple_bind_s(self.saveduser, self.savedpasswd) 
    8686                self.basedn = self.saveddbname 
    87             except ldap.SERVER_DOWN :     
     87            except ldap.SERVER_DOWN : 
    8888                message = "LDAP backend for PyKota seems to be down !" 
    8989                self.tool.printInfo("%s" % message, "error") 
    9090                self.tool.printInfo("Trying again in 2 seconds...", "warn") 
    9191                time.sleep(2) 
    92             except ldap.LDAPError :     
     92            except ldap.LDAPError : 
    9393                message = "Unable to connect to LDAP server %s as %s." % (self.savedhost, self.saveduser) 
    9494                self.tool.printInfo("%s" % message, "error") 
    9595                self.tool.printInfo("Trying again in 2 seconds...", "warn") 
    9696                time.sleep(2) 
    97             else :     
     97            else : 
    9898                self.useldapcache = self.tool.config.getLDAPCache() 
    9999                if self.useldapcache : 
     
    103103                self.tool.logdebug("Database opened (host=%s, dbname=%s, user=%s)" % (self.savedhost, self.saveddbname, self.saveduser)) 
    104104                return # All is fine here. 
    105         raise PyKotaStorageError, message          
    106              
    107     def close(self) :     
     105        raise PyKotaStorageError, message 
     106 
     107    def close(self) : 
    108108        """Closes the database connection.""" 
    109109        if not self.closed : 
     
    111111            self.closed = 1 
    112112            self.tool.logdebug("Database closed.") 
    113          
    114     def genUUID(self) :     
     113 
     114    def genUUID(self) : 
    115115        """Generates an unique identifier. 
    116          
     116 
    117117           TODO : this one is not unique accross several print servers, but should be sufficient for testing. 
    118118        """ 
    119119        return md5.md5("%s-%s" % (time.time(), random.random())).hexdigest() 
    120          
    121     def normalizeFields(self, fields) :     
     120 
     121    def normalizeFields(self, fields) : 
    122122        """Ensure all items are lists.""" 
    123123        for (k, v) in fields.items() : 
     
    125125                if not v : 
    126126                    del fields[k] 
    127                 else :     
     127                else : 
    128128                    fields[k] = [ v ] 
    129         return fields         
    130          
    131     def beginTransaction(self) :     
     129        return fields 
     130 
     131    def beginTransaction(self) : 
    132132        """Starts a transaction.""" 
    133133        self.tool.logdebug("Transaction begins... WARNING : No transactions in LDAP !") 
    134          
    135     def commitTransaction(self) :     
     134 
     135    def commitTransaction(self) : 
    136136        """Commits a transaction.""" 
    137137        self.tool.logdebug("Transaction committed. WARNING : No transactions in LDAP !") 
    138          
    139     def rollbackTransaction(self) :      
     138 
     139    def rollbackTransaction(self) : 
    140140        """Rollbacks a transaction.""" 
    141141        self.tool.logdebug("Transaction aborted. WARNING : No transaction in LDAP !") 
    142          
     142 
    143143    def doSearch(self, key, fields=None, base="", scope=ldap.SCOPE_SUBTREE, flushcache=0) : 
    144144        """Does an LDAP search query.""" 
     
    151151                    # retrieve ALL user defined attributes ("*") 
    152152                    # + the createTimestamp attribute, needed by job history 
    153                     #  
     153                    # 
    154154                    # This may not work with all LDAP servers 
    155                     # but works at least in OpenLDAP (2.1.25)  
     155                    # but works at least in OpenLDAP (2.1.25) 
    156156                    # and iPlanet Directory Server (5.1 SP3) 
    157                     fields = ["*", "createTimestamp"]          
    158                      
     157                    fields = ["*", "createTimestamp"] 
     158 
    159159                if self.useldapcache and (not flushcache) and (scope == ldap.SCOPE_BASE) and self.ldapcache.has_key(base) : 
    160160                    entry = self.ldapcache[base] 
     
    164164                    self.querydebug("QUERY : Filter : %s, BaseDN : %s, Scope : %s, Attributes : %s" % (key, base, scope, fields)) 
    165165                    result = self.database.search_s(base, scope, key, fields) 
    166             except ldap.NO_SUCH_OBJECT, msg :         
     166            except ldap.NO_SUCH_OBJECT, msg : 
    167167                raise PyKotaStorageError, (_("Search base %s doesn't seem to exist. Probable misconfiguration. Please double check /etc/pykota/pykota.conf : %s") % (base, msg)) 
    168             except ldap.LDAPError, msg :     
     168            except ldap.LDAPError, msg : 
    169169                message = (_("Search for %s(%s) from %s(scope=%s) returned no answer.") % (key, fields, base, scope)) + " : %s" % msg 
    170170                self.tool.printInfo("LDAP error : %s" % message, "error") 
     
    172172                self.close() 
    173173                self.secondStageInit() 
    174             else :      
     174            else : 
    175175                self.querydebug("QUERY : Result : %s" % result) 
    176176                result = [ (dn, cidict(attrs)) for (dn, attrs) in result ] 
     
    181181                return result 
    182182        raise PyKotaStorageError, message 
    183              
     183 
    184184    def doAdd(self, dn, fields) : 
    185185        """Adds an entry in the LDAP directory.""" 
     
    192192                self.querydebug("%s" % entry) 
    193193                self.database.add_s(dn, entry) 
    194             except ldap.ALREADY_EXISTS, msg :         
     194            except ldap.ALREADY_EXISTS, msg : 
    195195                raise PyKotaStorageError, "Entry %s already exists : %s" % (dn, msg) 
    196196            except ldap.LDAPError, msg : 
     
    206206                return dn 
    207207        raise PyKotaStorageError, message 
    208              
     208 
    209209    def doDelete(self, dn) : 
    210210        """Deletes an entry from the LDAP directory.""" 
     
    214214                self.querydebug("QUERY : Delete(%s)" % dn) 
    215215                self.database.delete_s(dn) 
    216             except ldap.NO_SUCH_OBJECT :     
     216            except ldap.NO_SUCH_OBJECT : 
    217217                self.tool.printInfo("Entry %s was already missing before we deleted it. This **MAY** be normal." % dn, "info") 
    218218            except ldap.LDAPError, msg : 
     
    222222                self.close() 
    223223                self.secondStageInit() 
    224             else :     
     224            else : 
    225225                if self.useldapcache : 
    226226                    try : 
    227227                        self.querydebug("LDAP cache del %s" % dn) 
    228228                        del self.ldapcache[dn] 
    229                     except KeyError :     
     229                    except KeyError : 
    230230                        pass 
    231                 return         
     231                return 
    232232        raise PyKotaStorageError, message 
    233              
     233 
    234234    def doModify(self, dn, fields, ignoreold=1, flushcache=0) : 
    235235        """Modifies an entry in the LDAP directory.""" 
     
    246246                            if k != "createTimestamp" : 
    247247                                oldentry[k] = v 
    248                     else :     
     248                    else : 
    249249                        self.querydebug("LDAP cache miss %s" % dn) 
    250250                        oldentry = self.doSearch("objectClass=*", base=dn, scope=ldap.SCOPE_BASE)[0][1] 
    251                 else :         
     251                else : 
    252252                    oldentry = self.doSearch("objectClass=*", base=dn, scope=ldap.SCOPE_BASE, flushcache=flushcache)[0][1] 
    253253                for (k, v) in fields.items() : 
     
    255255                        try : 
    256256                            oldvalue = v["convert"](oldentry.get(k, [0])[0]) 
    257                         except ValueError :     
     257                        except ValueError : 
    258258                            self.querydebug("Error converting %s with %s(%s)" % (oldentry.get(k), k, v)) 
    259259                            oldvalue = 0 
    260260                        if v["operator"] == '+' : 
    261261                            newvalue = oldvalue + v["value"] 
    262                         else :     
     262                        else : 
    263263                            newvalue = oldvalue - v["value"] 
    264264                        fields[k] = str(newvalue) 
     
    288288                            try : 
    289289                                del cachedentry[mtyp] 
    290                             except KeyError :     
     290                            except KeyError : 
    291291                                pass 
    292292                    self.querydebug("LDAP cache update %s => %s" % (dn, cachedentry)) 
    293293                return dn 
    294294        raise PyKotaStorageError, message 
    295              
     295 
    296296    def filterNames(self, records, attribute, patterns=None) : 
    297297        """Returns a list of 'attribute' from a list of records. 
    298          
     298 
    299299           Logs any missing attribute. 
    300         """    
     300        """ 
    301301        result = [] 
    302302        for (dn, record) in records : 
     
    309309                    if (not isinstance(patterns, type([]))) and (not isinstance(patterns, type(()))) : 
    310310                        patterns = [ patterns ] 
    311                     if self.tool.matchString(attrval, patterns) :    
     311                    if self.tool.matchString(attrval, patterns) : 
    312312                        result.append(attrval) 
    313                 else :     
     313                else : 
    314314                    result.append(attrval) 
    315         return result         
    316                  
    317     def getAllBillingCodes(self, billingcode=None) :     
     315        return result 
     316 
     317    def getAllBillingCodes(self, billingcode=None) : 
    318318        """Extracts all billing codes or only the billing codes matching the optional parameter.""" 
    319319        ldapfilter = "objectClass=pykotaBilling" 
     
    321321        if result : 
    322322            return self.filterNames(result, "pykotaBillingCode", billingcode) 
    323         else :     
     323        else : 
    324324            return [] 
    325          
    326     def getAllPrintersNames(self, printername=None) :     
     325 
     326    def getAllPrintersNames(self, printername=None) : 
    327327        """Extracts all printer names or only the printers' names matching the optional parameter.""" 
    328328        ldapfilter = "objectClass=pykotaPrinter" 
     
    330330        if result : 
    331331            return self.filterNames(result, "pykotaPrinterName", printername) 
    332         else :     
     332        else : 
    333333            return [] 
    334          
    335     def getAllUsersNames(self, username=None) :     
     334 
     335    def getAllUsersNames(self, username=None) : 
    336336        """Extracts all user names or only the users' names matching the optional parameter.""" 
    337337        ldapfilter = "objectClass=pykotaAccount" 
     
    339339        if result : 
    340340            return self.filterNames(result, "pykotaUserName", username) 
    341         else :     
     341        else : 
    342342            return [] 
    343          
    344     def getAllGroupsNames(self, groupname=None) :     
     343 
     344    def getAllGroupsNames(self, groupname=None) : 
    345345        """Extracts all group names or only the groups' names matching the optional parameter.""" 
    346346        ldapfilter = "objectClass=pykotaGroup" 
     
    348348        if result : 
    349349            return self.filterNames(result, "pykotaGroupName", groupname) 
    350         else :     
     350        else : 
    351351            return [] 
    352          
     352 
    353353    def getUserNbJobsFromHistory(self, user) : 
    354354        """Returns the number of jobs the user has in history.""" 
    355355        result = self.doSearch("(&(pykotaUserName=%s)(objectClass=pykotaJob))" % unicodeToDatabase(user.Name), None, base=self.info["jobbase"]) 
    356356        return len(result) 
    357          
    358     def getUserFromBackend(self, username) :     
     357 
     358    def getUserFromBackend(self, username) : 
    359359        """Extracts user information given its name.""" 
    360360        user = StorageUser(self, username) 
     
    377377                    if user.AccountBalance[0].upper() == "NONE" : 
    378378                        user.AccountBalance = None 
    379                     else :     
     379                    else : 
    380380                        user.AccountBalance = float(user.AccountBalance[0]) 
    381                 user.AccountBalance = user.AccountBalance or 0.0         
     381                user.AccountBalance = user.AccountBalance or 0.0 
    382382                user.LifeTimePaid = fields.get("pykotaLifeTimePaid") 
    383383                user.OverCharge = float(fields.get("pykotaOverCharge", [1.0])[0]) 
     
    385385                    if user.LifeTimePaid[0].upper() == "NONE" : 
    386386                        user.LifeTimePaid = None 
    387                     else :     
     387                    else : 
    388388                        user.LifeTimePaid = float(user.LifeTimePaid[0]) 
    389                 user.LifeTimePaid = user.LifeTimePaid or 0.0         
     389                user.LifeTimePaid = user.LifeTimePaid or 0.0 
    390390                user.Payments = [] 
    391391                for payment in fields.get("pykotaPayments", []) : 
     
    396396                        (date, amount) = payment.split(" # ") 
    397397                        description = "" 
    398                     else :     
     398                    else : 
    399399                        description = databaseToUnicode(base64.decodestring(description)) 
    400                     if amount.endswith(" #") :     
     400                    if amount.endswith(" #") : 
    401401                        amount = amount[:-2] # TODO : should be catched earlier, the bug is above I think 
    402402                    user.Payments.append((date, float(amount), description)) 
    403403            user.Exists = True 
    404404        return user 
    405         
    406     def getGroupFromBackend(self, groupname) :     
     405 
     406    def getGroupFromBackend(self, groupname) : 
    407407        """Extracts group information given its name.""" 
    408408        group = StorageGroup(self, groupname) 
     
    423423            group.Exists = True 
    424424        return group 
    425         
    426     def getPrinterFromBackend(self, printername) :         
     425 
     426    def getPrinterFromBackend(self, printername) : 
    427427        """Extracts printer information given its name : returns first matching printer.""" 
    428428        printer = StoragePrinter(self, printername) 
     
    447447                printer.PassThrough = 0 
    448448            printer.uniqueMember = fields.get("uniqueMember", []) 
    449             printer.Description = databaseToUnicode(fields.get("description", [""])[0])  
     449            printer.Description = databaseToUnicode(fields.get("description", [""])[0]) 
    450450            printer.Exists = True 
    451         return printer     
    452          
    453     def getUserPQuotaFromBackend(self, user, printer) :         
     451        return printer 
     452 
     453    def getUserPQuotaFromBackend(self, user, printer) : 
    454454        """Extracts a user print quota.""" 
    455455        userpquota = StorageUserPQuota(self, user, printer) 
     
    457457            if self.info["userquotabase"].lower() == "user" : 
    458458                base = user.ident 
    459             else :     
     459            else : 
    460460                base = self.info["userquotabase"] 
    461461            result = self.doSearch("(&(objectClass=pykotaUserPQuota)(pykotaUserName=%s)(pykotaPrinterName=%s))" % \ 
     
    473473                    if userpquota.SoftLimit[0].upper() == "NONE" : 
    474474                        userpquota.SoftLimit = None 
    475                     else :     
     475                    else : 
    476476                        userpquota.SoftLimit = int(userpquota.SoftLimit[0]) 
    477477                userpquota.HardLimit = fields.get("pykotaHardLimit") 
     
    479479                    if userpquota.HardLimit[0].upper() == "NONE" : 
    480480                        userpquota.HardLimit = None 
    481                     elif userpquota.HardLimit is not None :     
     481                    elif userpquota.HardLimit is not None : 
    482482                        userpquota.HardLimit = int(userpquota.HardLimit[0]) 
    483483                userpquota.DateLimit = fields.get("pykotaDateLimit") 
    484484                if userpquota.DateLimit is not None : 
    485                     if userpquota.DateLimit[0].upper() == "NONE" :  
     485                    if userpquota.DateLimit[0].upper() == "NONE" : 
    486486                        userpquota.DateLimit = None 
    487                     else :     
     487                    else : 
    488488                        userpquota.DateLimit = userpquota.DateLimit[0] 
    489489                userpquota.MaxJobSize = fields.get("pykotaMaxJobSize") 
     
    491491                    if userpquota.MaxJobSize[0].upper() == "NONE" : 
    492492                        userpquota.MaxJobSize = None 
    493                     else :     
     493                    else : 
    494494                        userpquota.MaxJobSize = int(userpquota.MaxJobSize[0]) 
    495495                userpquota.Exists = True 
    496496        return userpquota 
    497          
    498     def getGroupPQuotaFromBackend(self, group, printer) :         
     497 
     498    def getGroupPQuotaFromBackend(self, group, printer) : 
    499499        """Extracts a group print quota.""" 
    500500        grouppquota = StorageGroupPQuota(self, group, printer) 
     
    502502            if self.info["groupquotabase"].lower() == "group" : 
    503503                base = group.ident 
    504             else :     
     504            else : 
    505505                base = self.info["groupquotabase"] 
    506506            result = self.doSearch("(&(objectClass=pykotaGroupPQuota)(pykotaGroupName=%s)(pykotaPrinterName=%s))" % \ 
     
    515515                    if grouppquota.SoftLimit[0].upper() == "NONE" : 
    516516                        grouppquota.SoftLimit = None 
    517                     else :     
     517                    else : 
    518518                        grouppquota.SoftLimit = int(grouppquota.SoftLimit[0]) 
    519519                grouppquota.HardLimit = fields.get("pykotaHardLimit") 
     
    521521                    if grouppquota.HardLimit[0].upper() == "NONE" : 
    522522                        grouppquota.HardLimit = None 
    523                     else :     
     523                    else : 
    524524                        grouppquota.HardLimit = int(grouppquota.HardLimit[0]) 
    525525                grouppquota.DateLimit = fields.get("pykotaDateLimit") 
    526526                if grouppquota.DateLimit is not None : 
    527                     if grouppquota.DateLimit[0].upper() == "NONE" :  
     527                    if grouppquota.DateLimit[0].upper() == "NONE" : 
    528528                        grouppquota.DateLimit = None 
    529                     else :     
     529                    else : 
    530530                        grouppquota.DateLimit = grouppquota.DateLimit[0] 
    531531                grouppquota.MaxJobSize = fields.get("pykotaMaxJobSize") 
     
    533533                    if grouppquota.MaxJobSize[0].upper() == "NONE" : 
    534534                        grouppquota.MaxJobSize = None 
    535                     else :     
     535                    else : 
    536536                        grouppquota.MaxJobSize = int(grouppquota.MaxJobSize[0]) 
    537537                grouppquota.PageCounter = 0 
     
    548548                                          ["pykotaPageCounter", "pykotaLifePageCounter"], base=base) 
    549549                if result : 
    550                     for userpquota in result :     
     550                    for userpquota in result : 
    551551                        grouppquota.PageCounter += int(userpquota[1].get("pykotaPageCounter", [0])[0] or 0) 
    552552                        grouppquota.LifePageCounter += int(userpquota[1].get("pykotaLifePageCounter", [0])[0] or 0) 
    553553                grouppquota.Exists = True 
    554554        return grouppquota 
    555          
    556     def getPrinterLastJobFromBackend(self, printer) :         
     555 
     556    def getPrinterLastJobFromBackend(self, printer) : 
    557557        """Extracts a printer's last job information.""" 
    558558        lastjob = StorageLastJob(self, printer) 
     
    567567            result = None 
    568568            try : 
    569                 result = self.doSearch("objectClass=pykotaJob", [ "pykotaJobSizeBytes",  
    570                                                                   "pykotaHostName",  
    571                                                                   "pykotaUserName",  
    572                                                                   "pykotaPrinterName",  
    573                                                                   "pykotaJobId",  
    574                                                                   "pykotaPrinterPageCounter",  
    575                                                                   "pykotaJobSize",  
    576                                                                   "pykotaAction",  
    577                                                                   "pykotaJobPrice",  
    578                                                                   "pykotaFileName",  
    579                                                                   "pykotaTitle",  
    580                                                                   "pykotaCopies",  
    581                                                                   "pykotaOptions",  
    582                                                                   "pykotaBillingCode",  
    583                                                                   "pykotaPages",  
    584                                                                   "pykotaMD5Sum",  
     569                result = self.doSearch("objectClass=pykotaJob", [ "pykotaJobSizeBytes", 
     570                                                                  "pykotaHostName", 
     571                                                                  "pykotaUserName", 
     572                                                                  "pykotaPrinterName", 
     573                                                                  "pykotaJobId", 
     574                                                                  "pykotaPrinterPageCounter", 
     575                                                                  "pykotaJobSize", 
     576                                                                  "pykotaAction", 
     577                                                                  "pykotaJobPrice", 
     578                                                                  "pykotaFileName", 
     579                                                                  "pykotaTitle", 
     580                                                                  "pykotaCopies", 
     581                                                                  "pykotaOptions", 
     582                                                                  "pykotaBillingCode", 
     583                                                                  "pykotaPages", 
     584                                                                  "pykotaMD5Sum", 
    585585                                                                  "pykotaPrecomputedJobSize", 
    586586                                                                  "pykotaPrecomputedJobPrice", 
    587                                                                   "createTimestamp" ],  
     587                                                                  "createTimestamp" ], 
    588588                                                                base="cn=%s,%s" % (lastjobident, self.info["jobbase"]), scope=ldap.SCOPE_BASE) 
    589             except PyKotaStorageError :     
    590                 pass # Last job entry exists, but job probably doesn't exist anymore.  
     589            except PyKotaStorageError : 
     590                pass # Last job entry exists, but job probably doesn't exist anymore. 
    591591            if result : 
    592592                fields = result[0][1] 
     
    597597                try : 
    598598                    lastjob.JobSize = int(fields.get("pykotaJobSize", [0])[0]) 
    599                 except ValueError :     
     599                except ValueError : 
    600600                    lastjob.JobSize = None 
    601                 try :     
     601                try : 
    602602                    lastjob.JobPrice = float(fields.get("pykotaJobPrice", [0.0])[0]) 
    603                 except ValueError :     
     603                except ValueError : 
    604604                    lastjob.JobPrice = None 
    605605                lastjob.JobAction = databaseToUnicode(fields.get("pykotaAction", [""])[0]) 
    606                 lastjob.JobFileName = databaseToUnicode(fields.get("pykotaFileName", [""])[0])  
    607                 lastjob.JobTitle = databaseToUnicode(fields.get("pykotaTitle", [""])[0])  
     606                lastjob.JobFileName = databaseToUnicode(fields.get("pykotaFileName", [""])[0]) 
     607                lastjob.JobTitle = databaseToUnicode(fields.get("pykotaTitle", [""])[0]) 
    608608                lastjob.JobCopies = int(fields.get("pykotaCopies", [0])[0]) 
    609                 lastjob.JobOptions = databaseToUnicode(fields.get("pykotaOptions", [""])[0])  
     609                lastjob.JobOptions = databaseToUnicode(fields.get("pykotaOptions", [""])[0]) 
    610610                lastjob.JobHostName = databaseToUnicode(fields.get("pykotaHostName", [""])[0]) 
    611611                lastjob.JobSizeBytes = fields.get("pykotaJobSizeBytes", [0L])[0] 
     
    615615                try : 
    616616                    lastjob.PrecomputedJobSize = int(fields.get("pykotaPrecomputedJobSize", [0])[0]) 
    617                 except ValueError :     
     617                except ValueError : 
    618618                    lastjob.PrecomputedJobSize = None 
    619                 try :     
     619                try : 
    620620                    lastjob.PrecomputedJobPrice = float(fields.get("pykotaPrecomputedJobPrice", [0.0])[0]) 
    621                 except ValueError :     
     621                except ValueError : 
    622622                    lastjob.PrecomputedJobPrice = None 
    623623                if lastjob.JobTitle == lastjob.JobFileName == lastjob.JobOptions == u"hidden" : 
     
    628628                lastjob.Exists = True 
    629629        return lastjob 
    630          
    631     def getGroupMembersFromBackend(self, group) :         
     630 
     631    def getGroupMembersFromBackend(self, group) : 
    632632        """Returns the group's members list.""" 
    633633        groupmembers = [] 
     
    640640            for username in result[0][1].get(self.info["groupmembers"], []) : 
    641641                groupmembers.append(self.getUser(databaseToUnicode(username))) 
    642         return groupmembers         
    643          
    644     def getUserGroupsFromBackend(self, user) :         
     642        return groupmembers 
     643 
     644    def getUserGroupsFromBackend(self, user) : 
    645645        """Returns the user's groups list.""" 
    646646        groups = [] 
     
    660660                    if group.LimitBy is not None : 
    661661                        group.LimitBy = databaseToUnicode(group.LimitBy[0]) 
    662                     else :     
     662                    else : 
    663663                        group.LimitBy = u"quota" 
    664664                    group.AccountBalance = 0.0 
     
    671671                    self.cacheEntry("GROUPS", group.Name, group) 
    672672                groups.append(group) 
    673         return groups         
    674          
    675     def getParentPrintersFromBackend(self, printer) :     
     673        return groups 
     674 
     675    def getParentPrintersFromBackend(self, printer) : 
    676676        """Get all the printer groups this printer is a member of.""" 
    677677        pgroups = [] 
     
    687687                        pgroups.append(parentprinter) 
    688688        return pgroups 
    689          
     689 
    690690    def getMatchingPrinters(self, printerpattern) : 
    691691        """Returns the list of all printers for which name matches a certain pattern.""" 
     
    699699            try : 
    700700                patdict = {}.fromkeys(patterns) 
    701             except AttributeError :     
     701            except AttributeError : 
    702702                # Python v2.2 or earlier 
    703703                patdict = {} 
     
    718718                        printer.PassThrough = 0 
    719719                    printer.uniqueMember = fields.get("uniqueMember", []) 
    720                     printer.Description = databaseToUnicode(fields.get("description", [""])[0])  
     720                    printer.Description = databaseToUnicode(fields.get("description", [""])[0]) 
    721721                    printer.Exists = True 
    722722                    printers.append(printer) 
    723723                    self.cacheEntry("PRINTERS", printer.Name, printer) 
    724         return printers         
    725          
     724        return printers 
     725 
    726726    def getMatchingUsers(self, userpattern) : 
    727727        """Returns the list of all users for which name matches a certain pattern.""" 
     
    735735            try : 
    736736                patdict = {}.fromkeys(patterns) 
    737             except AttributeError :     
     737            except AttributeError : 
    738738                # Python v2.2 or earlier 
    739739                patdict = {} 
     
    747747                    user.Email = databaseToUnicode(fields.get(self.info["usermail"], [None])[0]) 
    748748                    user.LimitBy = databaseToUnicode(fields.get("pykotaLimitBy", ["quota"])[0]) 
    749                     user.Description = databaseToUnicode(fields.get("description", [""])[0])  
     749                    user.Description = databaseToUnicode(fields.get("description", [""])[0]) 
    750750                    uname = unicodeToDatabase(username) 
    751751                    result = self.doSearch("(&(objectClass=pykotaAccountBalance)(|(pykotaUserName=%s)(%s=%s)))" % \ 
     
    763763                            if user.AccountBalance[0].upper() == "NONE" : 
    764764                                user.AccountBalance = None 
    765                             else :     
     765                            else : 
    766766                                user.AccountBalance = float(user.AccountBalance[0]) 
    767                         user.AccountBalance = user.AccountBalance or 0.0         
     767                        user.AccountBalance = user.AccountBalance or 0.0 
    768768                        user.LifeTimePaid = fields.get("pykotaLifeTimePaid") 
    769769                        if user.LifeTimePaid is not None : 
    770770                            if user.LifeTimePaid[0].upper() == "NONE" : 
    771771                                user.LifeTimePaid = None 
    772                             else :     
     772                            else : 
    773773                                user.LifeTimePaid = float(user.LifeTimePaid[0]) 
    774                         user.LifeTimePaid = user.LifeTimePaid or 0.0         
     774                        user.LifeTimePaid = user.LifeTimePaid or 0.0 
    775775                        user.Payments = [] 
    776776                        for payment in fields.get("pykotaPayments", []) : 
     
    781781                                (date, amount) = payment.split(" # ") 
    782782                                description = "" 
    783                             else :     
     783                            else : 
    784784                                description = databaseToUnicode(base64.decodestring(description)) 
    785                             if amount.endswith(" #") :     
     785                            if amount.endswith(" #") : 
    786786                                amount = amount[:-2] # TODO : should be catched earlier, the bug is above I think 
    787787                            user.Payments.append((date, float(amount), description)) 
     
    789789                    users.append(user) 
    790790                    self.cacheEntry("USERS", user.Name, user) 
    791         return users        
    792          
     791        return users 
     792 
    793793    def getMatchingGroups(self, grouppattern) : 
    794794        """Returns the list of all groups for which name matches a certain pattern.""" 
     
    802802            try : 
    803803                patdict = {}.fromkeys(patterns) 
    804             except AttributeError :     
     804            except AttributeError : 
    805805                # Python v2.2 or earlier 
    806806                patdict = {} 
     
    812812                    group = StorageGroup(self, groupname) 
    813813                    group.ident = groupid 
    814                     group.Name = databaseToUnicode(fields.get("pykotaGroupName", [groupname])[0])  
     814                    group.Name = databaseToUnicode(fields.get("pykotaGroupName", [groupname])[0]) 
    815815                    group.LimitBy = databaseToUnicode(fields.get("pykotaLimitBy", ["quota"])[0]) 
    816                     group.Description = databaseToUnicode(fields.get("description", [""])[0])  
     816                    group.Description = databaseToUnicode(fields.get("description", [""])[0]) 
    817817                    group.AccountBalance = 0.0 
    818818                    group.LifeTimePaid = 0.0 
     
    825825                    self.cacheEntry("GROUPS", group.Name, group) 
    826826        return groups 
    827          
    828     def getPrinterUsersAndQuotas(self, printer, names=["*"]) :         
     827 
     828    def getPrinterUsersAndQuotas(self, printer, names=["*"]) : 
    829829        """Returns the list of users who uses a given printer, along with their quotas.""" 
    830830        usersandquotas = [] 
     
    851851                    if userpquota.SoftLimit[0].upper() == "NONE" : 
    852852                        userpquota.SoftLimit = None 
    853                     else :     
     853                    else : 
    854854                        userpquota.SoftLimit = int(userpquota.SoftLimit[0]) 
    855855                userpquota.HardLimit = fields.get("pykotaHardLimit") 
     
    857857                    if userpquota.HardLimit[0].upper() == "NONE" : 
    858858                        userpquota.HardLimit = None 
    859                     elif userpquota.HardLimit is not None :     
     859                    elif userpquota.HardLimit is not None : 
    860860                        userpquota.HardLimit = int(userpquota.HardLimit[0]) 
    861861                userpquota.DateLimit = fields.get("pykotaDateLimit") 
    862862                if userpquota.DateLimit is not None : 
    863                     if userpquota.DateLimit[0].upper() == "NONE" :  
     863                    if userpquota.DateLimit[0].upper() == "NONE" : 
    864864                        userpquota.DateLimit = None 
    865                     else :     
     865                    else : 
    866866                        userpquota.DateLimit = userpquota.DateLimit[0] 
    867867                userpquota.Exists = True 
    868868                usersandquotas.append((user, userpquota)) 
    869869                self.cacheEntry("USERPQUOTAS", "%s@%s" % (user.Name, printer.Name), userpquota) 
    870         usersandquotas.sort(lambda x, y : cmp(x[0].Name, y[0].Name))             
     870        usersandquotas.sort(lambda x, y : cmp(x[0].Name, y[0].Name)) 
    871871        return usersandquotas 
    872                  
    873     def getPrinterGroupsAndQuotas(self, printer, names=["*"]) :         
     872 
     873    def getPrinterGroupsAndQuotas(self, printer, names=["*"]) : 
    874874        """Returns the list of groups which uses a given printer, along with their quotas.""" 
    875875        groupsandquotas = [] 
     
    889889                grouppquota = self.getGroupPQuota(group, printer) 
    890890                groupsandquotas.append((group, grouppquota)) 
    891         groupsandquotas.sort(lambda x, y : cmp(x[0].Name, y[0].Name))             
     891        groupsandquotas.sort(lambda x, y : cmp(x[0].Name, y[0].Name)) 
    892892        return groupsandquotas 
    893          
     893 
    894894    def addPrinter(self, printer) : 
    895895        """Adds a printer to the quota storage, returns the old value if it already exists.""" 
     
    907907                   "pykotaPricePerPage" : str(printer.PricePerPage or 0.0), 
    908908                   "pykotaPricePerJob" : str(printer.PricePerJob or 0.0), 
    909                  }  
     909                 } 
    910910        dn = "%s=%s,%s" % (self.info["printerrdn"], printername, self.info["printerbase"]) 
    911911        self.doAdd(dn, fields) 
    912912        printer.isDirty = False 
    913913        return None # the entry created doesn't need further modification 
    914          
    915     def addUser(self, user) :         
     914 
     915    def addUser(self, user) : 
    916916        """Adds a user to the quota storage, returns the old value if it already exists.""" 
    917917        oldentry = self.getUser(user.Name) 
     
    924924                       "description" : unicodeToDatabase(user.Description or ""), 
    925925                       self.info["usermail"] : unicodeToDatabase(user.Email or ""), 
    926                     }    
    927                         
     926                    } 
     927 
    928928        mustadd = 1 
    929929        if self.info["newuser"].lower() != 'below' : 
     
    943943                fields.update({ "pykotaBalance" : str(user.AccountBalance or 0.0), 
    944944                                "pykotaOverCharge" : str(user.OverCharge), 
    945                                 "pykotaLifeTimePaid" : str(user.LifeTimePaid or 0.0), })    
     945                                "pykotaLifeTimePaid" : str(user.LifeTimePaid or 0.0), }) 
    946946                self.doModify(dn, fields) 
    947947                mustadd = 0 
    948948            else : 
    949949                message = _("Unable to find an existing objectClass %s entry with %s=%s to attach pykotaAccount objectClass") % (where, self.info["userrdn"], user.Name) 
    950                 if action.lower() == "warn" :     
     950                if action.lower() == "warn" : 
    951951                    self.tool.printInfo(_("%s. A new entry will be created instead.") % message, "warn") 
    952952                else : # 'fail' or incorrect setting 
    953953                    raise PyKotaStorageError, "%s. Action aborted. Please check your configuration." % message 
    954                  
     954 
    955955        if mustadd : 
    956             if self.info["userbase"] == self.info["balancebase"] :             
     956            if self.info["userbase"] == self.info["balancebase"] : 
    957957                fields = { self.info["userrdn"] : uname, 
    958958                           "objectClass" : ["pykotaObject", "pykotaAccount", "pykotaAccountBalance"], 
     
    960960                           "pykotaBalance" : str(user.AccountBalance or 0.0), 
    961961                           "pykotaOverCharge" : str(user.OverCharge), 
    962                            "pykotaLifeTimePaid" : str(user.LifeTimePaid or 0.0),  
    963                          }  
    964             else :              
     962                           "pykotaLifeTimePaid" : str(user.LifeTimePaid or 0.0), 
     963                         } 
     964            else : 
    965965                fields = { self.info["userrdn"] : uname, 
    966966                           "objectClass" : ["pykotaObject", "pykotaAccount"], 
    967967                           "cn" : uname, 
    968                          }  
    969             fields.update(newfields)          
     968                         } 
     969            fields.update(newfields) 
    970970            dn = "%s=%s,%s" % (self.info["userrdn"], uname, self.info["userbase"]) 
    971971            self.doAdd(dn, fields) 
    972             if self.info["userbase"] != self.info["balancebase"] :             
     972            if self.info["userbase"] != self.info["balancebase"] : 
    973973                fields = { self.info["balancerdn"] : uname, 
    974974                           "objectClass" : ["pykotaObject", "pykotaAccountBalance"], 
     
    976976                           "pykotaBalance" : str(user.AccountBalance or 0.0), 
    977977                           "pykotaOverCharge" : str(user.OverCharge), 
    978                            "pykotaLifeTimePaid" : str(user.LifeTimePaid or 0.0),   
    979                          }  
     978                           "pykotaLifeTimePaid" : str(user.LifeTimePaid or 0.0), 
     979                         } 
    980980                dn = "%s=%s,%s" % (self.info["balancerdn"], uname, self.info["balancebase"]) 
    981981                self.doAdd(dn, fields) 
     
    987987        user.isDirty = False 
    988988        return None # the entry created doesn't need further modification 
    989          
    990     def addGroup(self, group) :         
     989 
     990    def addGroup(self, group) : 
    991991        """Adds a group to the quota storage, returns the old value if it already exists.""" 
    992992        oldentry = self.getGroup(group.Name) 
     
    994994            return oldentry # we return the existing entry 
    995995        gname = unicodeToDatabase(group.Name) 
    996         newfields = {  
     996        newfields = { 
    997997                      "pykotaGroupName" : gname, 
    998998                      "pykotaLimitBy" : unicodeToDatabase(group.LimitBy or u"quota"), 
    999999                      "description" : unicodeToDatabase(group.Description or "") 
    1000                     }  
     1000                    } 
    10011001        mustadd = 1 
    10021002        if self.info["newgroup"].lower() != 'below' : 
     
    10181018            else : 
    10191019                message = _("Unable to find an existing entry to attach pykotaGroup objectclass %s") % group.Name 
    1020                 if action.lower() == "warn" :     
     1020                if action.lower() == "warn" : 
    10211021                    self.tool.printInfo("%s. A new entry will be created instead." % message, "warn") 
    10221022                else : # 'fail' or incorrect setting 
    10231023                    raise PyKotaStorageError, "%s. Action aborted. Please check your configuration." % message 
    1024                  
     1024 
    10251025        if mustadd : 
    10261026            fields = { self.info["grouprdn"] : gname, 
    10271027                       "objectClass" : ["pykotaObject", "pykotaGroup"], 
    10281028                       "cn" : gname, 
    1029                      }  
    1030             fields.update(newfields)          
     1029                     } 
     1030            fields.update(newfields) 
    10311031            dn = "%s=%s,%s" % (self.info["grouprdn"], gname, self.info["groupbase"]) 
    10321032            self.doAdd(dn, fields) 
    10331033        group.isDirty = False 
    10341034        return None # the entry created doesn't need further modification 
    1035          
    1036     def addUserToGroup(self, user, group) :     
     1035 
     1036    def addUserToGroup(self, user, group) : 
    10371037        """Adds an user to a group.""" 
    10381038        if user.Name not in [u.Name for u in self.getGroupMembers(group)] : 
    1039             result = self.doSearch("objectClass=pykotaGroup", None, base=group.ident, scope=ldap.SCOPE_BASE)     
     1039            result = self.doSearch("objectClass=pykotaGroup", None, base=group.ident, scope=ldap.SCOPE_BASE) 
    10401040            if result : 
    10411041                fields = result[0][1] 
     
    10451045                self.doModify(group.ident, fields) 
    10461046                group.Members.append(user) 
    1047                  
    1048     def delUserFromGroup(self, user, group) :     
     1047 
     1048    def delUserFromGroup(self, user, group) : 
    10491049        """Removes an user from a group.""" 
    10501050        if user.Name in [u.Name for u in self.getGroupMembers(group)] : 
     
    10541054                if not fields.has_key(self.info["groupmembers"]) : 
    10551055                    fields[self.info["groupmembers"]] = [] 
    1056                 try :     
     1056                try : 
    10571057                    fields[self.info["groupmembers"]].remove(unicodeToDatabase(user.Name)) 
    10581058                except ValueError : 
     
    10611061                    self.doModify(group.ident, fields) 
    10621062                    group.Members.remove(user) 
    1063                  
     1063 
    10641064    def addUserPQuota(self, upq) : 
    10651065        """Initializes a user print quota on a printer.""" 
     
    10821082                   "pykotaWarnCount" : str(upq.WarnCount or 0), 
    10831083                   "pykotaMaxJobSize" : str(upq.MaxJobSize or 0), 
    1084                  }  
     1084                 } 
    10851085        if self.info["userquotabase"].lower() == "user" : 
    10861086            dn = "cn=%s,%s" % (uuid, upq.User.ident) 
    1087         else :     
     1087        else : 
    10881088            dn = "cn=%s,%s" % (uuid, self.info["userquotabase"]) 
    10891089        self.doAdd(dn, fields) 
    10901090        upq.isDirty = False 
    10911091        return None # the entry created doesn't need further modification 
    1092          
     1092 
    10931093    def addGroupPQuota(self, gpq) : 
    10941094        """Initializes a group print quota on a printer.""" 
     
    11041104                   "pykotaPrinterName" : pname, 
    11051105                   "pykotaDateLimit" : "None", 
    1106                  }  
     1106                 } 
    11071107        if self.info["groupquotabase"].lower() == "group" : 
    11081108            dn = "cn=%s,%s" % (uuid, gpq.Group.ident) 
    1109         else :     
     1109        else : 
    11101110            dn = "cn=%s,%s" % (uuid, self.info["groupquotabase"]) 
    11111111        self.doAdd(dn, fields) 
    11121112        gpq.isDirty = False 
    11131113        return None # the entry created doesn't need further modification 
    1114          
    1115     def savePrinter(self, printer) :     
     1114 
     1115    def savePrinter(self, printer) : 
    11161116        """Saves the printer to the database in a single operation.""" 
    11171117        fields = { 
     
    11231123                 } 
    11241124        self.doModify(printer.ident, fields) 
    1125          
     1125 
    11261126    def saveUser(self, user) : 
    11271127        """Saves the user to the database in a single operation.""" 
    11281128        newfields = { 
    11291129                       "pykotaLimitBy" : unicodeToDatabase(user.LimitBy or u"quota"), 
    1130                        "description" : unicodeToDatabase(user.Description or ""),  
     1130                       "description" : unicodeToDatabase(user.Description or ""), 
    11311131                       self.info["usermail"] : user.Email or "", 
    1132                     }    
     1132                    } 
    11331133        self.doModify(user.ident, newfields) 
    1134          
     1134 
    11351135        newfields = { "pykotaBalance" : str(user.AccountBalance or 0.0), 
    1136                       "pykotaLifeTimePaid" : str(user.LifeTimePaid or 0.0),  
     1136                      "pykotaLifeTimePaid" : str(user.LifeTimePaid or 0.0), 
    11371137                      "pykotaOverCharge" : str(user.OverCharge), 
    11381138                    } 
    11391139        self.doModify(user.idbalance, newfields) 
    1140          
     1140 
    11411141    def saveGroup(self, group) : 
    11421142        """Saves the group to the database in a single operation.""" 
    11431143        newfields = { 
    11441144                       "pykotaLimitBy" : unicodeToDatabase(group.LimitBy or u"quota"), 
    1145                        "description" : unicodeToDatabase(group.Description or ""),  
    1146                     }    
     1145                       "description" : unicodeToDatabase(group.Description or ""), 
     1146                    } 
    11471147        self.doModify(group.ident, newfields) 
    1148          
    1149     def writeUserPQuotaDateLimit(self, userpquota, datelimit) :     
     1148 
     1149    def writeUserPQuotaDateLimit(self, userpquota, datelimit) : 
    11501150        """Sets the date limit permanently for a user print quota.""" 
    11511151        fields = { 
     
    11531153                 } 
    11541154        return self.doModify(userpquota.ident, fields) 
    1155              
    1156     def writeGroupPQuotaDateLimit(self, grouppquota, datelimit) :     
     1155 
     1156    def writeGroupPQuotaDateLimit(self, grouppquota, datelimit) : 
    11571157        """Sets the date limit permanently for a group print quota.""" 
    11581158        fields = { 
     
    11601160                 } 
    11611161        return self.doModify(grouppquota.ident, fields) 
    1162          
    1163     def increaseUserPQuotaPagesCounters(self, userpquota, nbpages) :     
     1162 
     1163    def increaseUserPQuotaPagesCounters(self, userpquota, nbpages) : 
    11641164        """Increase page counters for a user print quota.""" 
    11651165        fields = { 
     
    11671167                   "pykotaLifePageCounter" : { "operator" : "+", "value" : nbpages, "convert" : int }, 
    11681168                 } 
    1169         return self.doModify(userpquota.ident, fields)          
    1170          
    1171     def decreaseUserAccountBalance(self, user, amount) :     
     1169        return self.doModify(userpquota.ident, fields) 
     1170 
     1171    def decreaseUserAccountBalance(self, user, amount) : 
    11721172        """Decreases user's account balance from an amount.""" 
    11731173        fields = { 
    11741174                   "pykotaBalance" : { "operator" : "-", "value" : amount, "convert" : float }, 
    11751175                 } 
    1176         return self.doModify(user.idbalance, fields, flushcache=1)          
    1177         
     1176        return self.doModify(user.idbalance, fields, flushcache=1) 
     1177 
    11781178    def writeNewPayment(self, user, amount, comment="") : 
    11791179        """Adds a new payment to the payments history.""" 
     
    11851185                   "pykotaPayments" : payments, 
    11861186                 } 
    1187         return self.doModify(user.idbalance, fields)          
    1188          
    1189     def writeLastJobSize(self, lastjob, jobsize, jobprice) :         
     1187        return self.doModify(user.idbalance, fields) 
     1188 
     1189    def writeLastJobSize(self, lastjob, jobsize, jobprice) : 
    11901190        """Sets the last job's size permanently.""" 
    11911191        fields = { 
     
    11931193                   "pykotaJobPrice" : str(jobprice), 
    11941194                 } 
    1195         self.doModify(lastjob.ident, fields)          
    1196          
     1195        self.doModify(lastjob.ident, fields) 
     1196 
    11971197    def writeJobNew(self, printer, user, jobid, pagecounter, action, jobsize=None, jobprice=None, filename=None, title=None, copies=None, options=None, clienthost=None, jobsizebytes=None, jobmd5sum=None, jobpages=None, jobbilling=None, precomputedsize=None, precomputedprice=None) : 
    11981198        """Adds a job in a printer's history.""" 
     
    12021202            uuid = self.genUUID() 
    12031203            dn = "cn=%s,%s" % (uuid, self.info["jobbase"]) 
    1204         else :     
     1204        else : 
    12051205            uuid = printer.LastJob.ident[3:].split(",")[0] 
    12061206            dn = printer.LastJob.ident 
    1207         if self.privacy :     
     1207        if self.privacy : 
    12081208            # For legal reasons, we want to hide the title, filename and options 
    12091209            title = filename = options = u"hidden" 
     
    12161216                   "pykotaPrinterPageCounter" : str(pagecounter), 
    12171217                   "pykotaAction" : unicodeToDatabase(action), 
    1218                    "pykotaFileName" : ((filename is None) and "None") or unicodeToDatabase(filename),  
    1219                    "pykotaTitle" : ((title is None) and "None") or unicodeToDatabase(title),  
    1220                    "pykotaCopies" : str(copies),  
    1221                    "pykotaOptions" : ((options is None) and "None") or unicodeToDatabase(options),  
    1222                    "pykotaHostName" : str(clienthost),  
     1218                   "pykotaFileName" : ((filename is None) and "None") or unicodeToDatabase(filename), 
     1219                   "pykotaTitle" : ((title is None) and "None") or unicodeToDatabase(title), 
     1220                   "pykotaCopies" : str(copies), 
     1221                   "pykotaOptions" : ((options is None) and "None") or unicodeToDatabase(options), 
     1222                   "pykotaHostName" : str(clienthost), 
    12231223                   "pykotaJobSizeBytes" : str(jobsizebytes), 
    12241224                   "pykotaMD5Sum" : unicodeToDatabase(jobmd5sum), 
     
    12291229                 } 
    12301230        if (not self.disablehistory) or (not printer.LastJob.Exists) : 
    1231             if jobsize is not None :          
     1231            if jobsize is not None : 
    12321232                fields.update({ "pykotaJobSize" : str(jobsize), "pykotaJobPrice" : str(jobprice) }) 
    12331233            self.doAdd(dn, fields) 
    1234         else :     
     1234        else : 
    12351235            # here we explicitly want to reset jobsize to 'None' if needed 
    12361236            fields.update({ "pykotaJobSize" : str(jobsize), "pykotaJobPrice" : str(jobprice) }) 
    12371237            self.doModify(dn, fields) 
    1238              
     1238 
    12391239        if printer.LastJob.Exists : 
    12401240            fields = { 
    12411241                       "pykotaLastJobIdent" : uuid, 
    12421242                     } 
    1243             self.doModify(printer.LastJob.lastjobident, fields)          
    1244         else :     
     1243            self.doModify(printer.LastJob.lastjobident, fields) 
     1244        else : 
    12451245            lastjuuid = self.genUUID() 
    12461246            lastjdn = "cn=%s,%s" % (lastjuuid, self.info["lastjobbase"]) 
     
    12501250                       "pykotaPrinterName" : pname, 
    12511251                       "pykotaLastJobIdent" : uuid, 
    1252                      }   
    1253             self.doAdd(lastjdn, fields)           
    1254              
     1252                     } 
     1253            self.doAdd(lastjdn, fields) 
     1254 
    12551255    def saveUserPQuota(self, userpquota) : 
    12561256        """Saves an user print quota entry.""" 
    1257         fields = {  
     1257        fields = { 
    12581258                   "pykotaSoftLimit" : str(userpquota.SoftLimit), 
    12591259                   "pykotaHardLimit" : str(userpquota.HardLimit), 
     
    12651265                 } 
    12661266        self.doModify(userpquota.ident, fields) 
    1267          
     1267 
    12681268    def writeUserPQuotaWarnCount(self, userpquota, warncount) : 
    12691269        """Sets the warn counter value for a user quota.""" 
    1270         fields = {  
     1270        fields = { 
    12711271                   "pykotaWarnCount" : str(warncount or 0), 
    12721272                 } 
    12731273        self.doModify(userpquota.ident, fields) 
    1274          
     1274 
    12751275    def increaseUserPQuotaWarnCount(self, userpquota) : 
    12761276        """Increases the warn counter value for a user quota.""" 
     
    12781278                   "pykotaWarnCount" : { "operator" : "+", "value" : 1, "convert" : int }, 
    12791279                 } 
    1280         return self.doModify(userpquota.ident, fields)          
    1281          
     1280        return self.doModify(userpquota.ident, fields) 
     1281 
    12821282    def saveGroupPQuota(self, grouppquota) : 
    12831283        """Saves a group print quota entry.""" 
    1284         fields = {  
     1284        fields = { 
    12851285                   "pykotaSoftLimit" : str(grouppquota.SoftLimit), 
    12861286                   "pykotaHardLimit" : str(grouppquota.HardLimit), 
     
    12891289                 } 
    12901290        self.doModify(grouppquota.ident, fields) 
    1291              
     1291 
    12921292    def writePrinterToGroup(self, pgroup, printer) : 
    12931293        """Puts a printer into a printer group.""" 
     
    12961296            fields = { 
    12971297                       "uniqueMember" : pgroup.uniqueMember 
    1298                      }   
    1299             self.doModify(pgroup.ident, fields)          
    1300              
     1298                     } 
     1299            self.doModify(pgroup.ident, fields) 
     1300 
    13011301    def removePrinterFromGroup(self, pgroup, printer) : 
    13021302        """Removes a printer from a printer group.""" 
    13031303        try : 
    13041304            pgroup.uniqueMember.remove(printer.ident) 
    1305         except ValueError :     
     1305        except ValueError : 
    13061306            pass 
    1307         else :     
     1307        else : 
    13081308            fields = { 
    13091309                       "uniqueMember" : pgroup.uniqueMember, 
    1310                      }   
    1311             self.doModify(pgroup.ident, fields)          
    1312              
     1310                     } 
     1311            self.doModify(pgroup.ident, fields) 
     1312 
    13131313    def retrieveHistory(self, user=None, printer=None, hostname=None, billingcode=None, jobid=None, limit=100, start=None, end=None) : 
    13141314        """Retrieves all print jobs for user on printer (or all) between start and end date, limited to first 100 results.""" 
     
    13251325        if jobid is not None : 
    13261326            where.append("(pykotaJobId=%s)" % jobid) # TODO : jobid is text, so unicodeToDatabase(jobid) but do all of them as well. 
    1327         if where :     
     1327        if where : 
    13281328            where = "(&%s)" % "".join([precond] + where) 
    1329         else :     
     1329        else : 
    13301330            where = precond 
    1331         jobs = []     
    1332         result = self.doSearch(where, fields=[ "pykotaJobSizeBytes",  
    1333                                                "pykotaHostName",  
    1334                                                "pykotaUserName",  
    1335                                                "pykotaPrinterName",  
    1336                                                "pykotaJobId",  
    1337                                                "pykotaPrinterPageCounter",  
    1338                                                "pykotaAction",  
    1339                                                "pykotaJobSize",  
    1340                                                "pykotaJobPrice",  
    1341                                                "pykotaFileName",  
    1342                                                "pykotaTitle",  
    1343                                                "pykotaCopies",  
    1344                                                "pykotaOptions",  
    1345                                                "pykotaBillingCode",  
    1346                                                "pykotaPages",  
    1347                                                "pykotaMD5Sum",  
     1331        jobs = [] 
     1332        result = self.doSearch(where, fields=[ "pykotaJobSizeBytes", 
     1333                                               "pykotaHostName", 
     1334                                               "pykotaUserName", 
     1335                                               "pykotaPrinterName", 
     1336                                               "pykotaJobId", 
     1337                                               "pykotaPrinterPageCounter", 
     1338                                               "pykotaAction", 
     1339                                               "pykotaJobSize", 
     1340                                               "pykotaJobPrice", 
     1341                                               "pykotaFileName", 
     1342                                               "pykotaTitle", 
     1343                                               "pykotaCopies", 
     1344                                               "pykotaOptions", 
     1345                                               "pykotaBillingCode", 
     1346                                               "pykotaPages", 
     1347                                               "pykotaMD5Sum", 
    13481348                                               "pykotaPrecomputedJobSize", 
    13491349                                               "pykotaPrecomputedJobPrice", 
    1350                                                "createTimestamp" ],  
     1350                                               "createTimestamp" ], 
    13511351                                      base=self.info["jobbase"]) 
    13521352        if result : 
     
    13581358                try : 
    13591359                    job.JobSize = int(fields.get("pykotaJobSize", [0])[0]) 
    1360                 except ValueError :     
     1360                except ValueError : 
    13611361                    job.JobSize = None 
    1362                 try :     
     1362                try : 
    13631363                    job.JobPrice = float(fields.get("pykotaJobPrice", [0.0])[0]) 
    13641364                except ValueError : 
    13651365                    job.JobPrice = None 
    13661366                job.JobAction = databaseToUnicode(fields.get("pykotaAction", [""])[0]) 
    1367                 job.JobFileName = databaseToUnicode(fields.get("pykotaFileName", [""])[0])  
    1368                 job.JobTitle = databaseToUnicode(fields.get("pykotaTitle", [""])[0])  
     1367                job.JobFileName = databaseToUnicode(fields.get("pykotaFileName", [""])[0]) 
     1368                job.JobTitle = databaseToUnicode(fields.get("pykotaTitle", [""])[0]) 
    13691369                job.JobCopies = int(fields.get("pykotaCopies", [0])[0]) 
    1370                 job.JobOptions = databaseToUnicode(fields.get("pykotaOptions", [""])[0])  
     1370                job.JobOptions = databaseToUnicode(fields.get("pykotaOptions", [""])[0]) 
    13711371                job.JobHostName = databaseToUnicode(fields.get("pykotaHostName", [""])[0]) 
    13721372                job.JobSizeBytes = fields.get("pykotaJobSizeBytes", [0L])[0] 
     
    13761376                try : 
    13771377                    job.PrecomputedJobSize = int(fields.get("pykotaPrecomputedJobSize", [0])[0]) 
    1378                 except ValueError :     
     1378                except ValueError : 
    13791379                    job.PrecomputedJobSize = None 
    1380                 try :     
     1380                try : 
    13811381                    job.PrecomputedJobPrice = float(fields.get("pykotaPrecomputedJobPrice", [0.0])[0]) 
    13821382                except ValueError : 
     
    13951395                    job.Exists = True 
    13961396                    jobs.append(job) 
    1397             jobs.sort(lambda x, y : cmp(y.JobDate, x.JobDate))         
    1398             if limit :     
     1397            jobs.sort(lambda x, y : cmp(y.JobDate, x.JobDate)) 
     1398            if limit : 
    13991399                jobs = jobs[:int(limit)] 
    14001400        return jobs 
    1401          
    1402     def deleteUser(self, user) :     
     1401 
     1402    def deleteUser(self, user) : 
    14031403        """Completely deletes an user from the Quota Storage.""" 
    14041404        uname = unicodeToDatabase(user.Name) 
    1405         todelete = []     
     1405        todelete = [] 
    14061406        result = self.doSearch("(&(objectClass=pykotaJob)(pykotaUserName=%s))" % uname, base=self.info["jobbase"]) 
    14071407        for (ident, fields) in result : 
     
    14171417            # ensure the user print quota entry will be deleted 
    14181418            todelete.append(ident) 
    1419              
     1419 
    14201420            # if last job of current printer was printed by the user 
    14211421            # to delete, we also need to delete the printer's last job entry. 
     
    14231423            if printer.LastJob.UserName == user.Name : 
    14241424                todelete.append(printer.LastJob.lastjobident) 
    1425              
    1426         for ident in todelete :     
     1425 
     1426        for ident in todelete : 
    14271427            self.doDelete(ident) 
    1428              
    1429         result = self.doSearch("objectClass=pykotaAccount", None, base=user.ident, scope=ldap.SCOPE_BASE)     
     1428 
     1429        result = self.doSearch("objectClass=pykotaAccount", None, base=user.ident, scope=ldap.SCOPE_BASE) 
    14301430        if result : 
    14311431            fields = result[0][1] 
     
    14331433                if k.startswith("pykota") : 
    14341434                    del fields[k] 
    1435                 elif k.lower() == "objectclass" :     
     1435                elif k.lower() == "objectclass" : 
    14361436                    todelete = [] 
    14371437                    for i in range(len(fields[k])) : 
    1438                         if fields[k][i].startswith("pykota") :  
     1438                        if fields[k][i].startswith("pykota") : 
    14391439                            todelete.append(i) 
    1440                     todelete.sort()         
     1440                    todelete.sort() 
    14411441                    todelete.reverse() 
    14421442                    for i in todelete : 
    14431443                        del fields[k][i] 
    14441444            if fields.get("objectClass") or fields.get("objectclass") : 
    1445                 self.doModify(user.ident, fields, ignoreold=0)         
    1446             else :     
     1445                self.doModify(user.ident, fields, ignoreold=0) 
     1446            else : 
    14471447                self.doDelete(user.ident) 
    14481448        result = self.doSearch("(&(objectClass=pykotaAccountBalance)(pykotaUserName=%s))" % \ 
     
    14521452        for (ident, fields) in result : 
    14531453            self.doDelete(ident) 
    1454          
    1455     def deleteGroup(self, group) :     
     1454 
     1455    def deleteGroup(self, group) : 
    14561456        """Completely deletes a group from the Quota Storage.""" 
    14571457        gname = unicodeToDatabase(group.Name) 
     
    14661466        for (ident, fields) in result : 
    14671467            self.doDelete(ident) 
    1468         result = self.doSearch("objectClass=pykotaGroup", None, base=group.ident, scope=ldap.SCOPE_BASE)     
     1468        result = self.doSearch("objectClass=pykotaGroup", None, base=group.ident, scope=ldap.SCOPE_BASE) 
    14691469        if result : 
    14701470            fields = result[0][1] 
     
    14721472                if k.startswith("pykota") : 
    14731473                    del fields[k] 
    1474                 elif k.lower() == "objectclass" :     
     1474                elif k.lower() == "objectclass" : 
    14751475                    todelete = [] 
    14761476                    for i in range(len(fields[k])) : 
    1477                         if fields[k][i].startswith("pykota") :  
     1477                        if fields[k][i].startswith("pykota") : 
    14781478                            todelete.append(i) 
    1479                     todelete.sort()         
     1479                    todelete.sort() 
    14801480                    todelete.reverse() 
    14811481                    for i in todelete : 
    14821482                        del fields[k][i] 
    14831483            if fields.get("objectClass") or fields.get("objectclass") : 
    1484                 self.doModify(group.ident, fields, ignoreold=0)         
    1485             else :     
     1484                self.doModify(group.ident, fields, ignoreold=0) 
     1485            else : 
    14861486                self.doDelete(group.ident) 
    1487                  
     1487 
    14881488    def deleteManyBillingCodes(self, billingcodes) : 
    14891489        """Deletes many billing codes.""" 
    14901490        for bcode in billingcodes : 
    14911491            bcode.delete() 
    1492          
    1493     def deleteManyUsers(self, users) :         
     1492 
     1493    def deleteManyUsers(self, users) : 
    14941494        """Deletes many users.""" 
    14951495        for user in users : 
    14961496            user.delete() 
    1497              
    1498     def deleteManyGroups(self, groups) :         
     1497 
     1498    def deleteManyGroups(self, groups) : 
    14991499        """Deletes many groups.""" 
    15001500        for group in groups : 
    15011501            group.delete() 
    1502          
    1503     def deleteManyPrinters(self, printers) :         
     1502 
     1503    def deleteManyPrinters(self, printers) : 
    15041504        """Deletes many printers.""" 
    15051505        for printer in printers : 
    15061506            printer.delete() 
    1507          
    1508     def deleteManyUserPQuotas(self, printers, users) :         
     1507 
     1508    def deleteManyUserPQuotas(self, printers, users) : 
    15091509        """Deletes many user print quota entries.""" 
    15101510        # TODO : grab all with a single (possibly VERY huge) filter if possible (might depend on the LDAP server !) 
     
    15141514                if upq.Exists : 
    15151515                    upq.delete() 
    1516              
     1516 
    15171517    def deleteManyGroupPQuotas(self, printers, groups) : 
    15181518        """Deletes many group print quota entries.""" 
     
    15231523                if gpq.Exists : 
    15241524                    gpq.delete() 
    1525                  
    1526     def deleteUserPQuota(self, upquota) :     
     1525 
     1526    def deleteUserPQuota(self, upquota) : 
    15271527        """Completely deletes an user print quota entry from the database.""" 
    15281528        uname = unicodeToDatabase(upquota.User.Name) 
     
    15361536            self.doDelete(upquota.Printer.LastJob.lastjobident) 
    15371537        self.doDelete(upquota.ident) 
    1538          
    1539     def deleteGroupPQuota(self, gpquota) :     
     1538 
     1539    def deleteGroupPQuota(self, gpquota) : 
    15401540        """Completely deletes a group print quota entry from the database.""" 
    15411541        self.doDelete(gpquota.ident) 
    1542                  
    1543     def deletePrinter(self, printer) :     
     1542 
     1543    def deletePrinter(self, printer) : 
    15441544        """Completely deletes a printer from the Quota Storage.""" 
    15451545        pname = unicodeToDatabase(printer.Name) 
     
    15641564        for (ident, fields) in result : 
    15651565            self.doDelete(ident) 
    1566         for parent in self.getParentPrinters(printer) :   
     1566        for parent in self.getParentPrinters(printer) : 
    15671567            try : 
    15681568                parent.uniqueMember.remove(printer.ident) 
    1569             except ValueError :     
     1569            except ValueError : 
    15701570                pass 
    1571             else :     
     1571            else : 
    15721572                fields = { 
    15731573                           "uniqueMember" : parent.uniqueMember, 
    1574                          }   
    1575                 self.doModify(parent.ident, fields)          
    1576         self.doDelete(printer.ident)     
    1577          
     1574                         } 
     1575                self.doModify(parent.ident, fields) 
     1576        self.doDelete(printer.ident) 
     1577 
    15781578    def deleteBillingCode(self, code) : 
    15791579        """Deletes a billing code from the Quota Storage (no entries are deleted from the history)""" 
    15801580        self.doDelete(code.ident) 
    1581          
    1582     def sortRecords(self, fields, records, default, ordering) :      
     1581 
     1582    def sortRecords(self, fields, records, default, ordering) : 
    15831583        """Sort records based on list of fields prefixed with '+' (ASC) or '-' (DESC).""" 
    15841584        fieldindexes = {} 
    15851585        for i in range(len(fields)) : 
    15861586            fieldindexes[fields[i]] = i 
    1587         if not ordering :     
     1587        if not ordering : 
    15881588            ordering = default 
    1589         orderby = []     
     1589        orderby = [] 
    15901590        for orderkey in ordering : 
    15911591            # Create ordering hints, ignoring unknown fields 
     
    15981598                if index is not None : 
    15991599                    orderby.append((+1, index)) 
    1600             else :     
     1600            else : 
    16011601                index = fieldindexes.get(orderkey) 
    16021602                if index is not None : 
    16031603                    orderby.append((+1, index)) 
    1604                  
    1605         def compare(x, y, orderby=orderby) :     
     1604 
     1605        def compare(x, y, orderby=orderby) : 
    16061606            """Compares two records.""" 
    16071607            i = 0 
     
    16121612                if not result : 
    16131613                    i += 1 
    1614                 else :     
     1614                else : 
    16151615                    return sign * result 
    1616             return 0 # identical keys         
    1617              
     1616            return 0 # identical keys 
     1617 
    16181618        records.sort(compare) 
    16191619        return records 
    1620          
     1620 
    16211621    def extractPrinters(self, extractonly={}, ordering=[]) : 
    16221622        """Extracts all printer records.""" 
     
    16291629                if entry.PassThrough in (1, "1", "t", "true", "T", "TRUE", "True") : 
    16301630                    passthrough = "t" 
    1631                 else :     
     1631                else : 
    16321632                    passthrough = "f" 
    16331633                result.append((entry.ident, entry.Name, entry.PricePerPage, entry.PricePerJob, entry.Description, entry.MaxJobSize, passthrough)) 
    1634             return [fields] + self.sortRecords(fields, result, ["+dn"], ordering)  
    1635          
     1634            return [fields] + self.sortRecords(fields, result, ["+dn"], ordering) 
     1635 
    16361636    def extractUsers(self, extractonly={}, ordering=[]) : 
    16371637        """Extracts all user records.""" 
     
    16441644                result.append((entry.ident, entry.Name, entry.AccountBalance, entry.LifeTimePaid, entry.LimitBy, entry.Email, entry.Description, entry.OverCharge)) 
    16451645            return [fields] + self.sortRecords(fields, result, ["+dn"], ordering) 
    1646          
     1646 
    16471647    def extractBillingcodes(self, extractonly={}, ordering=[]) : 
    16481648        """Extracts all billing codes records.""" 
     
    16551655                result.append((entry.ident, entry.BillingCode, entry.Balance, entry.PageCounter, entry.Description)) 
    16561656            return [fields] + self.sortRecords(fields, result, ["+dn"], ordering) 
    1657          
     1657 
    16581658    def extractGroups(self, extractonly={}, ordering=[]) : 
    16591659        """Extracts all group records.""" 
     
    16661666                result.append((entry.ident, entry.Name, entry.LimitBy, entry.AccountBalance, entry.LifeTimePaid, entry.Description)) 
    16671667            return [fields] + self.sortRecords(fields, result, ["+dn"], ordering) 
    1668          
     1668 
    16691669    def extractPayments(self, extractonly={}, ordering=[]) : 
    16701670        """Extracts all payment records.""" 
     
    16851685                        result.append((entry.Name, amount, date, description)) 
    16861686            return [fields] + self.sortRecords(fields, result, ["+date"], ordering) 
    1687          
     1687 
    16881688    def extractUpquotas(self, extractonly={}, ordering=[]) : 
    16891689        """Extracts all userpquota records.""" 
     
    16981698                    result.append((user.Name, entry.Name, userpquota.ident, user.ident, entry.ident, userpquota.LifePageCounter, userpquota.PageCounter, userpquota.SoftLimit, userpquota.HardLimit, userpquota.DateLimit)) 
    16991699            return [fields] + self.sortRecords(fields, result, ["+userdn"], ordering) 
    1700          
     1700 
    17011701    def extractGpquotas(self, extractonly={}, ordering=[]) : 
    17021702        """Extracts all grouppquota records.""" 
     
    17111711                    result.append((group.Name, entry.Name, grouppquota.ident, group.ident, entry.ident, grouppquota.LifePageCounter, grouppquota.PageCounter, grouppquota.SoftLimit, grouppquota.HardLimit, grouppquota.DateLimit)) 
    17121712            return [fields] + self.sortRecords(fields, result, ["+groupdn"], ordering) 
    1713          
     1713 
    17141714    def extractUmembers(self, extractonly={}, ordering=[]) : 
    17151715        """Extracts all user groups members.""" 
     
    17251725                        result.append((entry.Name, member.Name, entry.ident, member.ident)) 
    17261726            return [fields] + self.sortRecords(fields, result, ["+groupdn", "+userdn"], ordering) 
    1727                  
     1727 
    17281728    def extractPmembers(self, extractonly={}, ordering=[]) : 
    17291729        """Extracts all printer groups members.""" 
     
    17391739                        result.append((parent.Name, entry.Name, parent.ident, entry.ident)) 
    17401740            return [fields] + self.sortRecords(fields, result, ["+pgroupdn", "+printerdn"], ordering) 
    1741          
     1741 
    17421742    def extractHistory(self, extractonly={}, ordering=[]) : 
    17431743        """Extracts all jobhistory records.""" 
     
    17451745        if uname : 
    17461746            user = self.getUser(uname) 
    1747         else :     
     1747        else : 
    17481748            user = None 
    17491749        pname = extractonly.get("printername") 
    17501750        if pname : 
    17511751            printer = self.getPrinter(pname) 
    1752         else :     
     1752        else : 
    17531753            printer = None 
    17541754        startdate = extractonly.get("start") 
     
    17601760            result = [] 
    17611761            for entry in entries : 
    1762                 result.append((entry.UserName, entry.PrinterName, entry.ident, entry.JobId, entry.PrinterPageCounter, entry.JobSize, entry.JobAction, entry.JobDate, entry.JobFileName, entry.JobTitle, entry.JobCopies, entry.JobOptions, entry.JobPrice, entry.JobHostName, entry.JobSizeBytes, entry.JobMD5Sum, entry.JobPages, entry.JobBillingCode, entry.PrecomputedJobSize, entry.PrecomputedJobPrice))  
     1762                result.append((entry.UserName, entry.PrinterName, entry.ident, entry.JobId, entry.PrinterPageCounter, entry.JobSize, entry.JobAction, entry.JobDate, entry.JobFileName, entry.JobTitle, entry.JobCopies, entry.JobOptions, entry.JobPrice, entry.JobHostName, entry.JobSizeBytes, entry.JobMD5Sum, entry.JobPages, entry.JobBillingCode, entry.PrecomputedJobSize, entry.PrecomputedJobPrice)) 
    17631763            return [fields] + self.sortRecords(fields, result, ["+dn"], ordering) 
    1764              
     1764 
    17651765    def getBillingCodeFromBackend(self, label) : 
    17661766        """Extracts billing code information given its label : returns first matching billing code.""" 
     
    17771777            code.PageCounter = int(fields.get("pykotaPageCounter", [0])[0]) 
    17781778            code.Balance = float(fields.get("pykotaBalance", [0.0])[0]) 
    1779             code.Description = databaseToUnicode(fields.get("description", [""])[0])  
     1779            code.Description = databaseToUnicode(fields.get("description", [""])[0]) 
    17801780            code.Exists = True 
    1781         return code     
    1782          
     1781        return code 
     1782 
    17831783    def addBillingCode(self, bcode) : 
    17841784        """Adds a billing code to the quota storage, returns it.""" 
     
    17931793                   "pykotaPageCounter" : str(bcode.PageCounter or 0), 
    17941794                   "pykotaBalance" : str(bcode.Balance or 0.0), 
    1795                    "description" : unicodeToDatabase(bcode.Description or ""),  
    1796                  }  
     1795                   "description" : unicodeToDatabase(bcode.Description or ""), 
     1796                 } 
    17971797        self.doAdd(dn, fields) 
    17981798        bcode.isDirty = False 
    17991799        return None # the entry created doesn't need further modification 
    1800          
     1800 
    18011801    def saveBillingCode(self, bcode) : 
    18021802        """Sets the new description for a billing code.""" 
    18031803        fields = { 
    1804                    "description" : unicodeToDatabase(bcode.Description or ""),  
     1804                   "description" : unicodeToDatabase(bcode.Description or ""), 
    18051805                   "pykotaPageCounter" : str(bcode.PageCounter or 0), 
    18061806                   "pykotaBalance" : str(bcode.Balance or 0.0), 
    18071807                 } 
    18081808        self.doModify(bcode.ident, fields) 
    1809              
     1809 
    18101810    def getMatchingBillingCodes(self, billingcodepattern) : 
    18111811        """Returns the list of all billing codes which match a certain pattern.""" 
     
    18181818            try : 
    18191819                patdict = {}.fromkeys(patterns) 
    1820             except AttributeError :     
     1820            except AttributeError : 
    18211821                # Python v2.2 or earlier 
    18221822                patdict = {} 
     
    18301830                    code.PageCounter = int(fields.get("pykotaPageCounter", [0])[0]) 
    18311831                    code.Balance = float(fields.get("pykotaBalance", [0.0])[0]) 
    1832                     code.Description = databaseToUnicode(fields.get("description", [""])[0])  
     1832                    code.Description = databaseToUnicode(fields.get("description", [""])[0]) 
    18331833                    code.Exists = True 
    18341834                    codes.append(code) 
    18351835                    self.cacheEntry("BILLINGCODES", code.BillingCode, code) 
    1836         return codes         
    1837          
     1836        return codes 
     1837 
    18381838    def consumeBillingCode(self, bcode, pagecounter, balance) : 
    18391839        """Consumes from a billing code.""" 
     
    18421842                   "pykotaPageCounter" : { "operator" : "+", "value" : pagecounter, "convert" : int }, 
    18431843                 } 
    1844         return self.doModify(bcode.ident, fields)          
    1845  
    1846     def refundJob(self, jobident) :    
     1844        return self.doModify(bcode.ident, fields) 
     1845 
     1846    def refundJob(self, jobident) : 
    18471847        """Marks a job as refunded in the history.""" 
    18481848        fields = { 
    18491849                     "pykotaAction" : "REFUND", 
    1850                  }     
    1851         self.doModify(jobident, fields)          
    1852          
     1850                 } 
     1851        self.doModify(jobident, fields) 
     1852 
    18531853    def storageUserFromRecord(self, username, record) : 
    18541854        """Returns a StorageUser instance from a database record.""" 
     
    18561856        user.Exists = True 
    18571857        return user 
    1858          
     1858 
    18591859    def storageGroupFromRecord(self, groupname, record) : 
    18601860        """Returns a StorageGroup instance from a database record.""" 
     
    18621862        group.Exists = True 
    18631863        return group 
    1864          
     1864 
    18651865    def storagePrinterFromRecord(self, printername, record) : 
    18661866        """Returns a StoragePrinter instance from a database record.""" 
     
    18681868        printer.Exists = True 
    18691869        return printer 
    1870          
    1871     def setJobAttributesFromRecord(self, job, record) :     
     1870 
     1871    def setJobAttributesFromRecord(self, job, record) : 
    18721872        """Sets the attributes of a job from a database record.""" 
    18731873        job.Exists = True 
    1874          
     1874 
    18751875    def storageJobFromRecord(self, record) : 
    18761876        """Returns a StorageJob instance from a database record.""" 
     
    18781878        self.setJobAttributesFromRecord(job, record) 
    18791879        return job 
    1880          
     1880 
    18811881    def storageLastJobFromRecord(self, printer, record) : 
    18821882        """Returns a StorageLastJob instance from a database record.""" 
     
    18841884        self.setJobAttributesFromRecord(lastjob, record) 
    18851885        return lastjob 
    1886          
     1886 
    18871887    def storageUserPQuotaFromRecord(self, user, printer, record) : 
    18881888        """Returns a StorageUserPQuota instance from a database record.""" 
     
    18901890        userpquota.Exists = True 
    18911891        return userpquota 
    1892          
     1892 
    18931893    def storageGroupPQuotaFromRecord(self, group, printer, record) : 
    18941894        """Returns a StorageGroupPQuota instance from a database record.""" 
     
    18961896        grouppquota.Exists = True 
    18971897        return grouppquota 
    1898          
     1898 
    18991899    def storageBillingCodeFromRecord(self, billingcode, record) : 
    19001900        """Returns a StorageBillingCode instance from a database record.""" 
  • pykota/trunk/pykota/storages/mysqlstorage.py

    r3411 r3413  
    88# the Free Software Foundation, either version 3 of the License, or 
    99# (at your option) any later version. 
    10 #  
     10# 
    1111# This program is distributed in the hope that it will be useful, 
    1212# but WITHOUT ANY WARRANTY; without even the implied warranty of 
    1313# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
    1414# GNU General Public License for more details. 
    15 #  
     15# 
    1616# You should have received a copy of the GNU General Public License 
    1717# along with this program.  If not, see <http://www.gnu.org/licenses/>. 
     
    2929try : 
    3030    import MySQLdb 
    31 except ImportError :     
     31except ImportError : 
    3232    import sys 
    3333    # TODO : to translate or not to translate ? 
     
    4141            (host, port) = host.split(":") 
    4242            port = int(port) 
    43         except ValueError :     
     43        except ValueError : 
    4444            port = 3306           # Use the default MySQL port 
    45          
     45 
    4646        self.tool.logdebug("Trying to open database (host=%s, port=%s, dbname=%s, user=%s)..." % (host, port, dbname, user)) 
    4747        try : 
    4848            self.database = MySQLdb.connect(host=host, port=port, db=dbname, user=user, passwd=passwd, charset="utf8") 
    49         except TypeError :     
     49        except TypeError : 
    5050            self.tool.logdebug("'charset' argument not allowed with this version of python-mysqldb, retrying without...") 
    5151            self.database = MySQLdb.connect(host=host, port=port, db=dbname, user=user, passwd=passwd) 
    52              
     52 
    5353        try : 
    5454            self.database.autocommit(1) 
    55         except AttributeError :     
     55        except AttributeError : 
    5656            raise PyKotaStorageError, _("Your version of python-mysqldb is too old. Please install a newer release.") 
    5757        self.cursor = self.database.cursor() 
     
    6262        try : 
    6363            # Here we try to select a string (an &eacute;) which is 
    64             # already encoded in UTF-8. If python-mysqldb suffers from  
     64            # already encoded in UTF-8. If python-mysqldb suffers from 
    6565            # the double encoding problem, we will catch the exception 
    6666            # and activate a workaround. 
    6767            self.cursor.execute("SELECT '%s';" % (chr(0xc3) + chr(0xa9))) # &eacute; in UTF-8 
    6868            self.cursor.fetchall() 
    69         except UnicodeDecodeError :     
     69        except UnicodeDecodeError : 
    7070            self.needsworkaround = True 
    7171            self.tool.logdebug("Database needs encoding workaround.") 
     
    7373            self.needsworkaround = False 
    7474            self.tool.logdebug("Database doesn't need encoding workaround.") 
    75              
    76     def close(self) :     
     75 
     76    def close(self) : 
    7777        """Closes the database connection.""" 
    7878        if not self.closed : 
     
    8181            self.closed = True 
    8282            self.tool.logdebug("Database closed.") 
    83          
    84     def beginTransaction(self) :     
     83 
     84    def beginTransaction(self) : 
    8585        """Starts a transaction.""" 
    8686        self.cursor.execute("BEGIN;") 
    8787        self.tool.logdebug("Transaction begins...") 
    88          
    89     def commitTransaction(self) :     
     88 
     89    def commitTransaction(self) : 
    9090        """Commits a transaction.""" 
    9191        self.database.commit() 
    9292        self.tool.logdebug("Transaction committed.") 
    93          
    94     def rollbackTransaction(self) :      
     93 
     94    def rollbackTransaction(self) : 
    9595        """Rollbacks a transaction.""" 
    9696        self.database.rollback() 
    9797        self.tool.logdebug("Transaction aborted.") 
    98          
     98 
    9999    def doRawSearch(self, query) : 
    100100        """Does a raw search query.""" 
    101         query = query.strip()     
    102         if not query.endswith(';') :     
     101        query = query.strip() 
     102        if not query.endswith(';') : 
    103103            query += ';' 
    104104        self.querydebug("QUERY : %s" % query) 
    105         if self.needsworkaround :     
     105        if self.needsworkaround : 
    106106            query = query.decode("UTF-8") 
    107107        try : 
    108108            self.cursor.execute(query) 
    109         except self.database.Error, msg :     
     109        except self.database.Error, msg : 
    110110            raise PyKotaStorageError, repr(msg) 
    111         else :     
     111        else : 
    112112            # This returns a list of lists. Integers are returned as longs. 
    113113            return self.cursor.fetchall() 
    114              
    115     def doSearch(self, query) :         
     114 
     115    def doSearch(self, query) : 
    116116        """Does a search query.""" 
    117117        result = self.doRawSearch(query) 
     
    131131    def doModify(self, query) : 
    132132        """Does a (possibly multiple) modify query.""" 
    133         query = query.strip()     
    134         if not query.endswith(';') :     
     133        query = query.strip() 
     134        if not query.endswith(';') : 
    135135            query += ';' 
    136136        self.querydebug("QUERY : %s" % query) 
    137         if self.needsworkaround :     
     137        if self.needsworkaround : 
    138138            query = query.decode("UTF-8") 
    139139        try : 
    140140            self.cursor.execute(query) 
    141         except self.database.Error, msg :     
     141        except self.database.Error, msg : 
    142142            self.tool.logdebug("Query failed : %s" % repr(msg)) 
    143143            raise PyKotaStorageError, repr(msg) 
    144              
     144 
    145145    def doQuote(self, field) : 
    146146        """Quotes a field for use as a string in SQL queries.""" 
  • pykota/trunk/pykota/storages/pgstorage.py

    r3411 r3413  
    88# the Free Software Foundation, either version 3 of the License, or 
    99# (at your option) any later version. 
    10 #  
     10# 
    1111# This program is distributed in the hope that it will be useful, 
    1212# but WITHOUT ANY WARRANTY; without even the implied warranty of 
    1313# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
    1414# GNU General Public License for more details. 
    15 #  
     15# 
    1616# You should have received a copy of the GNU General Public License 
    1717# along with this program.  If not, see <http://www.gnu.org/licenses/>. 
     
    2929from pykota.storages.sql import SQLStorage 
    3030 
    31 from pykota.utils import *                            
     31from pykota.utils import * 
    3232 
    3333try : 
    3434    import pg 
    35 except ImportError :     
     35except ImportError : 
    3636    import sys 
    3737    # TODO : to translate or not to translate ? 
    3838    raise PyKotaStorageError, "This python version (%s) doesn't seem to have the PygreSQL module installed correctly." % sys.version.split()[0] 
    39 else :     
     39else : 
    4040    try : 
    4141        PGError = pg.Error 
    42     except AttributeError :     
     42    except AttributeError : 
    4343        PGError = pg.error 
    4444 
     
    5050            (host, port) = host.split(":") 
    5151            port = int(port) 
    52         except ValueError :     
     52        except ValueError : 
    5353            port = 5432         # Use PostgreSQL's default tcp/ip port (5432). 
    54          
     54 
    5555        self.tool.logdebug("Trying to open database (host=%s, port=%s, dbname=%s, user=%s)..." % (host, port, dbname, user)) 
    5656        try : 
    5757            self.database = pg.connect(host=host, port=port, dbname=dbname, user=user, passwd=passwd) 
    58         except PGError, msg :     
     58        except PGError, msg : 
    5959            msg = "%(msg)s --- the most probable cause of your problem is that PostgreSQL is down, or doesn't accept incoming connections because you didn't configure it as explained in PyKota's documentation." % locals() 
    6060            raise PGError, msg 
     
    6262        try : 
    6363            self.database.query("SET CLIENT_ENCODING TO 'UTF-8';") 
    64         except PGError, msg :     
     64        except PGError, msg : 
    6565            self.tool.logdebug("Impossible to set database client encoding to UTF-8 : %s" % msg) 
    6666        self.tool.logdebug("Database opened (host=%s, port=%s, dbname=%s, user=%s)" % (host, port, dbname, user)) 
    67              
    68     def close(self) :     
     67 
     68    def close(self) : 
    6969        """Closes the database connection.""" 
    7070        if not self.closed : 
     
    7272            self.closed = 1 
    7373            self.tool.logdebug("Database closed.") 
    74          
    75     def beginTransaction(self) :     
     74 
     75    def beginTransaction(self) : 
    7676        """Starts a transaction.""" 
    7777        self.database.query("BEGIN;") 
    7878        self.tool.logdebug("Transaction begins...") 
    79          
    80     def commitTransaction(self) :     
     79 
     80    def commitTransaction(self) : 
    8181        """Commits a transaction.""" 
    8282        self.database.query("COMMIT;") 
    8383        self.tool.logdebug("Transaction committed.") 
    84          
    85     def rollbackTransaction(self) :      
     84 
     85    def rollbackTransaction(self) : 
    8686        """Rollbacks a transaction.""" 
    8787        self.database.query("ROLLBACK;") 
    8888        self.tool.logdebug("Transaction aborted.") 
    89          
     89 
    9090    def doRawSearch(self, query) : 
    9191        """Does a raw search query.""" 
    92         query = query.strip()     
    93         if not query.endswith(';') :     
     92        query = query.strip() 
     93        if not query.endswith(';') : 
    9494            query += ';' 
    9595        try : 
    9696            self.querydebug("QUERY : %s" % query) 
    9797            return self.database.query(query) 
    98         except PGError, msg :     
     98        except PGError, msg : 
    9999            raise PyKotaStorageError, repr(msg) 
    100              
    101     def doSearch(self, query) :         
     100 
     101    def doSearch(self, query) : 
    102102        """Does a search query.""" 
    103103        result = self.doRawSearch(query) 
    104         if (result is not None) and (result.ntuples() > 0) :  
     104        if (result is not None) and (result.ntuples() > 0) : 
    105105            return result.dictresult() 
    106          
     106 
    107107    def doModify(self, query) : 
    108108        """Does a (possibly multiple) modify query.""" 
    109         query = query.strip()     
    110         if not query.endswith(';') :     
     109        query = query.strip() 
     110        if not query.endswith(';') : 
    111111            query += ';' 
    112112        try : 
    113113            self.querydebug("QUERY : %s" % query) 
    114114            return self.database.query(query) 
    115         except PGError, msg :     
     115        except PGError, msg : 
    116116            self.tool.logdebug("Query failed : %s" % repr(msg)) 
    117117            raise PyKotaStorageError, repr(msg) 
    118              
     118 
    119119    def doQuote(self, field) : 
    120120        """Quotes a field for use as a string in SQL queries.""" 
    121         if type(field) == type(0.0) :  
     121        if type(field) == type(0.0) : 
    122122            typ = "decimal" 
    123         elif type(field) == type(0) :     
     123        elif type(field) == type(0) : 
    124124            typ = "int" 
    125         elif type(field) == type(0L) :     
     125        elif type(field) == type(0L) : 
    126126            typ = "int" 
    127         else :     
     127        else : 
    128128            typ = "text" 
    129129        return pg._quote(field, typ) 
    130          
     130 
    131131    def prepareRawResult(self, result) : 
    132132        """Prepares a raw result by including the headers.""" 
     
    140140                    field = fields[j] 
    141141                    if type(field) == StringType : 
    142                         fields[j] = databaseToUnicode(field)  
    143                 entries[i] = tuple(fields)     
     142                        fields[j] = databaseToUnicode(field) 
     143                entries[i] = tuple(fields) 
    144144            return entries 
    145          
     145 
  • pykota/trunk/pykota/storages/sqlitestorage.py

    r3411 r3413  
    88# the Free Software Foundation, either version 3 of the License, or 
    99# (at your option) any later version. 
    10 #  
     10# 
    1111# This program is distributed in the hope that it will be useful, 
    1212# but WITHOUT ANY WARRANTY; without even the implied warranty of 
    1313# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
    1414# GNU General Public License for more details. 
    15 #  
     15# 
    1616# You should have received a copy of the GNU General Public License 
    1717# along with this program.  If not, see <http://www.gnu.org/licenses/>. 
     
    2929try : 
    3030    from pysqlite2 import dbapi2 as sqlite 
    31 except ImportError :     
     31except ImportError : 
    3232    import sys 
    3333    # TODO : to translate or not to translate ? 
    3434    raise PyKotaStorageError, "This python version (%s) doesn't seem to have the PySQLite module installed correctly." % sys.version.split()[0] 
    35      
     35 
    3636class Storage(BaseStorage, SQLStorage) : 
    3737    def __init__(self, pykotatool, host, dbname, user, passwd) : 
    3838        """Opens the SQLite database connection.""" 
    3939        BaseStorage.__init__(self, pykotatool) 
    40          
     40 
    4141        self.tool.logdebug("Trying to open database (dbname=%s)..." % dbname) 
    4242        self.database = sqlite.connect(dbname, isolation_level=None) 
     
    4444        self.closed = 0 
    4545        self.tool.logdebug("Database opened (dbname=%s)" % dbname) 
    46              
    47     def close(self) :     
     46 
     47    def close(self) : 
    4848        """Closes the database connection.""" 
    4949        if not self.closed : 
     
    5252            self.closed = 1 
    5353            self.tool.logdebug("Database closed.") 
    54          
    55     def beginTransaction(self) :     
     54 
     55    def beginTransaction(self) : 
    5656        """Starts a transaction.""" 
    5757        self.cursor.execute("BEGIN;") 
    5858        self.tool.logdebug("Transaction begins...") 
    59          
    60     def commitTransaction(self) :     
     59 
     60    def commitTransaction(self) : 
    6161        """Commits a transaction.""" 
    6262        self.cursor.execute("COMMIT;") 
    6363        self.tool.logdebug("Transaction committed.") 
    64          
    65     def rollbackTransaction(self) :      
     64 
     65    def rollbackTransaction(self) : 
    6666        """Rollbacks a transaction.""" 
    6767        self.cursor.execute("ROLLBACK;") 
    6868        self.tool.logdebug("Transaction aborted.") 
    69          
     69 
    7070    def doRawSearch(self, query) : 
    7171        """Does a raw search query.""" 
    72         query = query.strip()     
    73         if not query.endswith(';') :     
     72        query = query.strip() 
     73        if not query.endswith(';') : 
    7474            query += ';' 
    7575        try : 
    7676            self.querydebug("QUERY : %s" % query) 
    7777            self.cursor.execute(query) 
    78         except self.database.Error, msg :     
     78        except self.database.Error, msg : 
    7979            raise PyKotaStorageError, repr(msg) 
    80         else :     
     80        else : 
    8181            result = self.cursor.fetchall() 
    8282            return result 
    83              
    84     def doSearch(self, query) :         
     83 
     84    def doSearch(self, query) : 
    8585        """Does a search query.""" 
    8686        result = self.doRawSearch(query) 
    87         if result :  
     87        if result : 
    8888            rows = [] 
    8989            fields = {} 
    9090            for i in range(len(self.cursor.description)) : 
    9191                fields[i] = self.cursor.description[i][0] 
    92             for row in result :     
     92            for row in result : 
    9393                rowdict = {} 
    9494                for field in fields.keys() : 
     
    9999                        pass 
    100100                    rowdict[fields[field]] = value 
    101                 rows.append(rowdict)     
    102             return rows     
    103          
     101                rows.append(rowdict) 
     102            return rows 
     103 
    104104    def doModify(self, query) : 
    105105        """Does a (possibly multiple) modify query.""" 
    106         query = query.strip()     
    107         if not query.endswith(';') :     
     106        query = query.strip() 
     107        if not query.endswith(';') : 
    108108            query += ';' 
    109109        try : 
    110110            self.querydebug("QUERY : %s" % query) 
    111111            self.cursor.execute(query) 
    112         except self.database.Error, msg :     
     112        except self.database.Error, msg : 
    113113            self.tool.logdebug("Query failed : %s" % repr(msg)) 
    114114            raise PyKotaStorageError, repr(msg) 
    115              
     115 
    116116    def doQuote(self, field) : 
    117117        """Quotes a field for use as a string in SQL queries.""" 
    118         if type(field) == type(0.0) :  
     118        if type(field) == type(0.0) : 
    119119            return field 
    120         elif type(field) == type(0) :     
     120        elif type(field) == type(0) : 
    121121            return field 
    122         elif type(field) == type(0L) :     
     122        elif type(field) == type(0L) : 
    123123            return field 
    124124        elif field is not None : 
    125125            return ("'%s'" % field.replace("'", "''")).decode("UTF-8") 
    126         else :      
     126        else : 
    127127            return "NULL" 
    128              
     128 
    129129    def prepareRawResult(self, result) : 
    130130        """Prepares a raw result by including the headers.""" 
    131131        if result : 
    132132            entries = [tuple([f[0] for f in self.cursor.description])] 
    133             for entry in result :     
     133            for entry in result : 
    134134                row = [] 
    135135                for value in entry : 
     
    139139                        pass 
    140140                    row.append(value) 
    141                 entries.append(tuple(row))     
    142             return entries    
    143          
     141                entries.append(tuple(row)) 
     142            return entries 
     143 
  • pykota/trunk/pykota/storages/sql.py

    r3411 r3413  
    88# the Free Software Foundation, either version 3 of the License, or 
    99# (at your option) any later version. 
    10 #  
     10# 
    1111# This program is distributed in the hope that it will be useful, 
    1212# but WITHOUT ANY WARRANTY; without even the implied warranty of 
    1313# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
    1414# GNU General Public License for more details. 
    15 #  
     15# 
    1616# You should have received a copy of the GNU General Public License 
    1717# along with this program.  If not, see <http://www.gnu.org/licenses/>. 
     
    2626                           StorageJob, StorageLastJob, StorageUserPQuota, \ 
    2727                           StorageGroupPQuota, StorageBillingCode 
    28                             
    29 from pykota.utils import *                            
     28 
     29from pykota.utils import * 
    3030 
    3131class SQLStorage : 
     
    4242        user.Exists = True 
    4343        return user 
    44          
     44 
    4545    def storageGroupFromRecord(self, groupname, record) : 
    4646        """Returns a StorageGroup instance from a database record.""" 
     
    5353        group.Exists = True 
    5454        return group 
    55          
     55 
    5656    def storagePrinterFromRecord(self, printername, record) : 
    5757        """Returns a StoragePrinter instance from a database record.""" 
     
    6969        printer.Exists = True 
    7070        return printer 
    71          
    72     def setJobAttributesFromRecord(self, job, record) :     
     71 
     72    def setJobAttributesFromRecord(self, job, record) : 
    7373        """Sets the attributes of a job from a database record.""" 
    7474        job.ident = record.get("id") 
     
    7878        job.JobPrice = record.get("jobprice") 
    7979        job.JobAction = record.get("action") 
    80         job.JobFileName = databaseToUnicode(record.get("filename") or "")  
    81         job.JobTitle = databaseToUnicode(record.get("title") or "")  
     80        job.JobFileName = databaseToUnicode(record.get("filename") or "") 
     81        job.JobTitle = databaseToUnicode(record.get("title") or "") 
    8282        job.JobCopies = record.get("copies") 
    83         job.JobOptions = databaseToUnicode(record.get("options") or "")  
     83        job.JobOptions = databaseToUnicode(record.get("options") or "") 
    8484        job.JobDate = record.get("jobdate") 
    8585        job.JobHostName = record.get("hostname") 
     
    9595            (job.JobTitle, job.JobFileName, job.JobOptions) = (_("Hidden because of privacy concerns"),) * 3 
    9696        job.Exists = True 
    97          
     97 
    9898    def storageJobFromRecord(self, record) : 
    9999        """Returns a StorageJob instance from a database record.""" 
     
    101101        self.setJobAttributesFromRecord(job, record) 
    102102        return job 
    103          
     103 
    104104    def storageLastJobFromRecord(self, printer, record) : 
    105105        """Returns a StorageLastJob instance from a database record.""" 
     
    107107        self.setJobAttributesFromRecord(lastjob, record) 
    108108        return lastjob 
    109          
     109 
    110110    def storageUserPQuotaFromRecord(self, user, printer, record) : 
    111111        """Returns a StorageUserPQuota instance from a database record.""" 
     
    120120        userpquota.Exists = True 
    121121        return userpquota 
    122          
     122 
    123123    def storageGroupPQuotaFromRecord(self, group, printer, record) : 
    124124        """Returns a StorageGroupPQuota instance from a database record.""" 
     
    135135        grouppquota.Exists = True 
    136136        return grouppquota 
    137          
     137 
    138138    def storageBillingCodeFromRecord(self, billingcode, record) : 
    139139        """Returns a StorageBillingCode instance from a database record.""" 
     
    145145        code.Exists = True 
    146146        return code 
    147          
    148     def createFilter(self, only) :     
     147 
     148    def createFilter(self, only) : 
    149149        """Returns the appropriate SQL filter.""" 
    150150        if only : 
     
    152152            for (k, v) in only.items() : 
    153153                expressions.append("%s=%s" % (k, self.doQuote(unicodeToDatabase(v)))) 
    154             return " AND ".join(expressions)      
    155         return ""         
    156          
    157     def createOrderBy(self, default, ordering) :     
     154            return " AND ".join(expressions) 
     155        return "" 
     156 
     157    def createOrderBy(self, default, ordering) : 
    158158        """Creates a suitable ORDER BY statement based on a list of fieldnames prefixed with '+' (ASC) or '-' (DESC).""" 
    159159        statements = [] 
    160160        if not ordering : 
    161161            ordering = default 
    162         for field in ordering :     
    163             if field.startswith("-") :     
     162        for field in ordering : 
     163            if field.startswith("-") : 
    164164                statements.append("%s DESC" % field[1:]) 
    165165            elif field.startswith("+") : 
    166166                statements.append("%s ASC" % field[1:]) 
    167             else :     
     167            else : 
    168168                statements.append("%s ASC" % field) 
    169         return ", ".join(statements)     
    170          
     169        return ", ".join(statements) 
     170 
    171171    def extractPrinters(self, extractonly={}, ordering=[]) : 
    172172        """Extracts all printer records.""" 
     
    177177        result = self.doRawSearch("SELECT * FROM printers %(thefilter)s ORDER BY %(orderby)s" % locals()) 
    178178        return self.prepareRawResult(result) 
    179          
     179 
    180180    def extractUsers(self, extractonly={}, ordering=[]) : 
    181181        """Extracts all user records.""" 
     
    186186        result = self.doRawSearch("SELECT * FROM users %(thefilter)s ORDER BY %(orderby)s" % locals()) 
    187187        return self.prepareRawResult(result) 
    188          
     188 
    189189    def extractBillingcodes(self, extractonly={}, ordering=[]) : 
    190190        """Extracts all billing codes records.""" 
     
    195195        result = self.doRawSearch("SELECT * FROM billingcodes %(thefilter)s ORDER BY %(orderby)s" % locals()) 
    196196        return self.prepareRawResult(result) 
    197          
     197 
    198198    def extractGroups(self, extractonly={}, ordering=[]) : 
    199199        """Extracts all group records.""" 
     
    204204        result = self.doRawSearch("SELECT groups.*,COALESCE(SUM(balance), 0) AS balance, COALESCE(SUM(lifetimepaid), 0) as lifetimepaid FROM groups LEFT OUTER JOIN users ON users.id IN (SELECT userid FROM groupsmembers WHERE groupid=groups.id) %(thefilter)s GROUP BY groups.id,groups.groupname,groups.limitby,groups.description ORDER BY %(orderby)s" % locals()) 
    205205        return self.prepareRawResult(result) 
    206          
     206 
    207207    def extractPayments(self, extractonly={}, ordering=[]) : 
    208208        """Extracts all payment records.""" 
     
    212212            try : 
    213213                del extractonly[limit] 
    214             except KeyError :     
     214            except KeyError : 
    215215                pass 
    216216        thefilter = self.createFilter(extractonly) 
     
    218218            thefilter = "AND %s" % thefilter 
    219219        (startdate, enddate) = self.cleanDates(startdate, enddate) 
    220         if startdate :  
     220        if startdate : 
    221221            thefilter = "%s AND date>=%s" % (thefilter, self.doQuote(startdate)) 
    222         if enddate :  
     222        if enddate : 
    223223            thefilter = "%s AND date<=%s" % (thefilter, self.doQuote(enddate)) 
    224224        orderby = self.createOrderBy(["+payments.id"], ordering) 
    225225        result = self.doRawSearch("SELECT username,payments.* FROM users,payments WHERE users.id=payments.userid %(thefilter)s ORDER BY %(orderby)s" % locals()) 
    226226        return self.prepareRawResult(result) 
    227          
     227 
    228228    def extractUpquotas(self, extractonly={}, ordering=[]) : 
    229229        """Extracts all userpquota records.""" 
     
    234234        result = self.doRawSearch("SELECT users.username,printers.printername,userpquota.* FROM users,printers,userpquota WHERE users.id=userpquota.userid AND printers.id=userpquota.printerid %(thefilter)s ORDER BY %(orderby)s" % locals()) 
    235235        return self.prepareRawResult(result) 
    236          
     236 
    237237    def extractGpquotas(self, extractonly={}, ordering=[]) : 
    238238        """Extracts all grouppquota records.""" 
     
    243243        result = self.doRawSearch("SELECT groups.groupname,printers.printername,grouppquota.*,coalesce(sum(pagecounter), 0) AS pagecounter,coalesce(sum(lifepagecounter), 0) AS lifepagecounter FROM groups,printers,grouppquota,userpquota WHERE groups.id=grouppquota.groupid AND printers.id=grouppquota.printerid AND userpquota.printerid=grouppquota.printerid AND userpquota.userid IN (SELECT userid FROM groupsmembers WHERE groupsmembers.groupid=grouppquota.groupid) %(thefilter)s GROUP BY grouppquota.id,grouppquota.groupid,grouppquota.printerid,grouppquota.softlimit,grouppquota.hardlimit,grouppquota.datelimit,grouppquota.maxjobsize,groups.groupname,printers.printername ORDER BY %(orderby)s" % locals()) 
    244244        return self.prepareRawResult(result) 
    245          
     245 
    246246    def extractUmembers(self, extractonly={}, ordering=[]) : 
    247247        """Extracts all user groups members.""" 
     
    252252        result = self.doRawSearch("SELECT groups.groupname, users.username, groupsmembers.* FROM groups,users,groupsmembers WHERE users.id=groupsmembers.userid AND groups.id=groupsmembers.groupid %(thefilter)s ORDER BY %(orderby)s" % locals()) 
    253253        return self.prepareRawResult(result) 
    254          
     254 
    255255    def extractPmembers(self, extractonly={}, ordering=[]) : 
    256256        """Extracts all printer groups members.""" 
     
    268268        result = self.doRawSearch("SELECT p1.printername as pgroupname, p2.printername as printername, printergroupsmembers.* FROM printers p1, printers p2, printergroupsmembers WHERE p1.id=printergroupsmembers.groupid AND p2.id=printergroupsmembers.printerid %(thefilter)s ORDER BY %(orderby)s" % locals()) 
    269269        return self.prepareRawResult(result) 
    270          
     270 
    271271    def extractHistory(self, extractonly={}, ordering=[]) : 
    272272        """Extracts all jobhistory records.""" 
     
    276276            try : 
    277277                del extractonly[limit] 
    278             except KeyError :     
     278            except KeyError : 
    279279                pass 
    280280        thefilter = self.createFilter(extractonly) 
     
    282282            thefilter = "AND %s" % thefilter 
    283283        (startdate, enddate) = self.cleanDates(startdate, enddate) 
    284         if startdate :  
     284        if startdate : 
    285285            thefilter = "%s AND jobdate>=%s" % (thefilter, self.doQuote(startdate)) 
    286         if enddate :  
     286        if enddate : 
    287287            thefilter = "%s AND jobdate<=%s" % (thefilter, self.doQuote(enddate)) 
    288288        orderby = self.createOrderBy(["+jobhistory.id"], ordering) 
    289289        result = self.doRawSearch("SELECT users.username,printers.printername,jobhistory.* FROM users,printers,jobhistory WHERE users.id=jobhistory.userid AND printers.id=jobhistory.printerid %(thefilter)s ORDER BY %(orderby)s" % locals()) 
    290290        return self.prepareRawResult(result) 
    291              
     291 
    292292    def filterNames(self, records, attribute, patterns=None) : 
    293293        """Returns a list of 'attribute' from a list of records. 
    294          
     294 
    295295           Logs any missing attribute. 
    296         """    
     296        """ 
    297297        result = [] 
    298298        for record in records : 
     
    307307                    if self.tool.matchString(attrval, patterns) : 
    308308                        result.append(attrval) 
    309                 else :     
     309                else : 
    310310                    result.append(attrval) 
    311         return result    
    312                  
    313     def getAllBillingCodes(self, billingcode=None) :     
     311        return result 
     312 
     313    def getAllBillingCodes(self, billingcode=None) : 
    314314        """Extracts all billing codes or only the billing codes matching the optional parameter.""" 
    315315        result = self.doSearch("SELECT billingcode FROM billingcodes") 
    316316        if result : 
    317317            return self.filterNames(result, "billingcode", billingcode) 
    318         else :     
     318        else : 
    319319            return [] 
    320          
    321     def getAllPrintersNames(self, printername=None) :     
     320 
     321    def getAllPrintersNames(self, printername=None) : 
    322322        """Extracts all printer names or only the printers' names matching the optional parameter.""" 
    323323        result = self.doSearch("SELECT printername FROM printers") 
    324324        if result : 
    325325            return self.filterNames(result, "printername", printername) 
    326         else :     
     326        else : 
    327327            return [] 
    328      
    329     def getAllUsersNames(self, username=None) :     
     328 
     329    def getAllUsersNames(self, username=None) : 
    330330        """Extracts all user names.""" 
    331331        result = self.doSearch("SELECT username FROM users") 
    332332        if result : 
    333333            return self.filterNames(result, "username", username) 
    334         else :     
     334        else : 
    335335            return [] 
    336          
    337     def getAllGroupsNames(self, groupname=None) :     
     336 
     337    def getAllGroupsNames(self, groupname=None) : 
    338338        """Extracts all group names.""" 
    339339        result = self.doSearch("SELECT groupname FROM groups") 
     
    342342        else : 
    343343            return [] 
    344          
     344 
    345345    def getUserNbJobsFromHistory(self, user) : 
    346346        """Returns the number of jobs the user has in history.""" 
     
    349349            return result[0]["count"] 
    350350        return 0 
    351          
    352     def getUserFromBackend(self, username) :     
     351 
     352    def getUserFromBackend(self, username) : 
    353353        """Extracts user information given its name.""" 
    354354        result = self.doSearch("SELECT * FROM users WHERE username=%s"\ 
     
    356356        if result : 
    357357            return self.storageUserFromRecord(username, result[0]) 
    358         else :     
     358        else : 
    359359            return StorageUser(self, username) 
    360         
    361     def getGroupFromBackend(self, groupname) :     
     360 
     361    def getGroupFromBackend(self, groupname) : 
    362362        """Extracts group information given its name.""" 
    363363        result = self.doSearch("SELECT groups.*,COALESCE(SUM(balance), 0.0) AS balance, COALESCE(SUM(lifetimepaid), 0.0) AS lifetimepaid FROM groups LEFT OUTER JOIN users ON users.id IN (SELECT userid FROM groupsmembers WHERE groupid=groups.id) WHERE groupname=%s GROUP BY groups.id,groups.groupname,groups.limitby,groups.description" \ 
     
    365365        if result : 
    366366            return self.storageGroupFromRecord(groupname, result[0]) 
    367         else :     
     367        else : 
    368368            return StorageGroup(self, groupname) 
    369         
    370     def getPrinterFromBackend(self, printername) :         
     369 
     370    def getPrinterFromBackend(self, printername) : 
    371371        """Extracts printer information given its name.""" 
    372372        result = self.doSearch("SELECT * FROM printers WHERE printername=%s" \ 
     
    374374        if result : 
    375375            return self.storagePrinterFromRecord(printername, result[0]) 
    376         else :     
     376        else : 
    377377            return StoragePrinter(self, printername) 
    378          
    379     def getBillingCodeFromBackend(self, label) :         
     378 
     379    def getBillingCodeFromBackend(self, label) : 
    380380        """Extracts a billing code information given its name.""" 
    381381        result = self.doSearch("SELECT * FROM billingcodes WHERE billingcode=%s" \ 
     
    383383        if result : 
    384384            return self.storageBillingCodeFromRecord(label, result[0]) 
    385         else :     
     385        else : 
    386386            return StorageBillingCode(self, label) 
    387          
    388     def getUserPQuotaFromBackend(self, user, printer) :         
     387 
     388    def getUserPQuotaFromBackend(self, user, printer) : 
    389389        """Extracts a user print quota.""" 
    390390        if printer.Exists and user.Exists : 
     
    394394                return self.storageUserPQuotaFromRecord(user, printer, result[0]) 
    395395        return StorageUserPQuota(self, user, printer) 
    396          
    397     def getGroupPQuotaFromBackend(self, group, printer) :         
     396 
     397    def getGroupPQuotaFromBackend(self, group, printer) : 
    398398        """Extracts a group print quota.""" 
    399399        if printer.Exists and group.Exists : 
     
    403403                return self.storageGroupPQuotaFromRecord(group, printer, result[0]) 
    404404        return StorageGroupPQuota(self, group, printer) 
    405          
    406     def getPrinterLastJobFromBackend(self, printer) :         
     405 
     406    def getPrinterLastJobFromBackend(self, printer) : 
    407407        """Extracts a printer's last job information.""" 
    408408        result = self.doSearch("SELECT jobhistory.id, jobid, userid, username, pagecounter, jobsize, jobprice, filename, title, copies, options, hostname, jobdate, md5sum, pages, billingcode, precomputedjobsize, precomputedjobprice FROM jobhistory, users WHERE userid=users.id AND jobhistory.id IN (SELECT max(id) FROM jobhistory WHERE printerid=%s)" % self.doQuote(printer.ident)) 
    409409        if result : 
    410410            return self.storageLastJobFromRecord(printer, result[0]) 
    411         else :     
     411        else : 
    412412            return StorageLastJob(self, printer) 
    413              
    414     def getGroupMembersFromBackend(self, group) :         
     413 
     414    def getGroupMembersFromBackend(self, group) : 
    415415        """Returns the group's members list.""" 
    416416        groupmembers = [] 
     
    422422                groupmembers.append(user) 
    423423                self.cacheEntry("USERS", user.Name, user) 
    424         return groupmembers         
    425          
    426     def getUserGroupsFromBackend(self, user) :         
     424        return groupmembers 
     425 
     426    def getUserGroupsFromBackend(self, user) : 
    427427        """Returns the user's groups list.""" 
    428428        groups = [] 
     
    431431            for record in result : 
    432432                groups.append(self.getGroup(databaseToUnicode(record.get("groupname")))) 
    433         return groups         
    434          
    435     def getParentPrintersFromBackend(self, printer) :     
     433        return groups 
     434 
     435    def getParentPrintersFromBackend(self, printer) : 
    436436        """Get all the printer groups this printer is a member of.""" 
    437437        pgroups = [] 
     
    444444                        pgroups.append(parentprinter) 
    445445        return pgroups 
    446          
     446 
    447447    def getMatchingPrinters(self, printerpattern) : 
    448448        """Returns the list of all printers for which name matches a certain pattern.""" 
     
    456456            try : 
    457457                patdict = {}.fromkeys(patterns) 
    458             except AttributeError :     
     458            except AttributeError : 
    459459                # Python v2.2 or earlier 
    460460                patdict = {} 
     
    467467                    printers.append(printer) 
    468468                    self.cacheEntry("PRINTERS", printer.Name, printer) 
    469         return printers         
    470          
     469        return printers 
     470 
    471471    def getMatchingUsers(self, userpattern) : 
    472472        """Returns the list of all users for which name matches a certain pattern.""" 
     
    480480            try : 
    481481                patdict = {}.fromkeys(patterns) 
    482             except AttributeError :     
     482            except AttributeError : 
    483483                # Python v2.2 or earlier 
    484484                patdict = {} 
     
    491491                    users.append(user) 
    492492                    self.cacheEntry("USERS", user.Name, user) 
    493         return users         
    494          
     493        return users 
     494 
    495495    def getMatchingGroups(self, grouppattern) : 
    496496        """Returns the list of all groups for which name matches a certain pattern.""" 
     
    504504            try : 
    505505                patdict = {}.fromkeys(patterns) 
    506             except AttributeError :     
     506            except AttributeError : 
    507507                # Python v2.2 or earlier 
    508508                patdict = {} 
     
    515515                    groups.append(group) 
    516516                    self.cacheEntry("GROUPS", group.Name, group) 
    517         return groups         
    518          
     517        return groups 
     518 
    519519    def getMatchingBillingCodes(self, billingcodepattern) : 
    520520        """Returns the list of all billing codes for which the label matches a certain pattern.""" 
     
    525525            try : 
    526526                patdict = {}.fromkeys(patterns) 
    527             except AttributeError :     
     527            except AttributeError : 
    528528                # Python v2.2 or earlier 
    529529                patdict = {} 
     
    536536                    codes.append(code) 
    537537                    self.cacheEntry("BILLINGCODES", code.BillingCode, code) 
    538         return codes         
    539          
    540     def getPrinterUsersAndQuotas(self, printer, names=["*"]) :         
     538        return codes 
     539 
     540    def getPrinterUsersAndQuotas(self, printer, names=["*"]) : 
    541541        """Returns the list of users who uses a given printer, along with their quotas.""" 
    542542        usersandquotas = [] 
     
    552552                    self.cacheEntry("USERPQUOTAS", "%s@%s" % (user.Name, printer.Name), userpquota) 
    553553        return usersandquotas 
    554                  
    555     def getPrinterGroupsAndQuotas(self, printer, names=["*"]) :         
     554 
     555    def getPrinterGroupsAndQuotas(self, printer, names=["*"]) : 
    556556        """Returns the list of groups which uses a given printer, along with their quotas.""" 
    557557        groupsandquotas = [] 
     
    565565                    groupsandquotas.append((group, grouppquota)) 
    566566        return groupsandquotas 
    567          
    568     def addPrinter(self, printer) :         
     567 
     568    def addPrinter(self, printer) : 
    569569        """Adds a printer to the quota storage, returns the old value if it already exists.""" 
    570570        oldentry = self.getPrinter(printer.Name) 
     
    580580        printer.isDirty = False 
    581581        return None # the entry created doesn't need further modification 
    582          
     582 
    583583    def addBillingCode(self, bcode) : 
    584584        """Adds a billing code to the quota storage, returns the old value if it already exists.""" 
     
    587587            return oldentry 
    588588        self.doModify("INSERT INTO billingcodes (billingcode, balance, pagecounter, description) VALUES (%s, %s, %s, %s)" \ 
    589                            % (self.doQuote(unicodeToDatabase(bcode.BillingCode)),  
     589                           % (self.doQuote(unicodeToDatabase(bcode.BillingCode)), 
    590590                              self.doQuote(bcode.Balance or 0.0), \ 
    591591                              self.doQuote(bcode.PageCounter or 0), \ 
     
    593593        bcode.isDirty = False 
    594594        return None # the entry created doesn't need further modification 
    595          
    596     def addUser(self, user) :         
     595 
     596    def addUser(self, user) : 
    597597        """Adds a user to the quota storage, returns the old value if it already exists.""" 
    598598        oldentry = self.getUser(user.Name) 
     
    613613        user.isDirty = False 
    614614        return None # the entry created doesn't need further modification 
    615          
    616     def addGroup(self, group) :         
     615 
     616    def addGroup(self, group) : 
    617617        """Adds a group to the quota storage, returns the old value if it already exists.""" 
    618618        oldentry = self.getGroup(group.Name) 
     
    626626        return None # the entry created doesn't need further modification 
    627627 
    628     def addUserToGroup(self, user, group) :     
     628    def addUserToGroup(self, user, group) : 
    629629        """Adds an user to a group.""" 
    630630        result = self.doSearch("SELECT COUNT(*) AS mexists FROM groupsmembers WHERE groupid=%s AND userid=%s" % (self.doQuote(group.ident), self.doQuote(user.ident))) 
    631631        try : 
    632632            mexists = int(result[0].get("mexists")) 
    633         except (IndexError, TypeError) :     
     633        except (IndexError, TypeError) : 
    634634            mexists = 0 
    635         if not mexists :     
     635        if not mexists : 
    636636            self.doModify("INSERT INTO groupsmembers (groupid, userid) VALUES (%s, %s)" % (self.doQuote(group.ident), self.doQuote(user.ident))) 
    637              
    638     def delUserFromGroup(self, user, group) :     
     637 
     638    def delUserFromGroup(self, user, group) : 
    639639        """Removes an user from a group.""" 
    640640        self.doModify("DELETE FROM groupsmembers WHERE groupid=%s AND userid=%s" % \ 
    641641                       (self.doQuote(group.ident), self.doQuote(user.ident))) 
    642              
     642 
    643643    def addUserPQuota(self, upq) : 
    644644        """Initializes a user print quota on a printer.""" 
     
    658658        upq.isDirty = False 
    659659        return None # the entry created doesn't need further modification 
    660          
     660 
    661661    def addGroupPQuota(self, gpq) : 
    662662        """Initializes a group print quota on a printer.""" 
     
    673673        gpq.isDirty = False 
    674674        return None # the entry created doesn't need further modification 
    675          
    676     def savePrinter(self, printer) :     
     675 
     676    def savePrinter(self, printer) : 
    677677        """Saves the printer to the database in a single operation.""" 
    678678        self.doModify("UPDATE printers SET passthrough=%s, maxjobsize=%s, description=%s, priceperpage=%s, priceperjob=%s WHERE id=%s" \ 
     
    683683                                 self.doQuote(printer.PricePerJob or 0.0), \ 
    684684                                 self.doQuote(printer.ident))) 
    685                                   
    686     def saveUser(self, user) :         
     685 
     686    def saveUser(self, user) : 
    687687        """Saves the user to the database in a single operation.""" 
    688688        self.doModify("UPDATE users SET limitby=%s, balance=%s, lifetimepaid=%s, email=%s, overcharge=%s, description=%s WHERE id=%s" \ 
     
    694694                                  self.doQuote(unicodeToDatabase(user.Description)), \ 
    695695                                  self.doQuote(user.ident))) 
    696                                    
    697     def saveGroup(self, group) :         
     696 
     697    def saveGroup(self, group) : 
    698698        """Saves the group to the database in a single operation.""" 
    699699        self.doModify("UPDATE groups SET limitby=%s, description=%s WHERE id=%s" \ 
     
    701701                                  self.doQuote(unicodeToDatabase(group.Description)), \ 
    702702                                  self.doQuote(group.ident))) 
    703          
    704     def writeUserPQuotaDateLimit(self, userpquota, datelimit) :     
     703 
     704    def writeUserPQuotaDateLimit(self, userpquota, datelimit) : 
    705705        """Sets the date limit permanently for a user print quota.""" 
    706706        self.doModify("UPDATE userpquota SET datelimit=%s WHERE id=%s" % (self.doQuote(datelimit), self.doQuote(userpquota.ident))) 
    707              
    708     def writeGroupPQuotaDateLimit(self, grouppquota, datelimit) :     
     707 
     708    def writeGroupPQuotaDateLimit(self, grouppquota, datelimit) : 
    709709        """Sets the date limit permanently for a group print quota.""" 
    710710        self.doModify("UPDATE grouppquota SET datelimit=%s WHERE id=%s" % (self.doQuote(datelimit), self.doQuote(grouppquota.ident))) 
    711          
    712     def increaseUserPQuotaPagesCounters(self, userpquota, nbpages) :     
     711 
     712    def increaseUserPQuotaPagesCounters(self, userpquota, nbpages) : 
    713713        """Increase page counters for a user print quota.""" 
    714714        self.doModify("UPDATE userpquota SET pagecounter=pagecounter + %s,lifepagecounter=lifepagecounter + %s WHERE id=%s" % (self.doQuote(nbpages), self.doQuote(nbpages), self.doQuote(userpquota.ident))) 
    715         
    716     def saveBillingCode(self, bcode) :     
     715 
     716    def saveBillingCode(self, bcode) : 
    717717        """Saves the billing code to the database.""" 
    718718        self.doModify("UPDATE billingcodes SET balance=%s, pagecounter=%s, description=%s WHERE id=%s" \ 
     
    721721                               self.doQuote(unicodeToDatabase(bcode.Description)), \ 
    722722                               self.doQuote(bcode.ident))) 
    723         
     723 
    724724    def consumeBillingCode(self, bcode, pagecounter, balance) : 
    725725        """Consumes from a billing code.""" 
    726726        self.doModify("UPDATE billingcodes SET balance=balance + %s, pagecounter=pagecounter + %s WHERE id=%s" % (self.doQuote(balance), self.doQuote(pagecounter), self.doQuote(bcode.ident))) 
    727         
    728     def refundJob(self, jobident) :    
     727 
     728    def refundJob(self, jobident) : 
    729729        """Marks a job as refunded in the history.""" 
    730730        self.doModify("UPDATE jobhistory SET action='REFUND' WHERE id=%s;" % self.doQuote(jobident)) 
    731          
    732     def decreaseUserAccountBalance(self, user, amount) :     
     731 
     732    def decreaseUserAccountBalance(self, user, amount) : 
    733733        """Decreases user's account balance from an amount.""" 
    734734        self.doModify("UPDATE users SET balance=balance - %s WHERE id=%s" % (self.doQuote(amount), self.doQuote(user.ident))) 
    735         
     735 
    736736    def writeNewPayment(self, user, amount, comment="") : 
    737737        """Adds a new payment to the payments history.""" 
    738738        if user.ident is not None : 
    739739            self.doModify("INSERT INTO payments (userid, amount, description) VALUES (%s, %s, %s)" % (self.doQuote(user.ident), self.doQuote(amount), self.doQuote(unicodeToDatabase(comment)))) 
    740         else :     
     740        else : 
    741741            self.doModify("INSERT INTO payments (userid, amount, description) VALUES ((SELECT id FROM users WHERE username=%s), %s, %s)" % (self.doQuote(unicodeToDatabase(user.Name)), self.doQuote(amount), self.doQuote(unicodeToDatabase(comment)))) 
    742          
    743     def writeLastJobSize(self, lastjob, jobsize, jobprice) :         
     742 
     743    def writeLastJobSize(self, lastjob, jobsize, jobprice) : 
    744744        """Sets the last job's size permanently.""" 
    745745        self.doModify("UPDATE jobhistory SET jobsize=%s, jobprice=%s WHERE id=%s" % (self.doQuote(jobsize), self.doQuote(jobprice), self.doQuote(lastjob.ident))) 
    746          
     746 
    747747    def writeJobNew(self, printer, user, jobid, pagecounter, action, jobsize=None, jobprice=None, filename=None, title=None, copies=None, options=None, clienthost=None, jobsizebytes=None, jobmd5sum=None, jobpages=None, jobbilling=None, precomputedsize=None, precomputedprice=None) : 
    748748        """Adds a job in a printer's history.""" 
    749         if self.privacy :     
     749        if self.privacy : 
    750750            # For legal reasons, we want to hide the title, filename and options 
    751751            title = filename = options = "hidden" 
     
    757757            if jobsize is not None : 
    758758                self.doModify("INSERT INTO jobhistory (userid, printerid, jobid, pagecounter, action, jobsize, jobprice, filename, title, copies, options, hostname, jobsizebytes, md5sum, pages, billingcode, precomputedjobsize, precomputedjobprice) VALUES (%s, %s, %s, %s, %s, %s, %s, %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), self.doQuote(clienthost), self.doQuote(jobsizebytes), self.doQuote(jobmd5sum), self.doQuote(jobpages), self.doQuote(jobbilling), self.doQuote(precomputedsize), self.doQuote(precomputedprice))) 
    759             else :     
     759            else : 
    760760                self.doModify("INSERT INTO jobhistory (userid, printerid, jobid, pagecounter, action, filename, title, copies, options, hostname, jobsizebytes, md5sum, pages, billingcode, precomputedjobsize, precomputedjobprice) VALUES (%s, %s, %s, %s, %s, %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(filename), self.doQuote(title), self.doQuote(copies), self.doQuote(options), self.doQuote(clienthost), self.doQuote(jobsizebytes), self.doQuote(jobmd5sum), self.doQuote(jobpages), self.doQuote(jobbilling), self.doQuote(precomputedsize), self.doQuote(precomputedprice))) 
    761         else :         
     761        else : 
    762762            # here we explicitly want to reset jobsize to NULL if needed 
    763763            self.doModify("UPDATE jobhistory SET userid=%s, jobid=%s, pagecounter=%s, action=%s, jobsize=%s, jobprice=%s, filename=%s, title=%s, copies=%s, options=%s, hostname=%s, jobsizebytes=%s, md5sum=%s, pages=%s, billingcode=%s, precomputedjobsize=%s, precomputedjobprice=%s, jobdate=now() WHERE id=%s" % (self.doQuote(user.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), self.doQuote(clienthost), self.doQuote(jobsizebytes), self.doQuote(jobmd5sum), self.doQuote(jobpages), self.doQuote(jobbilling), self.doQuote(precomputedsize), self.doQuote(precomputedprice), self.doQuote(printer.LastJob.ident))) 
    764              
     764 
    765765    def saveUserPQuota(self, userpquota) : 
    766766        """Saves an user print quota entry.""" 
     
    774774                                 self.doQuote(userpquota.MaxJobSize), \ 
    775775                                 self.doQuote(userpquota.ident))) 
    776          
     776 
    777777    def writeUserPQuotaWarnCount(self, userpquota, warncount) : 
    778778        """Sets the warn counter value for a user quota.""" 
    779779        self.doModify("UPDATE userpquota SET warncount=%s WHERE id=%s" % (self.doQuote(warncount), self.doQuote(userpquota.ident))) 
    780          
     780 
    781781    def increaseUserPQuotaWarnCount(self, userpquota) : 
    782782        """Increases the warn counter value for a user quota.""" 
    783783        self.doModify("UPDATE userpquota SET warncount=warncount+1 WHERE id=%s" % self.doQuote(userpquota.ident)) 
    784          
     784 
    785785    def saveGroupPQuota(self, grouppquota) : 
    786786        """Saves a group print quota entry.""" 
     
    798798            for record in result : 
    799799                children.append(record.get("printerid")) # TODO : put this into the database integrity rules 
    800         if printer.ident not in children :         
     800        if printer.ident not in children : 
    801801            self.doModify("INSERT INTO printergroupsmembers (groupid, printerid) VALUES (%s, %s)" % (self.doQuote(pgroup.ident), self.doQuote(printer.ident))) 
    802          
     802 
    803803    def removePrinterFromGroup(self, pgroup, printer) : 
    804804        """Removes a printer from a printer group.""" 
    805805        self.doModify("DELETE FROM printergroupsmembers WHERE groupid=%s AND printerid=%s" % (self.doQuote(pgroup.ident), self.doQuote(printer.ident))) 
    806          
     806 
    807807    def retrieveHistory(self, user=None, printer=None, hostname=None, billingcode=None, jobid=None, limit=100, start=None, end=None) : 
    808808        """Retrieves all print jobs for user on printer (or all) between start and end date, limited to first 100 results.""" 
     
    813813        if printer is not None : # printer.ident is None anyway if printer doesn't exist 
    814814            where.append("printerid=%s" % self.doQuote(printer.ident)) 
    815         if hostname is not None :     
     815        if hostname is not None : 
    816816            where.append("hostname=%s" % self.doQuote(hostname)) 
    817         if billingcode is not None :     
     817        if billingcode is not None : 
    818818            where.append("billingcode=%s" % self.doQuote(unicodeToDatabase(billingcode))) 
    819         if jobid is not None :     
     819        if jobid is not None : 
    820820            where.append("jobid=%s" % self.doQuote(jobid)) # TODO : jobid is text, so unicodeToDatabase(jobid) but do all of them as well. 
    821         if start is not None :     
     821        if start is not None : 
    822822            where.append("jobdate>=%s" % self.doQuote(start)) 
    823         if end is not None :     
     823        if end is not None : 
    824824            where.append("jobdate<=%s" % self.doQuote(end)) 
    825         if where :     
     825        if where : 
    826826            query += " AND %s" % " AND ".join(where) 
    827827        query += " ORDER BY jobhistory.id DESC" 
     
    829829            # TODO : LIMIT is not supported under DB2. 
    830830            # TODO : so we must use something like " FETCH FIRST %s ROWS ONLY" % self.doQuote(int(limit)) 
    831             query += " LIMIT %s" % self.doQuote(int(limit))  
    832         jobs = []     
    833         result = self.doSearch(query)     
     831            query += " LIMIT %s" % self.doQuote(int(limit)) 
     832        jobs = [] 
     833        result = self.doSearch(query) 
    834834        if result : 
    835835            for fields in result : 
     
    837837                jobs.append(job) 
    838838        return jobs 
    839          
    840     def deleteUser(self, user) :     
     839 
     840    def deleteUser(self, user) : 
    841841        """Completely deletes an user from the database.""" 
    842842        # TODO : What should we do if we delete the last person who used a given printer ? 
    843843        # TODO : we can't reassign the last job to the previous one, because next user would be 
    844844        # TODO : incorrectly charged (overcharged). 
    845         for q in [  
     845        for q in [ 
    846846                    "DELETE FROM payments WHERE userid=%s" % self.doQuote(user.ident), 
    847847                    "DELETE FROM groupsmembers WHERE userid=%s" % self.doQuote(user.ident), 
     
    851851                  ] : 
    852852            self.doModify(q) 
    853              
    854     def multipleQueriesInTransaction(self, queries) :         
     853 
     854    def multipleQueriesInTransaction(self, queries) : 
    855855        """Does many modifications in a single transaction.""" 
    856856        self.beginTransaction() 
     
    858858            for q in queries : 
    859859                self.doModify(q) 
    860         except :     
     860        except : 
    861861            self.rollbackTransaction() 
    862862            raise 
    863         else :     
     863        else : 
    864864            self.commitTransaction() 
    865              
    866     def deleteManyBillingCodes(self, billingcodes) :         
     865 
     866    def deleteManyBillingCodes(self, billingcodes) : 
    867867        """Deletes many billing codes.""" 
    868868        codeids = ", ".join(["%s" % self.doQuote(b.ident) for b in billingcodes]) 
    869869        if codeids : 
    870             self.multipleQueriesInTransaction([  
     870            self.multipleQueriesInTransaction([ 
    871871                    "DELETE FROM billingcodes WHERE id IN (%s)" % codeids,]) 
    872              
    873     def deleteManyUsers(self, users) :         
     872 
     873    def deleteManyUsers(self, users) : 
    874874        """Deletes many users.""" 
    875875        userids = ", ".join(["%s" % self.doQuote(u.ident) for u in users]) 
    876876        if userids : 
    877             self.multipleQueriesInTransaction([  
     877            self.multipleQueriesInTransaction([ 
    878878                    "DELETE FROM payments WHERE userid IN (%s)" % userids, 
    879879                    "DELETE FROM groupsmembers WHERE userid IN (%s)" % userids, 
     
    881881                    "DELETE FROM userpquota WHERE userid IN (%s)" % userids, 
    882882                    "DELETE FROM users WHERE id IN (%s)" % userids,]) 
    883                      
    884     def deleteManyGroups(self, groups) :         
     883 
     884    def deleteManyGroups(self, groups) : 
    885885        """Deletes many groups.""" 
    886886        groupids = ", ".join(["%s" % self.doQuote(g.ident) for g in groups]) 
    887887        if groupids : 
    888             self.multipleQueriesInTransaction([  
     888            self.multipleQueriesInTransaction([ 
    889889                    "DELETE FROM groupsmembers WHERE groupid IN (%s)" % groupids, 
    890890                    "DELETE FROM grouppquota WHERE groupid IN (%s)" % groupids, 
    891891                    "DELETE FROM groups WHERE id IN (%s)" % groupids,]) 
    892          
     892 
    893893    def deleteManyPrinters(self, printers) : 
    894894        """Deletes many printers.""" 
    895895        printerids = ", ".join(["%s" % self.doQuote(p.ident) for p in printers]) 
    896896        if printerids : 
    897             self.multipleQueriesInTransaction([  
     897            self.multipleQueriesInTransaction([ 
    898898                    "DELETE FROM printergroupsmembers WHERE groupid IN (%s) OR printerid IN (%s)" % (printerids, printerids), 
    899899                    "DELETE FROM jobhistory WHERE printerid IN (%s)" % printerids, 
     
    901901                    "DELETE FROM userpquota WHERE printerid IN (%s)" % printerids, 
    902902                    "DELETE FROM printers WHERE id IN (%s)" % printerids,]) 
    903          
    904     def deleteManyUserPQuotas(self, printers, users) :         
     903 
     904    def deleteManyUserPQuotas(self, printers, users) : 
    905905        """Deletes many user print quota entries.""" 
    906906        printerids = ", ".join(["%s" % self.doQuote(p.ident) for p in printers]) 
    907907        userids = ", ".join(["%s" % self.doQuote(u.ident) for u in users]) 
    908908        if userids and printerids : 
    909             self.multipleQueriesInTransaction([  
     909            self.multipleQueriesInTransaction([ 
    910910                    "DELETE FROM jobhistory WHERE userid IN (%s) AND printerid IN (%s)" \ 
    911911                                 % (userids, printerids), 
    912912                    "DELETE FROM userpquota WHERE userid IN (%s) AND printerid IN (%s)" \ 
    913913                                 % (userids, printerids),]) 
    914              
     914 
    915915    def deleteManyGroupPQuotas(self, printers, groups) : 
    916916        """Deletes many group print quota entries.""" 
     
    918918        groupids = ", ".join(["%s" % self.doQuote(g.ident) for g in groups]) 
    919919        if groupids and printerids : 
    920             self.multipleQueriesInTransaction([  
     920            self.multipleQueriesInTransaction([ 
    921921                    "DELETE FROM grouppquota WHERE groupid IN (%s) AND printerid IN (%s)" \ 
    922922                                 % (groupids, printerids),]) 
    923          
    924     def deleteUserPQuota(self, upquota) :     
     923 
     924    def deleteUserPQuota(self, upquota) : 
    925925        """Completely deletes an user print quota entry from the database.""" 
    926         for q in [  
     926        for q in [ 
    927927                    "DELETE FROM jobhistory WHERE userid=%s AND printerid=%s" \ 
    928928                                 % (self.doQuote(upquota.User.ident), self.doQuote(upquota.Printer.ident)), 
     
    930930                  ] : 
    931931            self.doModify(q) 
    932          
    933     def deleteGroupPQuota(self, gpquota) :     
     932 
     933    def deleteGroupPQuota(self, gpquota) : 
    934934        """Completely deletes a group print quota entry from the database.""" 
    935         for q in [  
     935        for q in [ 
    936936                    "DELETE FROM grouppquota WHERE id=%s" % self.doQuote(gpquota.ident), 
    937937                  ] : 
    938938            self.doModify(q) 
    939          
    940     def deleteGroup(self, group) :     
     939 
     940    def deleteGroup(self, group) : 
    941941        """Completely deletes a group from the database.""" 
    942942        for q in [ 
     
    944944                   "DELETE FROM grouppquota WHERE groupid=%s" % self.doQuote(group.ident), 
    945945                   "DELETE FROM groups WHERE id=%s" % self.doQuote(group.ident), 
    946                  ] :   
     946                 ] : 
    947947            self.doModify(q) 
    948              
    949     def deletePrinter(self, printer) :     
     948 
     949    def deletePrinter(self, printer) : 
    950950        """Completely deletes a printer from the database.""" 
    951         for q in [  
     951        for q in [ 
    952952                    "DELETE FROM printergroupsmembers WHERE groupid=%s OR printerid=%s" % (self.doQuote(printer.ident), self.doQuote(printer.ident)), 
    953953                    "DELETE FROM jobhistory WHERE printerid=%s" % self.doQuote(printer.ident), 
     
    957957                  ] : 
    958958            self.doModify(q) 
    959              
    960     def deleteBillingCode(self, code) :     
     959 
     960    def deleteBillingCode(self, code) : 
    961961        """Completely deletes a billing code from the database.""" 
    962962        for q in [ 
    963963                   "DELETE FROM billingcodes WHERE id=%s" % self.doQuote(code.ident), 
    964                  ] :   
     964                 ] : 
    965965            self.doModify(q) 
    966          
     966