Fork me on GitHub

sqlalchemy_imageattach.entity — Image entities

This module provides a short way to attach resizable images to other object-relationally mapped entity classes.

For example, imagine there’s a fictional entity named User and it has its picture and front_cover. So there should be two image entities that subclass Image mixin:

class UserPicture(Base, Image):
    '''User's profile picture.'''

    user_id = Column(Integer, ForeignKey('User.id'), primary_key=True)
    user = relationship('User')

    __tablename__ = 'user_picture'

You have to also inherit your own declarative_base() class (Base in the example).

Assume there’s also UserFrontCover in the same way.

Note that the class can override object_id property. Backend storages utilize this to identify images e.g. filename, S3 key. If the primary key of the image entity is integer, object_id automatically uses the primary key value by default, but it can be overridden if needed, and must be implemented if the primary key is not integer or composite key.

There’s also object_type property. Image provides the default value for it as well. It uses the class name (underscores will be replaced by hyphens) by default, but you can override it.

These Image subclasses can be related to the their ‘parent’ entity using image_attachment() function. It’s a specialized version of SQLAlchemy’s built-in relationship() function, so you can pass the same options as relationship() takes:

class User(Base):
    '''Users have their profile picture and front cover.'''

    id = Column(Integer, primary_key=True)
    picture = image_attachment('UserPicture')
    front_cover = image_attachment('UserFrontCover')

    __tablename__ = 'user'

It’s done, you can store the actual image files using from_file() or from_blob() method:

with store_context(store):
    user = User()
    with open('picture.jpg', 'rb') as f:
        user.picture.from_blob(f.read())
    with open('front_cover.jpg', 'rb') as f:
        user.front_cover.from_file(f)
    with session.begin():
        session.add(user)

Or you can resize the image to make thumbnails using generate_thumbnail() method:

with store_context(store):
    user.picture.generate_thumbnail(ratio=0.5)
    user.picture.generate_thumbnail(height=100)
    user.front_cover.generate_thumbnail(width=500)
sqlalchemy_imageattach.entity.VECTOR_TYPES = frozenset({'application/pdf', 'image/svg+xml'})

(typing.AbstractSet[str]) The set of vector image types.

class sqlalchemy_imageattach.entity.BaseImageSet

The abstract class of the following two image set types:

The common things about them, abstracted by BaseImageSet, are:

You can think image set of an abstract image hiding its size details. It actually encapsulates physical images of different sizes but having all the same look. So only its original image is canon, and other thumbnails are replica of it.

Note that it implements __html__() method, a de facto standard special method for HTML templating. So you can simply use it in Jinja2 like:

{{ user.profile }}

instead of:

<img src="{{ user.profile|permalink }}"
     width="{{ user.profile.original.width }}"
     height="{{ user.profile.original.height }}">
find_thumbnail(width=None, height=None)

Finds the thumbnail of the image with the given width and/or height.

Parameters:
Returns:

the thumbnail image

Return type:

Image

Raises:

sqlalchemy.orm.exc.NoResultFound – when there’s no image of such size

from_blob(blob, store=sqlalchemy_imageattach.context.current_store, extra_args=None, extra_kwargs=None)

Stores the blob (byte string) for the image into the store.

Parameters:
  • blob (str) – the byte string for the image
  • store (Store) – the storage to store the image data. current_store by default
  • extra_args (collections.abc.Sequence) – additional arguments to pass to the model’s constructor.
  • extra_kwargs (typing.Mapping[str, object]) – additional keyword arguments to pass to the model’s constructor.
Returns:

the created image instance

Return type:

Image

New in version 1.0.0: The extra_args and extra_kwargs options.

from_file(file, store=sqlalchemy_imageattach.context.current_store, extra_args=None, extra_kwargs=None)

Stores the file for the image into the store.

Parameters:
  • file (file-like object, file) – the readable file of the image
  • store (Store) – the storage to store the file. current_store by default
  • extra_args (collections.abc.Sequence) – additional arguments to pass to the model’s constructor.
  • extra_kwargs (typing.Mapping[str, object]) – additional keyword arguments to pass to the model’s constructor.
Returns:

the created image instance

Return type:

Image

New in version 1.0.0: The extra_args and extra_kwargs options.

from_raw_file(raw_file, store=sqlalchemy_imageattach.context.current_store, size=None, mimetype=None, original=True, extra_args=None, extra_kwargs=None)

Similar to from_file() except it’s lower than that. It assumes that raw_file is readable and seekable while from_file() only assumes the file is readable. Also it doesn’t make any in-memory buffer while from_file() always makes an in-memory buffer and copy the file into the buffer.

If size and mimetype are passed, it won’t try to read image and will use these values instead.

It’s used for implementing from_file() and from_blob() methods that are higher than it.

Parameters:
  • raw_file (file-like object, file) – the seekable and readable file of the image
  • store (Store) – the storage to store the file. current_store by default
  • size (tuple) – an optional size of the image. automatically detected if it’s omitted
  • mimetype (str) – an optional mimetype of the image. automatically detected if it’s omitted
  • original (bool) – an optional flag which represents whether it is an original image or not. defualt is True (meaning original)
  • extra_args (collections.abc.Sequence) – additional arguments to pass to the model’s constructor.
  • extra_kwargs (typing.Mapping[str, object]) – additional keyword arguments to pass to the model’s constructor.
Returns:

the created image instance

Return type:

Image

New in version 1.0.0: The extra_args and extra_kwargs options.

generate_thumbnail(ratio=None, width=None, height=None, filter='undefined', store=sqlalchemy_imageattach.context.current_store, _preprocess_image=None, _postprocess_image=None)

Resizes the original (scales up or down) and then store the resized thumbnail into the store.

Parameters:
  • ratio (numbers.Real) – resize by its ratio. if it’s greater than 1 it scales up, and if it’s less than 1 it scales down. exclusive for width and height parameters
  • width (numbers.Integral) – resize by its width. exclusive for ratio and height parameters
  • height (numbers.Integral) – resize by its height. exclusive for ratio and width parameters
  • filter (str, numbers.Integral) – a filter type to use for resizing. choose one in wand.image.FILTER_TYPES. default is 'undefined' which means ImageMagick will try to guess best one to use
  • store (Store) – the storage to store the resized image file. current_store by default
  • _preprocess_image – internal-use only option for preprocessing original image before resizing
  • _postprocess_image – internal-use only option for preprocessing original image before resizing
Returns:

the resized thumbnail image. it might be an already existing image if the same size already exists

Return type:

Image

Raises:

IOError – when there’s no original image yet

locate(store=sqlalchemy_imageattach.context.current_store)

The shorthand of locate() for the original.

Parameters:store (Store) – the storage which contains the image files. current_store by default
Returns:the url of the original image
Return type:str
make_blob(store=sqlalchemy_imageattach.context.current_store)

The shorthand of make_blob() for the original.

Parameters:store (Store) – the storage which contains the image files. current_store by default
Returns:the byte string of the original image
Return type:str
open_file(store=sqlalchemy_imageattach.context.current_store, use_seek=False)

The shorthand of open_file() for the original.

Parameters:
  • store (Store) – the storage which contains the image files current_store by default
  • use_seek (bool) – whether the file should seekable. if True it maybe buffered in the memory. default is False
Returns:

the file-like object of the image, which is a context manager (plus, also seekable only if use_seek is True)

Return type:

file, FileProxy, file-like object

original

(Image) The original image. It could be None if there are no stored images yet.

require_original()

Returns the original image or just raise IOError (instead of returning None). That means it guarantees the return value is never None but always Image.

Returns:the original image
Return type:Image
Raises:IOError – when there’s no original image yet
class sqlalchemy_imageattach.entity.BaseImageQuery(entities, session=None)

The subtype of Query specialized for Image. It provides more methods and properties over Query.

New in version 1.0.0.

class sqlalchemy_imageattach.entity.Image

The image of the particular size.

Note that it implements __html__() method, a de facto standard special method for HTML templating. So you can simply use it in HTML templates like:

{{ user.profile.find_thumbnail(120) }}

The above template is equivalent to:

{% with thumbnail = user.profile.find_thumbnail(120) %}
    <img src="{{ thumbnail.locate() }}"
         width="{{ thumbnail.width }}"
         height="{{ thumbnail.height }}">
{% endwith %}
object_type

(str) The identifier string of the image type. It uses __tablename__ (which replaces underscores with hyphens) by default, but can be overridden.

created_at = Column('created_at', DateTime(timezone=True), table=None, nullable=False, default=ColumnDefault(<sqlalchemy.sql.functions.now at 0x7f7c4466a8d0; now>))

(datetime.datetime) The created time.

height = Column('height', Integer(), table=None, primary_key=True, nullable=False)

(numbers.Integral) The image’s height.”“”

classmethod identity_attributes()

A list of the names of primary key fields.

Returns:A list of the names of primary key fields
Return type:typing.Sequence[str]

New in version 1.0.0.

identity_map

(typing.Mapping[str, object]) A dictionary of the values of primary key fields with their names.

New in version 1.0.0.

locate(store=sqlalchemy_imageattach.context.current_store)

Gets the URL of the image from the store.

Parameters:store (Store) – the storage which contains the image. current_store by default
Returns:the url of the image
Return type:str
make_blob(store=sqlalchemy_imageattach.context.current_store)

Gets the byte string of the image from the store.

Parameters:store (Store) – the storage which contains the image. current_store by default
Returns:the binary data of the image
Return type:str
mimetype = Column('mimetype', String(length=255), table=None, nullable=False)

(str) The mimetype of the image e.g. 'image/jpeg', 'image/png'.

object_id

(numbers.Integral) The identifier number of the image. It uses the primary key if it’s integer, but can be overridden, and must be implemented when the primary key is not integer or composite key.

Changed in version 1.1.0: Since 1.1.0, it provides a more default implementation for UUID primary keys. If a primary key is not composite and UUID type, object_id for that doesn’t have to be implemented.

object_type

(str) The identifier string of the image type. It uses __tablename__ (which replaces underscores with hyphens) by default, but can be overridden.

open_file(store=sqlalchemy_imageattach.context.current_store, use_seek=False)

Opens the file-like object which is a context manager (that means it can used for with statement).

If use_seek is True (though False by default) it guarentees the returned file-like object is also seekable (provides seek() method).

Parameters:store (Store) – the storage which contains image files. current_store by default
Returns:the file-like object of the image, which is a context manager (plus, also seekable only if use_seek is True)
Return type:file, FileProxy, file-like object
original = Column('original', Boolean(), table=None, nullable=False, default=ColumnDefault(False))

(bool) Whether it is original or resized.

size

(tuple) The same to the pair of (width, height).

width = Column('width', Integer(), table=None, primary_key=True, nullable=False)

(numbers.Integral) The image’s width.

sqlalchemy_imageattach.entity.ImageSet

Alias of SingleImageSet.

Deprecated since version Use: SingleImageSet to distinguish from MultipleImageSet.

Changed in version 1.0.0: Renamed to SingleImageSet, and this remains only for backward compatibility. It will be completely removed in the future.

alias of SingleImageSet

class sqlalchemy_imageattach.entity.ImageSubset(_query, **identity_map)

Image set which is contained by MultipleImageSet.

It contains one canonical original image and its thumbnails, as it’s also a subtype of BaseImageSet like SingleImageSet.

New in version 1.0.0.

class sqlalchemy_imageattach.entity.MultipleImageSet(entities, session=None)

Used for image_attachment() is congirued with uselist=True option.

Like SingleImageSet, it is a subtype of BaseImageQuery. It can be filtered using filter() method or sorted using order() method.

Unlike SingleImageSet, it is not a subtype of BaseImageSet, as it can contain multiple image sets. That means, it’s not image set, but set of image sets. Its elements are ImageSubset objects, that are image sets.

New in version 1.0.0.

get_image_set(**pk)

Choose a single image set to deal with. It takes criteria through keyword arguments. The given criteria doesn’t have to be satisfied by any already attached images. Null image sets returned by such criteria can be used for attaching a new image set.

Parameters:**pk – keyword arguments of extra discriminating primary key column names to its values
Returns:a single image set
Return type:ImageSubset
image_sets

(typing.Iterable[ImageSubset]) The set of attached image sets.

class sqlalchemy_imageattach.entity.SingleImageSet(entities, session=None)

Used for image_attachment() is congirued uselist=False option (which is default).

It contains one canonical original image and its thumbnails, as it’s a subtype of BaseImageSet.

New in version 1.0.0: Renamed from ImageSet.

sqlalchemy_imageattach.entity.image_attachment(*args, **kwargs)

The helper function, decorates raw relationship() function, sepcialized for relationships between Image subtypes.

It takes the same parameters as relationship().

If uselist is True, it becomes possible to attach multiple image sets. In order to attach multiple image sets, image entity types must have extra discriminating primary key columns to group each image set.

If uselist is False (which is default), it becomes possible to attach only a single image.

Parameters:
Returns:

the relationship property

Return type:

sqlalchemy.orm.properties.RelationshipProperty

New in version 1.0.0: The uselist parameter.