Author: johannes Date: 2007-02-26 02:21:54 -0600 (Mon, 26 Feb 2007) New Revision: 9410
Modified: trunk/gnue-common/src/datasources/drivers/sql/mysql/Behavior.py trunk/gnue-common/src/datasources/readgsd.py Log: Pep8-ified readgsd.py and added a comment to the mysql driver Modified: trunk/gnue-common/src/datasources/drivers/sql/mysql/Behavior.py =================================================================== --- trunk/gnue-common/src/datasources/drivers/sql/mysql/Behavior.py 2007-02-23 20:34:36 UTC (rev 9409) +++ trunk/gnue-common/src/datasources/drivers/sql/mysql/Behavior.py 2007-02-26 08:21:54 UTC (rev 9410) @@ -49,6 +49,9 @@ CREATE TABLE or SHOW TABLE STATUS) - MySQL does *not* store the name of a primary key, instead this is always 'PRIMARY'. That's why we lose the original primary key's names. + - You cannot set the value of an AUTO_INCREMENT field to 0 using an INSERT + statement. To do this you'd have to insert first and the use an UPDATE + afterwards using the last serial value as key. """ # --------------------------------------------------------------------------- Modified: trunk/gnue-common/src/datasources/readgsd.py =================================================================== --- trunk/gnue-common/src/datasources/readgsd.py 2007-02-23 20:34:36 UTC (rev 9409) +++ trunk/gnue-common/src/datasources/readgsd.py 2007-02-26 08:21:54 UTC (rev 9410) @@ -40,734 +40,749 @@ # Exceptions # ============================================================================= -class MissingTableError (errors.ApplicationError): - def __init__ (self, name): - msg = u_("Table '%(table)s' not found in the schema") % {'table': name} - errors.ApplicationError.__init__ (self, msg) +class MissingTableError(errors.ApplicationError): + def __init__(self, name): + msg = u_("Table '%(table)s' not found in the schema") % {'table': name} + errors.ApplicationError.__init__(self, msg) -class MissingKeyFieldError (errors.ApplicationError): - def __init__ (self, table, row, keySet, rowSet): - msg = u_("Key field(s) '%(fields)s' missing in row '%(row)s' of " \ - "table '%(table)s'") \ - % {'table' : table, 'row': row, - 'fields': ", ".join (keySet.difference (rowSet))} - errors.ApplicationError.__init__ (self, msg) +class MissingKeyFieldError(errors.ApplicationError): + def __init__(self, table, row, keySet, rowSet): + msg = u_("Key field(s) '%(fields)s' missing in row '%(row)s' of " \ + "table '%(table)s'") \ + % {'table' : table, 'row': row, + 'fields': ", ".join(keySet.difference(rowSet))} + errors.ApplicationError.__init__(self, msg) -class InvalidFieldsError (errors.ApplicationError): - def __init__ (self, table, row, fields): - msg = u_("Table '%(table)s' has no field '%(fields)s'") \ - % {'table': table, 'fields': ", ".join (fields)} - errors.ApplicationError.__init__ (self, msg) +class InvalidFieldsError(errors.ApplicationError): + def __init__(self, table, row, fields): + msg = u_("Table '%(table)s' has no field '%(fields)s'") \ + % {'table': table, 'fields': ", ".join(fields)} + errors.ApplicationError.__init__(self, msg) -class CircularReferenceError (errors.ApplicationError): - def __init__ (self): - msg = u_("Tables have circular or unresolveable references") - errors.ApplicationError.__init__ (self, msg) +class CircularReferenceError(errors.ApplicationError): + def __init__(self): + msg = u_("Tables have circular or unresolveable references") + errors.ApplicationError.__init__(self, msg) -class CircularDataReferences (errors.ApplicationError): - def __init__ (self, table): - msg = u_("Table '%s' contains circular/unresolvable record references") \ - % table - errors.ApplicationError.__init__ (self, msg) +class CircularDataReferences(errors.ApplicationError): + def __init__(self, table): + msg = u_("Table '%s' contains circular/unresolvable record references")\ + % table + errors.ApplicationError.__init__(self, msg) -class InvalidNumberError (errors.ApplicationError): - def __init__ (self, value, length, scale): - msg = u_("The value '%(value)s' is not a valid " \ - "number (%(length)s.%(scale)s)") \ - % {'value': value, 'length': length, 'scale': scale} - errors.ApplicationError.__init__ (self, msg) +class InvalidNumberError(errors.ApplicationError): + def __init__(self, value, length, scale): + msg = u_("The value '%(value)s' is not a valid " \ + "number (%(length)s.%(scale)s)") \ + % {'value': value, 'length': length, 'scale': scale} + errors.ApplicationError.__init__(self, msg) -class OutOfRangeError (errors.ApplicationError): - def __init__ (self, value, length, scale): - msg = u_("The value '%(value)s' is out of range (%(length)s.%(scale)s)") \ - % {'value': value, 'length': length, 'scale': scale} - errors.ApplicationError.__init__ (self, msg) +class OutOfRangeError(errors.ApplicationError): + def __init__(self, value, length, scale): + msg = u_("The value '%(value)s' is out of range " \ + "(%(length)s.%(scale)s)") \ + % {'value': value, 'length': length, 'scale': scale} + errors.ApplicationError.__init__(self, msg) -class InvalidBooleanError (errors.ApplicationError): - def __init__ (self, value): - msg = u_("'%(value)s' is not a valid boolean value") % {'value': value} - errors.ApplicationError.__init__ (self, msg) +class InvalidBooleanError(errors.ApplicationError): + def __init__(self, value): + msg = u_("'%(value)s' is not a valid boolean value") % {'value': value} + errors.ApplicationError.__init__(self, msg) -class InvalidDateError (errors.ApplicationError): - def __init__ (self, value): - msg = u_("'%s' is not a vaild date, use 'YYYY-MM-DD' (ISO)") % value - errors.ApplicationError.__init__ (self, msg) +class InvalidDateError(errors.ApplicationError): + def __init__(self, value): + msg = u_("'%s' is not a vaild date, use 'YYYY-MM-DD' (ISO)") % value + errors.ApplicationError.__init__(self, msg) -class InvalidTimeError (errors.ApplicationError): - def __init__ (self, value): - msg = u_("'%s' is not a vaild time, use 'HH[:MM[:SS[.ss]]]' (ISO)") % value - errors.ApplicationError.__init__ (self, msg) +class InvalidTimeError(errors.ApplicationError): + def __init__(self, value): + msg = u_("'%s' is not a vaild time, use 'HH[:MM[:SS[.ss]]]' (ISO)") \ + % value + errors.ApplicationError.__init__(self, msg) -class InvalidDateTimeError (errors.ApplicationError): - def __init__ (self, value): - msg = u_("'%s' is not a vaild date/time, use 'YYYY-MM-DD " \ - "HH[:MM[:SS[.ss]]]' (ISO)") % value - errors.ApplicationError.__init__ (self, msg) +class InvalidDateTimeError(errors.ApplicationError): + def __init__(self, value): + msg = u_("'%s' is not a vaild date/time, use 'YYYY-MM-DD " \ + "HH[:MM[:SS[.ss]]]' (ISO)") % value + errors.ApplicationError.__init__(self, msg) -class InvalidTypeError (errors.ApplicationError): - def __init__ (self, ftype): - msg = u_("'%s' is not a recognized field type") % ftype - errors.ApplicationError.__init__ (self, msg) +class InvalidTypeError(errors.ApplicationError): + def __init__(self, ftype): + msg = u_("'%s' is not a recognized field type") % ftype + errors.ApplicationError.__init__(self, msg) # ============================================================================= # Client application reading and importing GNUe Schema Definition files # ============================================================================= -class gsdClient (GClientApp.GClientApp): - """ - Client application for reading and importing gsd files. - """ +class gsdClient(GClientApp.GClientApp): + """ + Client application for reading and importing gsd files. + """ - NAME = "readgsd" - COMMAND = "readgsd" - VERSION = "0.1.0" - USAGE = "%s file [, file, ...]" % GClientApp.GClientApp.USAGE - SUMMARY = u_("Import GNUe Schema Definition files into a given connection") + NAME = "readgsd" + COMMAND = "readgsd" + VERSION = "0.1.0" + USAGE = "%s file [, file, ...]" % GClientApp.GClientApp.USAGE + SUMMARY = u_("Import GNUe Schema Definition files into a given connection") - # --------------------------------------------------------------------------- - # Constructor - # --------------------------------------------------------------------------- + # ------------------------------------------------------------------------- + # Constructor + # ------------------------------------------------------------------------- - def __init__ (self, connections = None): + def __init__(self, connections=None): - self.addCommandOption ('connection', 'c', argument = u_('connectionname'), - default = "gnue", - help = u_("Use the connection <connectionname> for creating the " - "schema")) + self.addCommandOption('connection', 'c', argument=u_('connectionname'), + default = "gnue", + help = u_("Use the connection <connectionname> for creating the " + "schema")) - self.addCommandOption ('output','o', argument = u_('filename'), - help = u_("Also send the code for creating the schema to this file.")) + self.addCommandOption('output','o', argument=u_('filename'), + help = u_("Also send the code for creating the schema to " + "this file.")) - self.addCommandOption ('file-only', 'f', default = False, - help = u_("If this flag is set, only code is sent to the output file " - "and the schema is not created automatically.")) + self.addCommandOption('file-only', 'f', default = False, + help = u_("If this flag is set, only code is sent to the output " + "file and the schema is not created automatically.")) - self.addCommandOption ('mode', 'm', argument='both|schema|data', - default = 'both', - help = u_("Mode of operation. If mode is 'schema', only schema " - "creation is done. If mode is 'data' only data integration " - "is done.")) + self.addCommandOption('mode', 'm', argument='both|schema|data', + default = 'both', + help = u_("Mode of operation. If mode is 'schema', only schema " + "creation is done. If mode is 'data' only data " + "integration is done.")) - self.addCommandOption ('username', 'u', argument = u_("user"), - help = u_("Set the username to connect to the database. If the " - "database is to be created and no owner (--owner) is " - "specified, this username will be it's owner.")) + self.addCommandOption('username', 'u', argument = u_("user"), + help = u_("Set the username to connect to the database. If the " + "database is to be created and no owner (--owner) is " + "specified, this username will be it's owner.")) - self.addCommandOption ('password', 'p', argument = u_("password"), - help = u_("Set the password to connect to the database.")) + self.addCommandOption('password', 'p', argument = u_("password"), + help = u_("Set the password to connect to the database.")) - self.addCommandOption ('owner', 'O', argument = u_("owner"), - help = u_("If the database is to be created this will be its owner.")) + self.addCommandOption('owner', 'O', argument = u_("owner"), + help = u_("If the database is to be created this will be its " + "owner.")) - self.addCommandOption ('ownerpassword', 'P', argument = u_("ownerpwd"), - help = u_("If the database is to be created this will be the password " - "used for the database owner.")) + self.addCommandOption('ownerpassword', 'P', argument = u_("ownerpwd"), + help = u_("If the database is to be created this will be the " + "password used for the database owner.")) - self.addCommandOption ('createdb', 'd', default = False, - help = u_("If this option is set, the database will be created before " - "any schema creation is done. There must be an owner or a " - "username " - "either from the given connection-configuration or from the " - "command line. This user becomes the owner of the database " - "and will be implicitly created.")) + self.addCommandOption('createdb', 'd', default = False, + help = u_("If this option is set, the database will be created " + "before any schema creation is done. There must be an " + "owner or a username either from the given " + "connection-configuration or from the command line. " + "This user becomes the owner of the database and will " + "be implicitly created.")) - self.addCommandOption ('yes', 'y', default = False, - help = u_("If this option is set, the program runs in batch-mode, " - "which means all questions are answered with 'yes' " - "automatically.")) + self.addCommandOption('yes', 'y', default = False, + help = u_("If this option is set, the program runs in batch-mode, " + "which means all questions are answered with 'yes' " + "automatically.")) - GClientApp.GClientApp.__init__ (self, connections, 'schema', ()) + GClientApp.GClientApp.__init__(self, connections, 'schema', ()) - # --------------------------------------------------------------------------- - # Run the import - # --------------------------------------------------------------------------- + # ------------------------------------------------------------------------- + # Run the import + # ------------------------------------------------------------------------- - def run (self): - """ - Check the options given on the command line, load all gsd files and import - their schema/data according to the command line options. - """ + def run(self): + """ + Check the options given on the command line, load all gsd files and + import their schema/data according to the command line options. + """ - self.__checkOptions () - self.__loadInputFiles () + self.__check_options() + self.__load_input_files() - proceed = True + proceed = True - if self.__doSchema: - proceed = self.__importSchema () + if self.__do_schema: + proceed = self.__import_schema() - if proceed and self.__doData: - self.__importData () + if proceed and self.__do_data: + self.__import_data() + # ------------------------------------------------------------------------- + # Check the command line arguments + # ------------------------------------------------------------------------- - # --------------------------------------------------------------------------- - # Check the command line arguments - # --------------------------------------------------------------------------- + def __check_options(self): + """ + Process the command line arguments. - def __checkOptions (self): - """ - Process the command line arguments - - Builds a list of file handles to process and validates that the - command line option combinations are valid. - """ - if not self.ARGUMENTS: - raise GBaseApp.StartupError, u_("No input file specified.") + Builds a list of file handles to process and validates that the command + line option combinations are valid. + """ - # Build file handle list -------------------------------------------------- - try: - self._files = [] + if not self.ARGUMENTS: + raise GBaseApp.StartupError, u_("No input file specified.") - for filename in self.ARGUMENTS: - self._files.append (openResource (filename)) + # --- Build file handle list ------------------------------------------ + try: + self._files = [] - except IOError: - raise GBaseApp.StartupError, \ - u_("Unable to open input file: %s") % errors.getException () [2] + for filename in self.ARGUMENTS: + self._files.append(openResource(filename)) + except IOError: + raise GBaseApp.StartupError, \ + u_("Unable to open input file: %s") % errors.getException()[2] - # Setup ouput file if requested ------------------------------------------- - self.outfile = self.OPTIONS ['output'] - if self.OPTIONS ['file-only'] and self.outfile is None: - raise GBaseApp.StartupError, \ - u_("Output to file only requested, but no filename specified.") + # --- Setup ouput file if requested ----------------------------------- + self.outfile = self.OPTIONS['output'] - # Determine which processing steps are executed --------------------------- - self.__doSchema = self.OPTIONS ['mode'].lower () in ['both', 'schema'] - self.__doData = self.OPTIONS ['mode'].lower () in ['both', 'data'] and \ - not self.OPTIONS ['file-only'] + if self.OPTIONS['file-only'] and self.outfile is None: + raise GBaseApp.StartupError, \ + u_("Output to file only requested, but no filename specified.") - if not (self.__doSchema or self.__doData): - raise GBaseApp.StartupError, \ - u_("Mode of operation must be one of 'both', 'schema' or 'data'.") + # --- Determine which processing steps are executed ------------------- - # Setup the connection ---------------------------------------------------- - cName = self.OPTIONS ['connection'] - self.connection = self.connections.getConnection (cName) + mode = self.OPTIONS['mode'].lower() + self.__do_schema = mode in ['both', 'schema'] + self.__do_data = mode in ['both', 'data'] and \ + not self.OPTIONS['file-only'] - # Authentication ---------------------------------------------------------- - # if a username is given on the command line we pass both username and - # password to the connection parameters. If the password is not set, it - # defaults to 'gnue'. - username = self.connection.parameters.get ('username', 'gnue') - password = self.connection.parameters.get ('password', 'gnue') + if not (self.__do_schema or self.__do_data): + raise GBaseApp.StartupError, \ + u_("Mode of operation must be one of 'both', 'schema' " \ + "or 'data'.") - if self.OPTIONS ['username'] is not None: - username = self.OPTIONS ['username'] + # --- Setup the connection -------------------------------------------- + cName = self.OPTIONS['connection'] + self.connection = self.connections.getConnection(cName) - if self.OPTIONS ['password'] is not None: - password = self.OPTIONS ['password'] + # --- Authentication -------------------------------------------------- + # If a username is given on the command line we pass both username and + # password to the connection parameters. If the password is not set, + # it defaults to 'gnue'. + username = self.connection.parameters.get('username', 'gnue') + password = self.connection.parameters.get('password', 'gnue') - self.connection.parameters ['username'] = username - self.connection.parameters ['password'] = password + if self.OPTIONS['username'] is not None: + username = self.OPTIONS['username'] - owner = self.OPTIONS.get ('owner', self.connection.parameters.get ('owner')) - if not owner: - owner = username + if self.OPTIONS['password'] is not None: + password = self.OPTIONS['password'] - self.connection.parameters ['owner'] = owner - if self.OPTIONS.get ('ownerpassword'): - self.connection.parameters ['ownerpwd'] = self.OPTIONS ['ownerpassword'] + self.connection.parameters['username'] = username + self.connection.parameters['password'] = password - + owner = self.OPTIONS.get('owner', + self.connection.parameters.get('owner')) + if not owner: + owner = username - # --------------------------------------------------------------------------- - # Load input files - # --------------------------------------------------------------------------- + self.connection.parameters['owner'] = owner + if self.OPTIONS.get('ownerpassword'): + self.connection.parameters['ownerpwd'] = \ + self.OPTIONS['ownerpassword'] - def __loadInputFiles (self): - """ - Builds a schema from the list of input filehandles stored in self._files - """ - self._schema = None - for stream in self._files: - xmltree = GSchema.loadFile (stream) - if self._schema is None: - self._schema = xmltree - else: - self._schema.merge (xmltree) + # ------------------------------------------------------------------------- + # Load input files + # ------------------------------------------------------------------------- - # --------------------------------------------------------------------------- - # Import the given GSD files into the connection - # --------------------------------------------------------------------------- - - def __importSchema (self): - - if self.OPTIONS ['createdb']: - # Create a new database - if self.__ask (u_("You are about to create the new database '%s'. " \ - "Continue") % self.connection.name, - [u_("y"), u_("n")], "n") == u_("n"): - return False + def __load_input_files(self): + """ + Builds a schema from the list of input filehandles stored in self._files + """ + self._schema = None - self.connection.createDatabase () + for stream in self._files: + xmltree = GSchema.loadFile(stream) + if self._schema is None: + self._schema = xmltree + else: + self._schema.merge(xmltree) - # Process schema information (if requested) - simulation = self.OPTIONS ['file-only'] - if not simulation: - if self.__ask (u_("You are about to change the database '%s'. Continue") \ - % self.connection.name, [u_("y"), u_("n")], u_("n")) == u_("n"): - return False - self.connections.loginToConnection (self.connection) + # ------------------------------------------------------------------------- + # Import the given GSD files into the connection + # ------------------------------------------------------------------------- - print o(u_("Updating schema ...")) - commands = self.connection.writeSchema (self._schema, simulation) + def __import_schema(self): - # Dump the commands to the output file (if requested) - if self.outfile is not None: - dest = open (self.outfile, 'w') - try: - for line in commands: - dest.write ("%s%s" % (line, os.linesep)) + if self.OPTIONS['createdb']: + # Create a new database + if self.__ask(u_("You are about to create the new database '%s'. " \ + "Continue") % self.connection.name, + [u_("y"), u_("n")], "n") == u_("n"): + return False - finally: - dest.close () + self.connection.createDatabase() - return True + # Process schema information (if requested) + simulation = self.OPTIONS['file-only'] + if not simulation: + if self.__ask(u_("You are about to change the database '%s'. " \ + "Continue") % self.connection.name, + [u_("y"), u_("n")], u_("n")) == u_("n"): + return False + self.connections.loginToConnection(self.connection) - # --------------------------------------------------------------------------- - # Import the given <data> - # --------------------------------------------------------------------------- + print o(u_("Updating schema ...")) + commands = self.connection.writeSchema(self._schema, simulation) - def __importData (self): + # Dump the commands to the output file (if requested) + if self.outfile is not None: + dest = open(self.outfile, 'w') + try: + for line in commands: + dest.write("%s%s" % (line, os.linesep)) - print o(u_("Updating data ...")) + finally: + dest.close() - # First fetch the current schema from the backend - self._current = self.connection.readSchema () + return True - tables = {} - pkeys = {} - fields = {} - # Then make sure to have valid key information for all tables - for tdata in self._schema.findChildrenOfType ('GSTableData', False, True): - table = self.__findTable (tdata.tablename) - tables [table.name.lower ()] = (table, tdata) - fields [table.name.lower ()] = sets.Set ([f.name.lower () for f in \ - table.findChildrenOfType ('GSField', False, True)]) + # ------------------------------------------------------------------------- + # Import the given <data> + # ------------------------------------------------------------------------- - key = tdata.findChildOfType ('GSPrimaryKey') - if key is None: - key = self.__getKeyFromTable (table) - if key is not None: - GSchema.GSPrimaryKey (tdata).assign (key, True) + def __import_data(self): - else: - q = u_("The table '%s' has no key defined. Shall i insert all rows") \ - % table.name - if self.__ask (q, [u_("y"), u_("n")], u_("n")) == u_("n"): - tdata.getParent ()._children.remove (tdata) - del tables [table.name.lower ()] + print o(u_("Updating data ...")) - if key is not None: - pkeys [table.name.lower ()] = sets.Set ([f.name.lower () for f in \ - key.findChildrenOfType ('GSPKField', False, True)]) + # First fetch the current schema from the backend + self._current = self.connection.readSchema() - # Since we have all key information available now, double check the rows - for item in self._schema.findChildrenOfType ('GSTableData', False, True): - keySet = pkeys.get (item.tablename.lower ()) + tables = {} + pkeys = {} + fields = {} - for (n, r) in enumerate (item.findChildrenOfType ('GSRow',False,True)): - rowfields = sets.Set ([value.field.lower () \ - for value in r.findChildrenOfType ('GSValue', False, True)]) + # Then make sure to have valid key information for all tables + for tdata in self._schema.findChildrenOfType('GSTableData',False,True): + table = self.__findTable(tdata.tablename) + tables[table.name.lower()] = (table, tdata) + fields[table.name.lower()] = sets.Set([f.name.lower() for f in \ + table.findChildrenOfType('GSField', False, True)]) - # If the table has a key, are all keyfields available in the row - if keySet is not None and not keySet.issubset (rowfields): - raise MissingKeyFieldError, (item.tablename, n, keySet, rowfields) + key = tdata.findChildOfType('GSPrimaryKey') + if key is None: + key = self.__get_key_from_table(table) + if key is not None: + GSchema.GSPrimaryKey(tdata).assign(key, True) - # Are all fields in the row defined by the table - if not rowfields.issubset (fields [item.tablename.lower ()]): - raise InvalidFieldsError, \ - (item.tablename, n, rowfields.difference (fields [item.tablename])) + else: + q = u_("The table '%s' has no key defined. Shall i " \ + "insert all rows") % table.name + if self.__ask(q, [u_("y"), u_("n")], u_("n")) == u_("n"): + tdata.getParent()._children.remove(tdata) + del tables[table.name.lower()] - # Order the tables so the do not violate constraints - references = {} - fishhooks = {} + if key is not None: + pkeys[table.name.lower()] = sets.Set([f.name.lower() for f in \ + key.findChildrenOfType('GSPKField', False, True)]) - for (table, tdata) in tables.values (): - deps = references.setdefault (table.name.lower (), []) + # Since we have all key information available now, double check the + # rows + for item in self._schema.findChildrenOfType('GSTableData',False,True): + keySet = pkeys.get(item.tablename.lower()) - for fk in table.findChildrenOfType ('GSForeignKey', False, True): - fkname = fk.references.lower () + for (n, r) in enumerate(item.findChildrenOfType('GSRow', False, + True)): + rowfields = sets.Set([value.field.lower() \ + for value in r.findChildrenOfType('GSValue', False, True)]) - if fkname == table.name.lower (): - fishhooks.setdefault (table.name.lower (), []).append (fk) + # If the table has a key, are all keyfields available in the + # row + if keySet is not None and not keySet.issubset(rowfields): + raise MissingKeyFieldError, (item.tablename, n, keySet, + rowfields) - # Only add a dependency for a constraint, if we plan to add data for - # that table too - elif fkname in tables: - if not fkname in deps: - deps.append (fkname) + # Are all fields in the row defined by the table + if not rowfields.issubset(fields[item.tablename.lower()]): + raise InvalidFieldsError, (item.tablename, n, + rowfields.difference(fields[item.tablename])) - needCommit = False - for name in self.__orderByDependency (references): - (table, tdata) = tables [name] - if not name in pkeys: - needCommit |= self.__importAllInserts (table, tdata) - else: - needCommit |= self.__importTable (table, tdata, fishhooks.get (name)) + # Order the tables so the do not violate constraints + references = {} + fishhooks = {} - if needCommit: - self.connection.commit () + for (table, tdata) in tables.values(): + deps = references.setdefault(table.name.lower(), []) + for fk in table.findChildrenOfType('GSForeignKey', False, True): + fkname = fk.references.lower() - # ---------------------------------------------------------------------------- - # Import a table having a primary key - # ---------------------------------------------------------------------------- + if fkname == table.name.lower(): + fishhooks.setdefault(table.name.lower(), []).append(fk) - def __importTable (self, table, tabledata, fishes): + # Only add a dependency for a constraint, if we plan to add + # data for that table too + elif fkname in tables: + if not fkname in deps: + deps.append(fkname) - fields = {} - for field in table.findChildrenOfType ('GSField', False, True): - fields [field.name.lower ()] = field + needCommit = False + for name in self.__order_by_dependency(references): + (table, tdata) = tables[name] + if not name in pkeys: + needCommit |= self.__import_all_inserts(table, tdata) + else: + needCommit |= self.__import_table(table, tdata, + fishhooks.get(name)) - pkf = [f.name.lower () for f in \ - tabledata.findChildrenOfType ('GSPKField', False, True)] - rows = {} - rowFields = {} - fishLookup = {} + if needCommit: + self.connection.commit() - for row in tabledata.findChildrenOfType ('GSRow', False, True): - record = {} - for value in row.findChildrenOfType ('GSValue'): - fname = value.field.lower () - rowFields [fname] = True - record [fname] = self.__getValue (value, fields [fname]) - pkey = tuple ([record [k] for k in pkf]) - rows [pkey] = record + # -------------------------------------------------------------------------- + # Import a table having a primary key + # -------------------------------------------------------------------------- - if fishes is not None: - for fkey in fishes: - ref = [] - for fkfield in fkey.findChildrenOfType ('GSFKField'): - ref.append (record.get (fkfield.references.lower ())) + def __import_table(self, table, tabledata, fishes): - fishLookup.setdefault (fkey.name, {}) [tuple (ref)] = pkey + fields = {} + for field in table.findChildrenOfType('GSField', False, True): + fields[field.name.lower()] = field + pkf = [f.name.lower() for f in \ + tabledata.findChildrenOfType('GSPKField', False, True)] + rows = {} + rowFields = {} + fishLookup = {} - if fishes is not None: - sortdict = {} + for row in tabledata.findChildrenOfType('GSRow', False, True): + record = {} + for value in row.findChildrenOfType('GSValue'): + fname = value.field.lower() + rowFields[fname] = True + record[fname] = self.__getValue(value, fields[fname]) - for (key, data) in rows.items (): - deps = sortdict.setdefault (key, []) + pkey = tuple([record[k] for k in pkf]) + rows[pkey] = record - for fkey in fishes: - k = tuple ([data.get (f.name.lower ()) for f in \ - fkey.findChildrenOfType ('GSFKField')]) - rkey = fishLookup [fkey.name].get (k) + if fishes is not None: + for fkey in fishes: + ref = [] + for fkfield in fkey.findChildrenOfType('GSFKField'): + ref.append(record.get(fkfield.references.lower())) - if rkey is not None: - deps.append (rkey) + fishLookup.setdefault(fkey.name, {})[tuple(ref)] = pkey - recOrder = self.__orderByDependency (sortdict, CircularDataReferences, - table.name) - else: - recOrder = rows.keys () + if fishes is not None: + sortdict = {} - # Build a datasource and insert the data - source = GDataSource.DataSourceWrapper (connections = self.connections, - attributes = {'name' : "dts_%s" % table.name, - 'connection': self.connection.name, - 'table' : table.name, - 'primarykey': ",".join (pkf)}, - fields = rowFields.keys ()) + for (key, data) in rows.items(): + deps = sortdict.setdefault(key, []) - # Build a mapping for the existing table, based on the primary key - existing = {} - resultSet = source.createResultSet () + for fkey in fishes: + k = tuple([data.get(f.name.lower()) for f in \ + fkey.findChildrenOfType('GSFKField')]) + rkey = fishLookup[fkey.name].get(k) - rec = resultSet.firstRecord () - while rec is not None: - recKey = tuple ([rec [f] for f in pkf]) - existing [recKey] = rec + if rkey is not None: + deps.append(rkey) - rec = resultSet.nextRecord () + recOrder = self.__order_by_dependency(sortdict, + CircularDataReferences, table.name) + else: + recOrder = rows.keys() - # Now run over all datarows in the previously determined order - print o (u_(" updating table '%s' ...") % table.name) - doPost = False - new = 0 - upd = 0 + # Build a datasource and insert the data + source = GDataSource.DataSourceWrapper(connections = self.connections, + attributes = {'name' : "dts_%s" % table.name, + 'connection': self.connection.name, + 'table' : table.name, + 'primarykey': ",".join(pkf)}, + fields = rowFields.keys()) - for key in recOrder: - if key in existing: - rs = existing [key] - changed = 0 + # Build a mapping for the existing table, based on the primary key + existing = {} + resultSet = source.createResultSet() - for (field, value) in rows [key].items (): - (ov, nv) = GConditions.unify ([rs.getField (field), value]) - if ov != nv: - rs.setField (field, value) - changed = 1 + rec = resultSet.firstRecord() + while rec is not None: + recKey = tuple([rec[f] for f in pkf]) + existing[recKey] = rec - upd += changed + rec = resultSet.nextRecord() - else: - new += 1 - newRec = resultSet.insertRecord () - for (field, value) in rows [key].items (): - newRec.setField (field, value) + # Now run over all datarows in the previously determined order + print o(u_(" updating table '%s' ...") % table.name) + doPost = False + new = 0 + upd = 0 - if new or upd: - resultSet.post () + for key in recOrder: + if key in existing: + rs = existing[key] + changed = 0 - print o (u_(" Rows: %(ins)d inserted, %(upd)d updated, %(kept)d " - "unchanged.") \ - % {'ins': new, 'upd': upd, 'kept': len (rows) - upd - new}) + for (field, value) in rows[key].items(): + (ov, nv) = GConditions.unify([rs.getField(field), value]) + if ov != nv: + rs.setField(field, value) + changed = 1 - return (new + upd) > 0 + upd += changed + else: + new += 1 + newRec = resultSet.insertRecord() + for (field, value) in rows[key].items(): + newRec.setField(field, value) - # --------------------------------------------------------------------------- - # Import a table by inserting all it's rows - # --------------------------------------------------------------------------- + if new or upd: + resultSet.post() - def __importAllInserts (self, table, tabledata): - - fields = {} - for field in table.findChildrenOfType ('GSField', False, True): - fields [field.name.lower ()] = field + print o(u_(" Rows: %(ins)d inserted, %(upd)d updated, %(kept)d " + "unchanged.") \ + % {'ins': new, 'upd': upd, 'kept': len(rows) - upd - new}) - rows = [] - rowFields = {} + return (new + upd) > 0 - for row in tabledata.findChildrenOfType ('GSRow', False, True): - record = {} - for value in row.findChildrenOfType ('GSValue'): - fname = value.field.lower () - rowFields [fname] = True - record [fname] = self.__getValue (value, fields [fname]) - rows.append (record) + # ------------------------------------------------------------------------- + # Import a table by inserting all it's rows + # ------------------------------------------------------------------------- - if not rows: - return False + def __import_all_inserts(self, table, tabledata): - # Build a datasource and insert the data - source = GDataSource.DataSourceWrapper (connections = self.connections, + fields = {} + for field in table.findChildrenOfType('GSField', False, True): + fields[field.name.lower()] = field + + rows = [] + rowFields = {} + + for row in tabledata.findChildrenOfType('GSRow', False, True): + record = {} + for value in row.findChildrenOfType('GSValue'): + fname = value.field.lower() + rowFields[fname] = True + record[fname] = self.__getValue(value, fields[fname]) + + rows.append(record) + + if not rows: + return False + + # Build a datasource and insert the data + source = GDataSource.DataSourceWrapper(connections = self.connections, attributes = {'name' : "dts_%s" % table.name, 'connection': self.connection.name, 'table' : table.name}, - fields = rowFields.keys ()) + fields = rowFields.keys()) - print o (u_(" inserting into table '%s' ...") % table.name) + print o(u_(" inserting into table '%s' ...") % table.name) - resultSet = source.createEmptyResultSet () - for record in rows: - new = resultSet.insertRecord () - for (field, value) in record.items (): - new.setField (field, value) + resultSet = source.createEmptyResultSet() + for record in rows: + new = resultSet.insertRecord() + for (field, value) in record.items(): + new.setField(field, value) - resultSet.post () + resultSet.post() - print o (u_(" Rows: %(ins)d inserted") % {'ins': len (rows)}) + print o(u_(" Rows: %(ins)d inserted") % {'ins': len(rows)}) - return True + return True - # --------------------------------------------------------------------------- - # Order a given dependency tree - # --------------------------------------------------------------------------- + # ------------------------------------------------------------------------- + # Order a given dependency tree + # ------------------------------------------------------------------------- - def __orderByDependency (self, depTree, error = CircularReferenceError, *ea): + def __order_by_dependency(self, depTree, error=CircularReferenceError, *ea): - result = [] + result = [] - while depTree: - addition = [] + while depTree: + addition = [] - for (key, deps) in depTree.items (): - # If a key has no dependencies, add it to the result - if not len (deps): - addition.append (key) + for (key, deps) in depTree.items(): + # If a key has no dependencies, add it to the result + if not len(deps): + addition.append(key) - # and remove that key from all other dependency sequences - for otherDeps in depTree.values (): - if key in otherDeps: - otherDeps.remove (key) + # and remove that key from all other dependency sequences + for otherDeps in depTree.values(): + if key in otherDeps: + otherDeps.remove(key) - # finally remove it from the dictionary - del depTree [key] + # finally remove it from the dictionary + del depTree[key] - # If no key without a dependency was found, but there are still - # entries in the tree, they *must* have circular references - if not addition and depTree: - raise error, ea + # If no key without a dependency was found, but there are still + # entries in the tree, they *must* have circular references + if not addition and depTree: + raise error, ea - result.extend (addition) + result.extend(addition) - return result + return result - # --------------------------------------------------------------------------- - # Get a native python value from a GSValue instance using a given GSField - # --------------------------------------------------------------------------- + # ------------------------------------------------------------------------- + # Get a native python value from a GSValue instance using a given GSField + # ------------------------------------------------------------------------- - def __getValue (self, value, field): + def __getValue(self, value, field): - ftype = field.type.lower () - contents = value.getChildrenAsContent () + ftype = field.type.lower() + contents = value.getChildrenAsContent() - # unquote the contents if it is quoted - if len (contents) > 1 and contents [0] in ["'", '"']: - if contents [-1] == contents [0]: - contents = contents [1:-1] + # unquote the contents if it is quoted + if len(contents) > 1 and contents[0] in ["'", '"']: + if contents[-1] == contents[0]: + contents = contents[1:-1] - # If no value is given, just return None - if not len (contents): - return None + # If no value is given, just return None + if not len(contents): + return None - length = hasattr (field, 'length') and field.length or 0 - scale = hasattr (field, 'precision') and field.precision or 0 + length = hasattr(field, 'length') and field.length or 0 + scale = hasattr(field, 'precision') and field.precision or 0 - # return string type fields with an optional length restriction - if ftype == 'string': - maxlen = length and length or len (contents) - return contents [:maxlen] + # return string type fields with an optional length restriction + if ftype == 'string': + maxlen = length and length or len(contents) + return contents[:maxlen] - # Try to convert a numeric field according to length and scale - elif ftype == 'number': - value = contents.strip () + # Try to convert a numeric field according to length and scale + elif ftype == 'number': + value = contents.strip() - if value in [u'TRUE', u'FALSE']: - return int (value == u'TRUE') + if value in [u'TRUE', u'FALSE']: + return int(value == u'TRUE') - elif length or scale: - vmatch = re.compile ('^([+-]{0,1})(\d+)[\.]{0,1}(\d*)$').match (value) - if vmatch is None: - raise InvalidNumberError, (value, length, scale) + elif length or scale: + vmatch = re.compile('^([+-]{0,1})(\d+)[\.]{0,1}(\d*)$').match(\ + value) + if vmatch is None: + raise InvalidNumberError, (value, length, scale) - (sign, pre, frac) = vmatch.groups () - if len (pre) > (length - scale) or len (frac) > scale: - OutOfRangeError, (value, length, scale) + (sign, pre, frac) = vmatch.groups() + if len(pre) > (length - scale) or len(frac) > scale: + OutOfRangeError, (value, length, scale) - if len (frac): - return float ("%s%s.%s" % (sign, pre, frac)) + if len(frac): + return float("%s%s.%s" % (sign, pre, frac)) - else: - return int ("%s%s" % (sign, pre)) + else: + return int("%s%s" % (sign, pre)) - # we don't know anything about precision - else: - if '.' in value or ',' in value: - return float (value) + # we don't know anything about precision + else: + if '.' in value or ',' in value: + return float(value) - else: - return int (value) + else: + return int(value) - # booleans must be 'TRUE' or 'FALSE', otherwise they're None - elif ftype == 'boolean': - bool = contents.upper ().strip () - if bool in ['TRUE', 'FALSE']: - return bool == 'TRUE' - else: - raise InvalidBooleanError, bool + # booleans must be 'TRUE' or 'FALSE', otherwise they're None + elif ftype == 'boolean': + bool = contents.upper().strip() + if bool in ['TRUE', 'FALSE']: + return bool == 'TRUE' + else: + raise InvalidBooleanError, bool - # Dates must conform with the ISO spec: YYYY-MM-DD - elif ftype == 'date': - try: - return GDateTime.parseISODate (contents.strip ()) + # Dates must conform with the ISO spec: YYYY-MM-DD + elif ftype == 'date': + try: + return GDateTime.parseISODate(contents.strip()) - except ValueError: - raise InvalidDateError, contents.strip () + except ValueError: + raise InvalidDateError, contents.strip() - # Times must conform with the ISO spec: HH:[MM:[:SS[.ss]]] - elif ftype == 'time': - try: - return GDateTime.parseISOTime (contents.strip ()) + # Times must conform with the ISO spec: HH:[MM:[:SS[.ss]]] + elif ftype == 'time': + try: + return GDateTime.parseISOTime(contents.strip()) - except ValueError: - raise InvalidTimeError, contents.strip () + except ValueError: + raise InvalidTimeError, contents.strip() - elif ftype == 'datetime': - try: - return GDateTime.parseISO (contents.strip ()) + elif ftype == 'datetime': + try: + return GDateTime.parseISO(contents.strip()) - except ValueError: - raise InvalidDateTimeError, contents.strip () + except ValueError: + raise InvalidDateTimeError, contents.strip() - else: - raise InvalidTypeError, ftype + else: + raise InvalidTypeError, ftype - # ---------------------------------------------------------------------------- - # Find a given GSTable instance in the current schema - # ---------------------------------------------------------------------------- + # -------------------------------------------------------------------------- + # Find a given GSTable instance in the current schema + # -------------------------------------------------------------------------- - def __findTable (self, name): + def __findTable(self, name): - for item in self._current.findChildrenOfType ('GSTable', False, True): - if item.name.lower () == name.lower (): - return item + for item in self._current.findChildrenOfType('GSTable', False, True): + if item.name.lower() == name.lower(): + return item - raise MissingTableError, (name) + raise MissingTableError, (name) - # ---------------------------------------------------------------------------- - # Get a usable key from the given table - # ---------------------------------------------------------------------------- + # -------------------------------------------------------------------------- + # Get a usable key from the given table + # -------------------------------------------------------------------------- - def __getKeyFromTable (self, table): + def __get_key_from_table(self, table): - # Is there a PK defined in the backend schema ? - pk = table.findChildOfType ('GSPrimaryKey') - if pk is not None: - return pk + # Is there a PK defined in the backend schema ? + pk = table.findChildOfType('GSPrimaryKey') + if pk is not None: + return pk - # Maybe we could use a 'unique index' to as key, since it has the same - # nature as a primary key. But then we have to check wether all <rows> - # have all fields used by the index available. This is left for a future - # version though :) + # Maybe we could use a 'unique index' to as key, since it has the same + # nature as a primary key. But then we have to check wether all <rows> + # have all fields used by the index available. This is left for a future + # version though :) - return None + return None - # --------------------------------------------------------------------------- - # Ask a question with a set of valid options and a default - # --------------------------------------------------------------------------- + # ------------------------------------------------------------------------- + # Ask a question with a set of valid options and a default + # ------------------------------------------------------------------------- - def __ask (self, question, options, default): - """ - Ask for a question, allowing a set of answers, using a default-value if the - user just presses <Enter>. + def __ask(self, question, options, default): + """ + Ask for a question, allowing a set of answers, using a default-value if + the user just presses <Enter>. - @param question: string with the question to ask - @param options: sequence of allowed options, i.e. ['y', 'n'] - @param default: string with the default option + @param question: string with the question to ask + @param options: sequence of allowed options, i.e. ['y', 'n'] + @param default: string with the default option - @return: string with the option selected - """ + @return: string with the option selected + """ - if self.OPTIONS ['yes']: - return u_("y") + if self.OPTIONS['yes']: + return u_("y") - answer = None - default = default.lower () - lopts = [opt.lower () for opt in options] + answer = None + default = default.lower() + lopts = [opt.lower() for opt in options] - dopts = [] - for item in lopts: - dopts.append (item == default and item.upper () or item) + dopts = [] + for item in lopts: + dopts.append(item == default and item.upper() or item) - while True: - print o(question), o("[%s]:" % ",".join (dopts)), - answer = raw_input ().lower () or default + while True: + print o(question), o("[%s]:" % ",".join(dopts)), + answer = raw_input().lower() or default - if answer in lopts: - break + if answer in lopts: + break - return answer + return answer # ============================================================================= @@ -775,4 +790,4 @@ # ============================================================================= if __name__ == '__main__': - gsdClient ().run () + gsdClient().run() _______________________________________________ commit-gnue mailing list commit-gnue@gnu.org http://lists.gnu.org/mailman/listinfo/commit-gnue