def load_database(self, database):
        """
        Load the given database, whatever it might be.

        A connection string: ``sqlite:///database.sqlite``

        A dictionary: ``{'engine': 'SqliteDatabase', 'name': 'database.sqlite'}``

        A peewee.Database instance: ``peewee.SqliteDatabase('database.sqlite')``

        :param database: Connection string, dict, or peewee.Database instance to use.
        :raises: peewee.DatabaseError if database connection cannot be established.
        :return: Database connection.
        :rtype: peewee.Database instance.
        """
        # It could be an actual instance...
        if isinstance(database, (peewee.Proxy, peewee.Database)):
            return database

        # It could be a dictionary...
        if isinstance(database, dict):
            try:
                name = database.pop('name')
                engine = database.pop('engine')
            except KeyError:
                error_msg = 'Configuration dict must specify "name" and "engine" keys.'
                raise peewee.DatabaseError(error_msg)

            db_class = pydoc.locate(engine)
            if not db_class:
                raise peewee.DatabaseError(
                    'Unable to import engine class: {}'.format(engine))
            return db_class(name, **database)

        # Or it could be a database URL.
        return url_connect(database)
Exemple #2
0
    def reflect(self):
        """Adds fields and indexes to the model using reflection."""

        meta = self._meta
        database = meta.database
        table_name = meta.table_name
        schema = meta.schema

        if not database or not database.connected:
            return

        # Lists tables in the schema. This is a bit of a hack but
        # faster than using database.table_exists because it's cached.
        database.get_fields(table_name, schema)  # Force caching of _metadata.
        schema_tables = database._metadata[schema].keys()

        if table_name not in schema_tables:
            return

        for index in meta.indexes:
            if hasattr(index, 'reflected') and index.reflected:
                meta.indexes.remove(index)

        if not database.is_connection_usable():
            raise peewee.DatabaseError('database not connected.')

        if hasattr(meta, 'reflection_options'):
            opts = meta.reflection_options
            skip_fks = opts.get('skip_foreign_keys', False)
            use_peewee_reflection = opts.get('use_peewee_reflection', True)
        else:
            skip_fks = False
            use_peewee_reflection = True

        try:

            if use_peewee_reflection:

                # Check for locks. We only need to do this if using the Peewee
                # reflection because one of the queries it does can be blocked
                # by a AccessExclusiveLock lock.
                locks = is_table_locked(database, table_name)
                if locks and 'AccessExclusiveLock' in locks:
                    warnings.warn(
                        f'table {schema}.{table_name} is locked and '
                        'will not be reflected.', SdssdbUserWarning)
                    return

                introspector = database.get_introspector(schema)
                reflected_model = introspector.generate_models(
                    table_names=[table_name])[table_name]
                fields = reflected_model._meta.fields

            else:
                fields = database.get_fields(table_name, schema)
                fields = {field.column_name: field for field in fields}

        except KeyError as ee:
            warnings.warn(
                f'reflection failed for {table_name}: '
                f'table or column {ee} not found.', SdssdbUserWarning)
            return

        except Exception as ee:
            warnings.warn(f'reflection failed for {table_name}: {ee}',
                          SdssdbUserWarning)
            return

        for field_name, field in fields.items():

            if field_name in keyword.kwlist:
                field_name += '_'

            if field_name in meta.fields:
                meta_field = meta.fields[field_name]
                if not getattr(meta_field, 'reflected', False):
                    continue

            if isinstance(field, peewee.ForeignKeyField) and skip_fks:
                continue

            if field.primary_key:
                meta.set_primary_key(field_name, field)
            else:
                meta.add_field(field_name, field)

            meta.fields[field_name].reflected = True

        # Composite keys are not a normal column so if the pk has not been
        # set already, check if it exists in the reflected model. We avoid
        # adding pks that are foreign keys.
        if not meta.primary_key:
            if use_peewee_reflection and reflected_model._meta.primary_key:
                pk = reflected_model._meta.primary_key
                if not isinstance(pk, peewee.ForeignKeyField) or not skip_fks:
                    meta.set_primary_key(pk.name, pk)
            elif not use_peewee_reflection:
                pk = database.get_primary_keys(table_name, schema)
                if len(pk) > 1:
                    pk = peewee.CompositeKey(*pk)
                    meta.set_primary_key('__composite_key__', pk)