Refactoring to get away from cyclical imports.
authorJoel Rosdahl <joel@rosdahl.net>
Wed, 28 Sep 2005 20:14:50 +0000 (20:14 +0000)
committerJoel Rosdahl <joel@rosdahl.net>
Wed, 28 Sep 2005 20:14:50 +0000 (20:14 +0000)
src/packages/kofoto/albumtype.py [new file with mode: 0644]
src/packages/kofoto/imageversiontype.py [new file with mode: 0644]
src/packages/kofoto/search.py
src/packages/kofoto/shelf.py
src/packages/kofoto/shelfexceptions.py [new file with mode: 0644]
src/packages/kofoto/shelfschema.py [new file with mode: 0644]
src/packages/kofoto/shelfupgrade.py
src/test/shelftests.py

diff --git a/src/packages/kofoto/albumtype.py b/src/packages/kofoto/albumtype.py
new file mode 100644 (file)
index 0000000..d2ca1fd
--- /dev/null
@@ -0,0 +1,5 @@
+"""Type of an album."""
+
+from kofoto.alternative import Alternative
+
+AlbumType = Alternative("Orphans", "Plain", "Search")
diff --git a/src/packages/kofoto/imageversiontype.py b/src/packages/kofoto/imageversiontype.py
new file mode 100644 (file)
index 0000000..1e70ac0
--- /dev/null
@@ -0,0 +1,5 @@
+"""Type of a image version."""
+
+from kofoto.alternative import Alternative
+
+ImageVersionType = Alternative("Important", "Original", "Other")
index 973d462..ea37603 100644 (file)
@@ -44,7 +44,7 @@ __all__ = [
 
 import re
 from kofoto.common import KofotoError, UnimplementedError
-import kofoto.shelf
+from kofoto.albumtype import AlbumType
 
 class ParseError(KofotoError):
     """Base class for parse error exceptions related to search expressions."""
@@ -77,10 +77,10 @@ class SearchNodeFactory:
 
         tag_or_album -- A tag string or Album instance.
         """
-        if isinstance(tag_or_album, kofoto.shelf.Album):
-            album = tag_or_album
-        else:
+        if isinstance(tag_or_album, basestring):
             album = self._shelf.getAlbumByTag(tag_or_album)
+        else:
+            album = tag_or_album
         return AlbumSearchNode(self._shelf, album)
 
     def andNode(self, subnodes):
@@ -111,10 +111,10 @@ class SearchNodeFactory:
 
         tag_or_category -- A tag string or Category instance.
         """
-        if isinstance(tag_or_category, kofoto.shelf.Category):
-            category = tag_or_category
-        else:
+        if isinstance(tag_or_category, basestring):
             category = self._shelf.getCategoryByTag(tag_or_category)
+        else:
+            category = tag_or_category
         if recursive:
             catids = list(self._shelf.categorydag.get().getDescendants(
                 category.getId()))
@@ -282,17 +282,17 @@ class AlbumSearchNode(SearchNode):
     def getQuery(self):
         """Return the SQL expression for the node."""
         t = self._album.getType()
-        if t == kofoto.shelf.AlbumType.Orphans:
+        if t == AlbumType.Orphans:
             return (" select i.id"
                     " from   image as i left join attribute as a"
                     " on     i.id = a.object and a.name = 'captured'"
                     " where  i.id not in (select object from member)"
                     " order by a.lcvalue")
-        elif t == kofoto.shelf.AlbumType.Plain:
+        elif t == AlbumType.Plain:
             return (" select distinct object"
                     " from   member"
                     " where  album = %s" % self._album.getId())
-        elif t == kofoto.shelf.AlbumType.Search:
+        elif t == AlbumType.Search:
             query = self._album.getAttribute(u"query")
             if not query:
                 return ""
index 1b3c8ab..ecd83c8 100644 (file)
@@ -4,36 +4,9 @@
 ### Public names.
 
 __all__ = [
-    "AlbumDoesNotExistError",
-    "AlbumExistsError",
-    "AlbumType",
-    "BadAlbumTagError",
-    "BadCategoryTagError",
-    "CategoriesAlreadyConnectedError",
-    "CategoryDoesNotExistError",
-    "CategoryExistsError",
-    "CategoryLoopError",
-    "CategoryPresentError",
-    "FailedWritingError",
-    "ImageDoesNotExistError",
-    "ImageVersionDoesNotExistError",
-    "ImageVersionExistsError",
-    "ImageVersionType",
-    "MultipleImageVersionsAtOneLocationError",
-    "NotAnImageFileError",
-    "ObjectDoesNotExistError",
-    "SearchExpressionParseError",
     "Shelf",
-    "ShelfLockedError",
-    "ShelfNotFoundError",
-    "UndeletableAlbumError",
-    "UnknownAlbumTypeError",
-    "UnknownImageVersionTypeError",
-    "UnsettableChildrenError",
-    "UnsupportedShelfError",
     "computeImageHash",
     "makeValidTag",
-    "schema",
     "verifyValidAlbumTag",
     "verifyValidCategoryTag",
 ]
@@ -46,11 +19,37 @@ import re
 import threading
 import sqlite as sql
 from sets import Set
-from kofoto.common import KofotoError, UnimplementedError
+from kofoto.common import UnimplementedError
 from kofoto.dag import DAG, LoopError
 from kofoto.cachedobject import CachedObject
-from kofoto.alternative import Alternative
+from kofoto.albumtype import AlbumType
+from kofoto.imageversiontype import ImageVersionType
 import kofoto.shelfupgrade
+import kofoto.shelfschema
+from kofoto.shelfexceptions import \
+    AlbumDoesNotExistError, \
+    AlbumExistsError, \
+    BadAlbumTagError, \
+    BadCategoryTagError, \
+    CategoriesAlreadyConnectedError, \
+    CategoryDoesNotExistError, \
+    CategoryExistsError, \
+    CategoryLoopError, \
+    CategoryPresentError, \
+    FailedWritingError, \
+    ImageDoesNotExistError, \
+    ImageVersionDoesNotExistError, \
+    ImageVersionExistsError, \
+    MultipleImageVersionsAtOneLocationError, \
+    NotAnImageFileError, \
+    ObjectDoesNotExistError, \
+    ShelfLockedError, \
+    ShelfNotFoundError, \
+    UndeletableAlbumError, \
+    UnknownAlbumTypeError, \
+    UnknownImageVersionTypeError, \
+    UnsettableChildrenError, \
+    UnsupportedShelfError
 
 import warnings
 warnings.filterwarnings("ignore", "DB-API extension")
@@ -59,330 +58,13 @@ warnings.filterwarnings(
     ".*losing bits or changing sign will return a long.*",
     FutureWarning)
 
+
 ######################################################################
-### Database schema.
-
-schema = """
-    -- EER diagram without attributes:
-    --
-    --                                          .----.
-    --                                        ,'      |
-    --                   ,^.                ,' N    ,^.
-    --                 ,'   '.  N +----------+    ,'   '.
-    --                <  has  >===| category |---< child >
-    --                 '.   .'    +----------+ 0  '.   .'
-    --                   'v'                        'v'
-    --                    | 0
-    --                    |           ,^.
-    --              N +--------+ 0  ,'   '.  N +-----------+
-    --      .---------| object |---<  has  >===| attribute |
-    --      |         +--------+    '.   ,'    +-----------+
-    --    ,/\.          |    |        'v'
-    --  ,'    '.     __/      \__
-    -- < member >   |            |
-    --  '.    ,'   \|/          \|/
-    --    '\/'      |            |
-    --      | 1 +-------+    +-------+
-    --      '---| album |    | image |
-    --          +-------+    +-------+
-    --                        1 | | 1
-    --                       ,-'   '-.
-    --                     ,^.       ,^.
-    --                   ,'   '.   ,'   '.
-    --                  <  has  > <primary>
-    --                   '.   .'   '.   .'
-    --                     'v'       'v'
-    --                     N \       / 0..1
-    --                      +---------+
-    --                      | version |
-    --                      +---------+
-    --
-    --        |
-    -- where \|/ is supposed to look like the subclass relation symbol.
-    --        |
-
-    -- Administrative information about the database.
-    CREATE TABLE dbinfo (
-        version     INTEGER NOT NULL
-    );
-
-    -- Superclass of objects in an album.
-    CREATE TABLE object (
-        -- Identifier of the object.
-        id          INTEGER NOT NULL,
-
-        PRIMARY KEY (id)
-    );
-
-    -- Albums in the shelf. Subclass of object.
-    CREATE TABLE album (
-        -- Identifier of the album. Shared primary key with object.
-        id          INTEGER NOT NULL,
-        -- Human-memorizable tag.
-        tag         VARCHAR(256) NOT NULL,
-        -- Whether it is possible to delete the album.
-        deletable   INTEGER NOT NULL,
-        -- Album type (plain, orphans or search).
-        type        VARCHAR(256) NOT NULL,
-
-        UNIQUE      (tag),
-        FOREIGN KEY (id) REFERENCES object,
-        PRIMARY KEY (id)
-    );
-
-    -- Images in the shelf. Subclass of object.
-    CREATE TABLE image (
-        -- Internal identifier of the image. Shared primary key with
-        -- object.
-        id          INTEGER NOT NULL,
-
-        -- The primary version. NULL if no such version exists.
-        primary_version INTEGER,
-
-        FOREIGN KEY (id) REFERENCES object,
-        FOREIGN KEY (primary_version) REFERENCES image_version,
-        PRIMARY KEY (id)
-    );
-
-    -- Image versions.
-    CREATE TABLE image_version (
-        -- Identifier of the image version.
-        id          INTEGER NOT NULL,
-
-        -- Identifier of the image associated with this version.
-        image       INTEGER NOT NULL,
-
-        -- Type (original, important or other).
-        type        VARCHAR(20) NOT NULL,
-
-        -- Arbitrary comment about the version.
-        comment     TEXT NOT NULL,
-
-        -- Identifier string which is derived from the image data and
-        -- identifies the image uniquely. Currently an MD5 checksum
-        -- (in hex format) of all image data.
-        hash        CHAR(32) NOT NULL,
-        -- Directory part of the last known location (local pathname)
-        -- of the image.
-        directory   VARCHAR(256) NOT NULL,
-        -- Filename part of the last known location (local pathname)
-        -- of the image.
-        filename    VARCHAR(256) NOT NULL,
-        -- Last known time of modification (UNIX epoch time).
-        mtime       INTEGER NOT NULL,
-        -- Image width.
-        width       INTEGER NOT NULL,
-        -- Image height.
-        height      INTEGER NOT NULL,
-        
-        FOREIGN KEY (image) REFERENCES image,
-        UNIQUE      (hash),
-        PRIMARY KEY (id)
-    );
-
-    CREATE INDEX image_version_image_index ON image_version (image);
-    CREATE INDEX image_version_location_index ON image_version (directory, filename);
-
-    -- Members in an album.
-    CREATE TABLE member (
-        -- Identifier of the album.
-        album       INTEGER NOT NULL,
-        -- Member position, from 0 and up.
-        position    UNSIGNED NOT NULL,
-        -- Key of the member object.
-        object      INTEGER NOT NULL,
-
-        FOREIGN KEY (album) REFERENCES album,
-        FOREIGN KEY (object) REFERENCES object,
-        PRIMARY KEY (album, position)
-    );
-
-    CREATE INDEX member_object_index ON member (object);
-
-    -- Attributes for objects.
-    CREATE TABLE attribute (
-        -- Key of the object.
-        object      INTEGER NOT NULL,
-        -- Name of the attribute.
-        name        TEXT NOT NULL,
-        -- Value of the attribute.
-        value       TEXT NOT NULL,
-        -- Lowercased value of the attribute.
-        lcvalue     TEXT NOT NULL,
-
-        FOREIGN KEY (object) REFERENCES object,
-        PRIMARY KEY (object, name)
-    );
-
-    -- Categories in the shelf.
-    CREATE TABLE category (
-        -- Key of the category.
-        id          INTEGER NOT NULL,
-        -- Human-memorizable tag.
-        tag         TEXT NOT NULL,
-        -- Short description of the category.
-        description TEXT NOT NULL,
-
-        UNIQUE      (tag),
-        PRIMARY KEY (id)
-    );
-
-    -- Parent-child relations between categories.
-    CREATE TABLE category_child (
-        -- Parent category.
-        parent      INTEGER NOT NULL,
-
-        -- Child category.
-        child       INTEGER NOT NULL,
-
-        FOREIGN KEY (parent) REFERENCES category,
-        FOREIGN KEY (child) REFERENCES category,
-        PRIMARY KEY (parent, child)
-    );
-
-    CREATE INDEX category_child_child ON category_child (child);
-
-    -- Category-object mapping.
-    CREATE TABLE object_category (
-        -- Object.
-        object      INTEGER NOT NULL,
-
-        -- Category.
-        category    INTEGER NOT NULL,
-
-        FOREIGN KEY (object) REFERENCES object,
-        FOREIGN KEY (category) REFERENCES category,
-        PRIMARY KEY (object, category)
-    );
-
-    CREATE INDEX object_category_category ON object_category (category);
-"""
+### Constants.
 
 _ROOT_ALBUM_ID = 0
 _SHELF_FORMAT_VERSION = 3
 
-######################################################################
-### Exceptions.
-
-class ObjectDoesNotExistError(KofotoError):
-    """Object does not exist in the album."""
-    pass
-
-
-class AlbumDoesNotExistError(ObjectDoesNotExistError):
-    """Album does not exist in the album."""
-    pass
-
-
-class AlbumExistsError(KofotoError):
-    """Album already exists in the shelf."""
-    pass
-
-
-class BadAlbumTagError(KofotoError):
-    """Bad album tag."""
-    pass
-
-
-class BadCategoryTagError(KofotoError):
-    """Bad category tag."""
-    pass
-
-
-class CategoriesAlreadyConnectedError(KofotoError):
-    """The categories are already connected."""
-    pass
-
-
-class CategoryDoesNotExistError(KofotoError):
-    """Category does not exist."""
-    pass
-
-
-class CategoryExistsError(KofotoError):
-    """Category already exists."""
-    pass
-
-
-class CategoryLoopError(KofotoError):
-    """Connecting the categories would create a loop in the category DAG."""
-    pass
-
-
-class CategoryPresentError(KofotoError):
-    """The object is already associated with this category."""
-    pass
-
-
-class FailedWritingError(KofotoError):
-    """Kofoto shelf already exists."""
-    pass
-
-
-class ImageDoesNotExistError(KofotoError):
-    """Image does not exist."""
-    pass
-
-
-class ImageVersionDoesNotExistError(KofotoError):
-    """Image version does not exist."""
-    pass
-
-
-class ImageVersionExistsError(KofotoError):
-    """Image version already exists in the shelf."""
-    pass
-
-
-class MultipleImageVersionsAtOneLocationError(KofotoError):
-    """Failed to identify image version by location since the location
-    isn't unique."""
-    pass
-
-
-class NotAnImageFileError(KofotoError):
-    """Could not recognise file as an image file."""
-    pass
-
-
-class SearchExpressionParseError(KofotoError):
-    """Could not parse search expression."""
-    pass
-
-
-class ShelfLockedError(KofotoError):
-    """The shelf is locked by another process."""
-    pass
-
-
-class ShelfNotFoundError(KofotoError):
-    """Kofoto shelf not found."""
-    pass
-
-
-class UndeletableAlbumError(KofotoError):
-    """Album is not deletable."""
-    pass
-
-
-class UnknownAlbumTypeError(KofotoError):
-    """The album type is unknown."""
-    pass
-
-
-class UnknownImageVersionTypeError(KofotoError):
-    """The image version type is unknown."""
-    pass
-
-
-class UnsettableChildrenError(KofotoError):
-    """The album is magic and doesn't have any explicit children."""
-    pass
-
-
-class UnsupportedShelfError(KofotoError):
-    """Unsupported shelf database format."""
-
 
 ######################################################################
 ### Public functions.
@@ -441,13 +123,6 @@ def makeValidTag(tag):
     return tag
 
 
-######################################################################
-### Public alternatives.
-
-AlbumType = Alternative("Orphans", "Plain", "Search")
-ImageVersionType = Alternative("Important", "Original", "Other")
-
-
 ######################################################################
 ### Public classes.
 
@@ -1276,7 +951,7 @@ class Shelf:
     def _createShelf(self):
         """Helper method for Shelf.create."""
         cursor = self.connection.cursor()
-        cursor.execute(schema)
+        cursor.execute(kofoto.shelfschema.schema)
         cursor.execute(
             " insert into dbinfo (version)"
             " values (%s)",
diff --git a/src/packages/kofoto/shelfexceptions.py b/src/packages/kofoto/shelfexceptions.py
new file mode 100644 (file)
index 0000000..5a2bda2
--- /dev/null
@@ -0,0 +1,102 @@
+"""Shelf-related exceptions."""
+
+__all__ = [
+    "AlbumDoesNotExistError",
+    "AlbumExistsError",
+    "BadAlbumTagError",
+    "BadCategoryTagError",
+    "CategoriesAlreadyConnectedError",
+    "CategoryDoesNotExistError",
+    "CategoryExistsError",
+    "CategoryLoopError",
+    "CategoryPresentError",
+    "FailedWritingError",
+    "ImageDoesNotExistError",
+    "ImageVersionDoesNotExistError",
+    "ImageVersionExistsError",
+    "MultipleImageVersionsAtOneLocationError",
+    "NotAnImageFileError",
+    "ObjectDoesNotExistError",
+    "ShelfLockedError",
+    "ShelfNotFoundError",
+    "UndeletableAlbumError",
+    "UnknownAlbumTypeError",
+    "UnknownImageVersionTypeError",
+    "UnsettableChildrenError",
+    "UnsupportedShelfError",
+]
+
+from kofoto.common import KofotoError
+
+class ObjectDoesNotExistError(KofotoError):
+    """Object does not exist in the album."""
+
+class AlbumDoesNotExistError(ObjectDoesNotExistError):
+    """Album does not exist in the album."""
+
+class AlbumExistsError(KofotoError):
+    """Album already exists in the shelf."""
+
+class BadAlbumTagError(KofotoError):
+    """Bad album tag."""
+
+class BadCategoryTagError(KofotoError):
+    """Bad category tag."""
+
+class CategoriesAlreadyConnectedError(KofotoError):
+    """The categories are already connected."""
+
+class CategoryDoesNotExistError(KofotoError):
+    """Category does not exist."""
+
+class CategoryExistsError(KofotoError):
+    """Category already exists."""
+
+class CategoryLoopError(KofotoError):
+    """Connecting the categories would create a loop in the category DAG."""
+
+class CategoryPresentError(KofotoError):
+    """The object is already associated with this category."""
+
+class FailedWritingError(KofotoError):
+    """Kofoto shelf already exists."""
+
+class ImageDoesNotExistError(KofotoError):
+    """Image does not exist."""
+
+class ImageVersionDoesNotExistError(KofotoError):
+    """Image version does not exist."""
+
+class ImageVersionExistsError(KofotoError):
+    """Image version already exists in the shelf."""
+
+class MultipleImageVersionsAtOneLocationError(KofotoError):
+    """Failed to identify image version by location since the location
+    isn't unique."""
+
+class NotAnImageFileError(KofotoError):
+    """Could not recognise file as an image file."""
+
+class SearchExpressionParseError(KofotoError):
+    """Could not parse search expression."""
+
+class ShelfLockedError(KofotoError):
+    """The shelf is locked by another process."""
+
+class ShelfNotFoundError(KofotoError):
+    """Kofoto shelf not found."""
+
+class UndeletableAlbumError(KofotoError):
+    """Album is not deletable."""
+
+class UnknownAlbumTypeError(KofotoError):
+    """The album type is unknown."""
+
+class UnknownImageVersionTypeError(KofotoError):
+    """The image version type is unknown."""
+
+class UnsettableChildrenError(KofotoError):
+    """The album is magic and doesn't have any explicit children."""
+
+class UnsupportedShelfError(KofotoError):
+    """Unsupported shelf database format."""
diff --git a/src/packages/kofoto/shelfschema.py b/src/packages/kofoto/shelfschema.py
new file mode 100644 (file)
index 0000000..1ad38ca
--- /dev/null
@@ -0,0 +1,197 @@
+"""Schema of the metadata database."""
+
+schema = """
+    -- EER diagram without attributes:
+    --
+    --                                          .----.
+    --                                        ,'      |
+    --                   ,^.                ,' N    ,^.
+    --                 ,'   '.  N +----------+    ,'   '.
+    --                <  has  >===| category |---< child >
+    --                 '.   .'    +----------+ 0  '.   .'
+    --                   'v'                        'v'
+    --                    | 0
+    --                    |           ,^.
+    --              N +--------+ 0  ,'   '.  N +-----------+
+    --      .---------| object |---<  has  >===| attribute |
+    --      |         +--------+    '.   ,'    +-----------+
+    --    ,/\.          |    |        'v'
+    --  ,'    '.     __/      \__
+    -- < member >   |            |
+    --  '.    ,'   \|/          \|/
+    --    '\/'      |            |
+    --      | 1 +-------+    +-------+
+    --      '---| album |    | image |
+    --          +-------+    +-------+
+    --                        1 | | 1
+    --                       ,-'   '-.
+    --                     ,^.       ,^.
+    --                   ,'   '.   ,'   '.
+    --                  <  has  > <primary>
+    --                   '.   .'   '.   .'
+    --                     'v'       'v'
+    --                     N \       / 0..1
+    --                      +---------+
+    --                      | version |
+    --                      +---------+
+    --
+    --        |
+    -- where \|/ is supposed to look like the subclass relation symbol.
+    --        |
+
+    -- Administrative information about the database.
+    CREATE TABLE dbinfo (
+        version     INTEGER NOT NULL
+    );
+
+    -- Superclass of objects in an album.
+    CREATE TABLE object (
+        -- Identifier of the object.
+        id          INTEGER NOT NULL,
+
+        PRIMARY KEY (id)
+    );
+
+    -- Albums in the shelf. Subclass of object.
+    CREATE TABLE album (
+        -- Identifier of the album. Shared primary key with object.
+        id          INTEGER NOT NULL,
+        -- Human-memorizable tag.
+        tag         VARCHAR(256) NOT NULL,
+        -- Whether it is possible to delete the album.
+        deletable   INTEGER NOT NULL,
+        -- Album type (plain, orphans or search).
+        type        VARCHAR(256) NOT NULL,
+
+        UNIQUE      (tag),
+        FOREIGN KEY (id) REFERENCES object,
+        PRIMARY KEY (id)
+    );
+
+    -- Images in the shelf. Subclass of object.
+    CREATE TABLE image (
+        -- Internal identifier of the image. Shared primary key with
+        -- object.
+        id          INTEGER NOT NULL,
+
+        -- The primary version. NULL if no such version exists.
+        primary_version INTEGER,
+
+        FOREIGN KEY (id) REFERENCES object,
+        FOREIGN KEY (primary_version) REFERENCES image_version,
+        PRIMARY KEY (id)
+    );
+
+    -- Image versions.
+    CREATE TABLE image_version (
+        -- Identifier of the image version.
+        id          INTEGER NOT NULL,
+
+        -- Identifier of the image associated with this version.
+        image       INTEGER NOT NULL,
+
+        -- Type (original, important or other).
+        type        VARCHAR(20) NOT NULL,
+
+        -- Arbitrary comment about the version.
+        comment     TEXT NOT NULL,
+
+        -- Identifier string which is derived from the image data and
+        -- identifies the image uniquely. Currently an MD5 checksum
+        -- (in hex format) of all image data.
+        hash        CHAR(32) NOT NULL,
+        -- Directory part of the last known location (local pathname)
+        -- of the image.
+        directory   VARCHAR(256) NOT NULL,
+        -- Filename part of the last known location (local pathname)
+        -- of the image.
+        filename    VARCHAR(256) NOT NULL,
+        -- Last known time of modification (UNIX epoch time).
+        mtime       INTEGER NOT NULL,
+        -- Image width.
+        width       INTEGER NOT NULL,
+        -- Image height.
+        height      INTEGER NOT NULL,
+        
+        FOREIGN KEY (image) REFERENCES image,
+        UNIQUE      (hash),
+        PRIMARY KEY (id)
+    );
+
+    CREATE INDEX image_version_image_index ON image_version (image);
+    CREATE INDEX image_version_location_index ON image_version (directory, filename);
+
+    -- Members in an album.
+    CREATE TABLE member (
+        -- Identifier of the album.
+        album       INTEGER NOT NULL,
+        -- Member position, from 0 and up.
+        position    UNSIGNED NOT NULL,
+        -- Key of the member object.
+        object      INTEGER NOT NULL,
+
+        FOREIGN KEY (album) REFERENCES album,
+        FOREIGN KEY (object) REFERENCES object,
+        PRIMARY KEY (album, position)
+    );
+
+    CREATE INDEX member_object_index ON member (object);
+
+    -- Attributes for objects.
+    CREATE TABLE attribute (
+        -- Key of the object.
+        object      INTEGER NOT NULL,
+        -- Name of the attribute.
+        name        TEXT NOT NULL,
+        -- Value of the attribute.
+        value       TEXT NOT NULL,
+        -- Lowercased value of the attribute.
+        lcvalue     TEXT NOT NULL,
+
+        FOREIGN KEY (object) REFERENCES object,
+        PRIMARY KEY (object, name)
+    );
+
+    -- Categories in the shelf.
+    CREATE TABLE category (
+        -- Key of the category.
+        id          INTEGER NOT NULL,
+        -- Human-memorizable tag.
+        tag         TEXT NOT NULL,
+        -- Short description of the category.
+        description TEXT NOT NULL,
+
+        UNIQUE      (tag),
+        PRIMARY KEY (id)
+    );
+
+    -- Parent-child relations between categories.
+    CREATE TABLE category_child (
+        -- Parent category.
+        parent      INTEGER NOT NULL,
+
+        -- Child category.
+        child       INTEGER NOT NULL,
+
+        FOREIGN KEY (parent) REFERENCES category,
+        FOREIGN KEY (child) REFERENCES category,
+        PRIMARY KEY (parent, child)
+    );
+
+    CREATE INDEX category_child_child ON category_child (child);
+
+    -- Category-object mapping.
+    CREATE TABLE object_category (
+        -- Object.
+        object      INTEGER NOT NULL,
+
+        -- Category.
+        category    INTEGER NOT NULL,
+
+        FOREIGN KEY (object) REFERENCES object,
+        FOREIGN KEY (category) REFERENCES category,
+        PRIMARY KEY (object, category)
+    );
+
+    CREATE INDEX object_category_category ON object_category (category);
+"""
index 269a234..46ef0ef 100644 (file)
@@ -3,15 +3,17 @@
 __all__ = ["isUpgradable", "upgradeShelf"]
 
 import os
-import kofoto.shelf
 import sqlite as sql
 import time
+import kofoto.shelfschema
+from kofoto.shelfexceptions import \
+    ShelfNotFoundError, ShelfLockedError, ShelfNotFoundError
 
 def isUpgradable(location):
     """Check whether a shelf is upgradable, i.e. not the latest version."""
 
     if not os.path.exists(location):
-        raise kofoto.shelf.ShelfNotFoundError, location
+        raise ShelfNotFoundError, location
     try:
         connection = sql.connect(location)
         cursor = connection.cursor()
@@ -22,9 +24,9 @@ def isUpgradable(location):
         else:
             return False
     except sql.OperationalError:
-        raise kofoto.shelf.ShelfLockedError, location
+        raise ShelfLockedError, location
     except sql.DatabaseError:
-        raise kofoto.shelf.ShelfNotFoundError, location
+        raise ShelfNotFoundError, location
 
 def tryUpgrade(location, toVersion):
     """Upgrade the database format.
@@ -47,7 +49,7 @@ def tryUpgrade(location, toVersion):
             location, time.strftime("%Y%m%d-%H%M%S"))
         connection = sql.connect(new_location, client_encoding="UTF-8")
         cursor = connection.cursor()
-        cursor.execute(kofoto.shelf.schema)
+        cursor.execute(kofoto.shelfschema.schema)
         cursor.execute("attach '%s' as old" % (location,))
         for tablename in ["dbinfo", "object", "album", "member",
                           "attribute", "category", "category_child",
index 3394bd8..ce0d6e2 100755 (executable)
@@ -14,7 +14,34 @@ if __name__ == "__main__":
         os.path.join(os.path.dirname(sys.argv[0]), "..", "packages")))
     os.chdir(libdir)
     sys.path.insert(0, libdir)
-from kofoto.shelf import *
+from kofoto.shelf import \
+    Shelf, \
+    computeImageHash, \
+    makeValidTag, \
+    verifyValidAlbumTag, \
+    verifyValidCategoryTag
+from kofoto.albumtype import AlbumType
+from kofoto.imageversiontype import ImageVersionType
+from kofoto.shelfexceptions import \
+    AlbumDoesNotExistError, \
+    AlbumExistsError, \
+    BadAlbumTagError, \
+    BadCategoryTagError, \
+    CategoriesAlreadyConnectedError, \
+    CategoryDoesNotExistError, \
+    CategoryExistsError, \
+    CategoryLoopError, \
+    CategoryPresentError, \
+    FailedWritingError, \
+    ImageDoesNotExistError, \
+    ImageVersionDoesNotExistError, \
+    ImageVersionExistsError, \
+    ShelfLockedError, \
+    ShelfNotFoundError, \
+    UndeletableAlbumError, \
+    UndeletableAlbumError, \
+    UnsettableChildrenError, \
+    UnsupportedShelfError
 
 PICDIR = unicode(os.path.realpath(
     os.path.join("..", "reference_pictures", "working")))