コード例 #1
0
ファイル: image.py プロジェクト: geertj/draco2
class ImageInfo(object):
    """Get image info.

    The object's responsibility is to provide information on images in
    certain parts of the file system. The information returns in a
    3-tuple of (format, with, height).

    A LRU cache is used for efficiency. The cache is validated on every
    access by means of file modification time.

    This class is thread safe.
    """

    def __init__(self):
        """Constructor."""
        self.m_path = []
        self.m_cache = LruCache(1000)

    @classmethod
    def _create(cls, api):
        """Factory method."""
        images = cls()
        docroot = api.request.docroot()
        images.add_path(docroot)
        config = api.config.ns('draco2.draco.image')
        if config.has_key('cachesize'):
            images._set_cache_size(config['cachesize'])
        if hasattr(api, 'changes'):
            images._set_change_manager(api.changes)
        return images

    def _set_change_manager(self, changes):
        """Set the change manager to `changes'."""
        ctx = changes.get_context('draco2.core.config')
        ctx.add_callback(self._change_callback)

    def _change_callback(self, api):
        """Reload config."""
        config = api.config.ns('draco2.draco.image')
        if config.has_key('cachesize'):
            self._set_cache_size(config['cachesize'])
        logger = logging.getLogger('draco2.draco.image')
        logger.debug('Reloaded due to config change.')

    def _set_cache_size(self, size):
        """Set the cache size."""
        self.m_cache.set_size(size)

    def add_path(self, path):
        """Add `path' to the image search path. """
        self.m_path.append(path)

    def get_info(self, fname):
        """Get image size for `fname'.

        The file `fname' is looked up in the path.
        """
        for path in self.m_path:
            # do not use os.path.join() as fname() may start with '/'
            fname = path + os.sep + fname
            try:
                st = os.stat(fname)
            except OSError:
                st = None
            if st and stat.S_ISREG(st.st_mode):
                break
        else:
            return
        mtime = st.st_mtime
        entry = self.m_cache.get(fname)
        if entry and entry[0] == mtime:
            return entry[1]
        info = get_image_info(fname)
        if not info:
            return
        entry = [mtime, info]
        self.m_cache.add(fname, entry)
        return info
コード例 #2
0
ファイル: translator.py プロジェクト: geertj/draco2
class Translator(TranslatorInterface):
    """The default translator.

    This translator uses the the DracoModel to translate messages. It also
    employs a LRU cache to cut down on the number of database lookups.
    """

    def __init__(self, models, changes=None):
        """Constructor."""
        self.m_models = models
        if changes:
            self._set_change_manager(changes)
        self.m_cache = LruCache(1000)

    @classmethod
    def _create(cls, api):
        """Factory method."""
        if hasattr(api, 'changes'):
            changes = api.changes
        else:
            changes = None
        translator = cls(api.models, changes)
        config = api.config.namespace('draco2.draco.config')
        if config.has_key('cachesize'):
            translator.set_cache_size(config['cachesize'])
        return translator

    def _set_change_manager(self, changes):
        """Use change manager `changes'."""
        ctx = changes.get_context('draco2.draco.translator')
        ctx.add_object('translation', self._mtime)
        ctx.add_callback(self._change_callback)
        ctx = changes.get_context('draco2.draco.config')  # for cache size
        ctx.add_callback(self._change_callback)

    def _change_callback(self, api):
        """Change callback."""
        self.clear_cache()
        config = api.config.namespace('draco2.draco.config')
        if config.has_key('cachesize'):
            self.set_cache_size(config['cachesize'])

    def _mtime(self):
        """Return the time stamp at which the last update to the
        translation table was made."""
        transaction = self.m_models.model('draco').transaction('shared')
        try:
            change = transaction.entity(Change, (Translation.name,))
        except ModelInterfaceError:
            return
        return change['change_date']

    def set_cache_size(self, size):
        """Set the cache size to `size'."""
        self.m_cache.set_size(size)

    def clear_cache(self):
        """Clear the translations cache."""
        self.m_cache.clear()

    def translate(self, message, languages, context=None, name=None):
        """Translate `message'."""
        hash = Message.hash(message)
        cacheid = (hash, context, name) + tuple(languages)
        translation = self.m_cache.get(cacheid)
        if translation:
            return translation
        # All translations are looked up where the corresponding message
        # matches `message' or `name', and that match any of the languages
        # specified in `languages'. If no results are found, `message' itself
        # is returned. If results are found, they are ordered by applying the
        # criteria mentioned below and the first entry is returned:
        # 1. Translations where the message name matched.
        # 2. Translations where the message id matched.
        # 3. Translations that have a language earlier in the `languages' list.
        # 4. Translations where the context matched.
        transaction = self.m_models.model('draco').transaction('shared')
        where = '(message.hash = %s'
        args = [hash]
        if name:
            where += ' OR message.name = %s'
            args.append(name)
        where += ')'
        array = ','.join(['%s'] * len(languages))
        where += ' AND language IN (%s)' % array
        args += languages
        # Ordering on columns that can contain NULL values: testing whether a
        # NULL value is equal to something always returns NULL, and therefore
        # we need to weed those out in the ordering test.
        order = []
        if name is not None:
            order.append('message.name = %s AND NOT name IS NULL DESC')
            args.append(name)
        else:
            order.append('message.name IS NULL DESC')
        order.append('message.hash = %s DESC')
        args.append(hash)
        order += ['language=%s DESC'] * len(languages)
        args += languages
        if context:
            order.append('message.context = %s AND NOT context IS NULL DESC')
            args.append(context)
        order = ','.join(order)
        join = (Translation, 'translation',
                MessageTranslationRelationship, 'INNER')
        result = transaction.select(Translation, where, args,
                                    order=order, join=join)
        if result:
            translation = result[0]['translation']
        else:
            translation = message
        self.m_cache.add(cacheid, translation)
        return translation