コード例 #1
0
class JobRenderer(threading.Thread):
    """
    A simple, blocking job rendered. It can be used as a thread, or directly in
    the main processing path of the caller if it chooses to call run()
    directly.
    """
    def __init__(self, job, prefix):
        threading.Thread.__init__(self, name='renderer')
        self.job = job
        self.prefix = prefix
        self.result = None

    def __get_my_tid(self):
        if not self.isAlive():
            raise threading.ThreadError("the thread is not active")

        # Do we have it cached?
        if hasattr(self, '__thread_id'):
            return self.__thread_id

        # If not, look for it
        for tid, tobj in threading._active.items():
            if tobj is self:
                self.__thread_id = tid
                return self.__thread_id

        raise AssertionError("Could not resolve the thread's ID")

    def kill(self):
        LOG.debug("Killing job #%d's worker thread..." % self.job.id)
        res = ctypes.pythonapi.PyThreadState_SetAsyncExc(
            self.__get_my_tid(), ctypes.py_object(SystemExit))
        if res == 0:
            raise ValueError("Invalid thread ID")
        elif res != 1:
            ctypes.pythonapi.PyThreadState_SetAsyncExc(self.__get_my_tid(), 0)
            raise SystemError("PyThreadState_SetAsync failed")

    def run(self):
        """Renders the given job, encapsulating all processing errors and
        exceptions.

        This does not affect the job entry in the database in any way. It's the
        responsibility of the caller to do maintain the job status in the
        database.

        Returns one of the RESULT_ constants.
        """

        LOG.info("Rendering job #%d '%s'..." %
                 (self.job.id, self.job.maptitle))

        try:
            if not self.job.administrative_city:
                bbox = BoundingBox(self.job.lat_upper_left,
                                   self.job.lon_upper_left,
                                   self.job.lat_bottom_right,
                                   self.job.lon_bottom_right)
                renderer = OCitySMap(config_file=OCITYSMAP_CFG_PATH,
                                     map_areas_prefix=self.prefix,
                                     boundingbox=bbox,
                                     language=self.job.map_language)
            else:
                renderer = OCitySMap(config_file=OCITYSMAP_CFG_PATH,
                                     map_areas_prefix=self.prefix,
                                     osmid=self.job.administrative_osmid,
                                     language=self.job.map_language)
        except KeyboardInterrupt:
            self.result = RESULT_KEYBOARD_INTERRUPT
            LOG.info("Rendering of job #%d interrupted!" % self.job.id)
            return self.result
        except Exception, e:
            self.result = RESULT_PREPARATION_EXCEPTION
            LOG.exception(
                "Rendering of job #%d failed (exception occurred during"
                " data preparation)!" % self.job.id)
            return self.result

        prefix = os.path.join(RENDERING_RESULT_PATH, self.job.files_prefix())

        try:
            # Render the map in all RENDERING_RESULT_FORMATS
            result = renderer.render_map_into_files(self.job.maptitle, prefix,
                                                    RENDERING_RESULT_FORMATS,
                                                    'zoom:16')

            # Render the index in all RENDERING_RESULT_FORMATS, using the
            # same map size.
            renderer.render_index(self.job.maptitle, prefix,
                                  RENDERING_RESULT_FORMATS, result.width,
                                  result.height)

            # Create thumbnail
            if 'png' in RENDERING_RESULT_FORMATS:
                img = Image.open(prefix + '.png')
                img.thumbnail((200, 200), Image.ANTIALIAS)
                img.save(prefix + THUMBNAIL_SUFFIX)

            self.result = RESULT_SUCCESS
            LOG.info("Finished rendering of job #%d." % self.job.id)
        except KeyboardInterrupt:
            self.result = RESULT_KEYBOARD_INTERRUPT
            LOG.info("Rendering of job #%d interrupted!" % self.job.id)
        except Exception, e:
            self.result = RESULT_RENDERING_EXCEPTION
            LOG.warning(e)
            LOG.warning(
                "Rendering of job #%d failed (exception occurred during"
                " rendering)!" % self.job.id)