Source code for pyfarm.models.jobtype

# No shebang line, this module is meant to be imported
#
# Copyright 2013 Oliver Palmer
# Copyright 2014 Ambient Entertainment GmbH & Co. KG
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""
Job Type Models
===============

Models and objects dedicated to handling information which is specific
to an individual job.  See :mod:`pyfarm.models.job` for more the more
general implementation.
"""

import ast
from hashlib import sha1
from textwrap import dedent

from sqlalchemy import event
from sqlalchemy.orm import validates
from sqlalchemy.schema import UniqueConstraint

from pyfarm.core.config import read_env_int, read_env_bool, read_env
from pyfarm.core.logger import getLogger
from pyfarm.master.application import db
from pyfarm.models.core.cfg import (
    TABLE_JOB_TYPE, TABLE_JOB_TYPE_VERSION, MAX_JOBTYPE_LENGTH)
from pyfarm.models.core.mixins import UtilityMixins, ReprMixin
from pyfarm.models.core.types import id_column, IDTypeWork


__all__ = ("JobType", )

JOBTYPE_BASECLASS = read_env("PYFARM_JOBTYPE_SUBCLASSES_BASE_CLASS", "JobType")

logger = getLogger("models.jobtype")


[docs]class JobType(db.Model, UtilityMixins, ReprMixin): """ Stores the unique information necessary to execute a task """ __tablename__ = TABLE_JOB_TYPE __table_args__ = (UniqueConstraint("name"),) REPR_COLUMNS = ("id", "name") id = id_column(IDTypeWork) name = db.Column(db.String(MAX_JOBTYPE_LENGTH), nullable=False, doc=dedent(""" The name of the job type. This can be either a human readable name or the name of the job type class itself.""")) description = db.Column(db.Text, nullable=True, doc=dedent(""" Human readable description of the job type. This field is not required and is not directly relied upon anywhere.""")) @validates("name")
[docs] def validate_name(self, key, value): if value == "": raise ValueError("Name cannot be empty") return value
class JobTypeVersion(db.Model, UtilityMixins, ReprMixin): __tablename__ = TABLE_JOB_TYPE_VERSION __table_args__ = (UniqueConstraint("jobtype_id", "version"),) REPR_COLUMNS = ( "id", "jobtype_id", "version") id = id_column(IDTypeWork) jobtype_id = db.Column(IDTypeWork, db.ForeignKey("%s.id" % TABLE_JOB_TYPE), nullable=False, doc="The jobtype this version belongs to") version = db.Column(db.Integer, nullable=False, doc="The version number") max_batch = db.Column(db.Integer, default=read_env_int( "JOBTYPE_DEFAULT_MAX_BATCH", read_env_int("PYFARM_QUEUE_MAX_BATCH", 1)), doc=dedent(""" When the queue runs, this is the maximum number of tasks that the queue can select to assign to a single agent. If left empty, no maximum applies""")) batch_contiguous = db.Column(db.Boolean, default=read_env_bool( "JOBTYPE_DEFAULT_BATCH_CONTIGUOUS", True), doc=dedent(""" If True then the queue will be forced to batch numerically contiguous tasks only for this job type. For example if True it would batch frames 1, 2, 3, 4 together but not 2, 4, 6, 8. If this column is False however the queue will batch non-contiguous tasks too.""")) classname = db.Column(db.String(MAX_JOBTYPE_LENGTH), nullable=True, doc=dedent(""" The name of the job class contained within the file being loaded. This field may be null but when it's not provided job type name will be used instead.""")) code = db.Column(db.UnicodeText, nullable=False, doc="The source code of the job type") jobtype = db.relationship("JobType", backref=db.backref("versions", lazy="dynamic", cascade="all, delete-orphan"), doc=dedent(""" Relationship between this version and the :class:`JobType` it belongs to""")) jobs = db.relationship("Job", backref="jobtype_version", lazy="dynamic", doc=dedent(""" Relationship between this jobtype version and :class:`.Job` objects.""")) @validates("max_batch") def validate_max_batch(self, key, value): if isinstance(value, int) and value < 1: raise ValueError("max_batch must be greater than or equal to 1") return value @validates("version") def validate_version(self, key, value): if isinstance(value, int) and value < 1: raise ValueError("version must be greater than or equal to 1") return value