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

Removed unnecessary spaces at EOL.

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • 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."""