def cached_convert()

in Allura/allura/lib/app_globals.py [0:0]


    def cached_convert(self, artifact: MappedClass, field_name: str) -> Markup:
        """
        Convert ``artifact.field_name`` markdown source to html, caching
        the result if the render time is greater than the defined threshold.

        :param artifact: often an artifact, but also can be Neighborhood, OAuthConsumerToken, etc
        """
        source_text = getattr(artifact, field_name)
        cache_field_name = field_name + '_cache'
        cache = getattr(artifact, cache_field_name, None)
        if not cache:
            log.warning(
                'Skipping Markdown caching - Missing cache field "%s" on class %s',
                field_name, artifact.__class__.__name__)
            return self.convert(source_text)

        bugfix_rev = 4  # increment this if we need all caches to invalidated (e.g. xss in markdown rendering fixed)
        md5 = None
        # If a cached version exists and it is valid, return it.
        if cache.md5 is not None:
            md5 = hashlib.md5(source_text.encode('utf-8')).hexdigest()
            if cache.md5 == md5 and getattr(cache, 'fix7528', False) == bugfix_rev:
                return Markup(cache.html)  # noqa: S704

        # Convert the markdown and time the result.
        start = time.time()
        html = self.convert(source_text, render_limit=False)
        render_time = time.time() - start

        threshold = config.get('markdown_cache_threshold')
        try:
            threshold = float(threshold) if threshold else None
        except ValueError:
            threshold = None
            log.warning('Skipping Markdown caching - The value for config param '
                        '"markdown_cache_threshold" must be a float.')

        # Check if contains macro and never cache
        if self.uncacheable_macro_regex.search(source_text):
            if render_time > float(config.get('markdown_cache_threshold.nocache', 0.5)):
                try:
                    details = artifact.index_id()
                except Exception:
                    details = str(artifact._id)
                try:
                    details += ' ' + artifact.url()
                except Exception:
                    pass
                log.info(f'Not saving markdown cache since it has a dynamic macro.  Took {render_time:.03}s on {details}')
            return html

        if threshold is not None and render_time > threshold:
            # Save the cache
            if md5 is None:
                md5 = hashlib.md5(source_text.encode('utf-8')).hexdigest()
            cache.md5, cache.html, cache.render_time = md5, html, render_time
            cache.fix7528 = bugfix_rev  # flag to indicate good caches created after [#7528] and other critical bugs were fixed.

            try:
                sess = session(artifact)
            except AttributeError:
                # this can happen if a non-artifact object is used
                log.exception('Could not get session for %s', artifact)
            else:
                with utils.skip_mod_date(artifact.__class__), \
                        utils.skip_last_updated(artifact.__class__):
                    sess.flush(artifact)
        return html