docstr: Compute or get already computed chart thumbnail from cache.
  ---
  get:
    summary: Get chart thumbnail
    description: Compute or get already computed chart thumbnail from cache.
    parameters:
    - in: path
      schema:
        type: integer
      name: pk
    - in: path
      schema:
        type: string
      name: digest
    responses:
      200:
        description: Chart thumbnail image
        content:
         image/*:
           schema:
             type: string
             format: binary
      302:
        description: Redirects to the current digest
      400:
        $ref: '#/components/responses/400'
      401:
        $ref: '#/components/responses/401'
      404:
        $ref: '#/components/responses/404'
      500:
        $ref: '#/components/responses/500'
docstr_tok: ["Compute","or","get","already","computed","chart","thumbnail","from","cache",".","--","-","get",":","summary",":","Get","chart","thumbnail","description",":","Compute","or","get","already","computed","chart","thumbnail","from","cache",".","parameters",":","-","in",":","path","schema",":","type",":","integer","name",":","pk","-","in",":","path","schema",":","type",":","string","name",":","digest","responses",":","200",":","description",":","Chart","thumbnail","image","content",":","image\/","*",":","schema",":","type",":","string","format",":","binary","302",":","description",":","Redirects","to","the","current","digest","400",":","$","ref",":","'","#","\/components\/responses\/400'","401",":","$","ref",":","'","#","\/components\/responses\/401'","404",":","$","ref",":","'","#","\/components\/responses\/404'","500",":","$","ref",":","'","#","\/components\/responses\/500","'"]
code: def thumbnail(
      self, pk: int, digest: str, **kwargs: Any
  ) -> WerkzeugResponse:
      """Compute or get already computed chart thumbnail from cache.
      ---
      get:
        summary: Get chart thumbnail
        description: Compute or get already computed chart thumbnail from cache.
        parameters:
        - in: path
          schema:
            type: integer
          name: pk
        - in: path
          schema:
            type: string
          name: digest
        responses:
          200:
            description: Chart thumbnail image
            content:
             image/*:
               schema:
                 type: string
                 format: binary
          302:
            description: Redirects to the current digest
          400:
            $ref: '#/components/responses/400'
          401:
            $ref: '#/components/responses/401'
          404:
            $ref: '#/components/responses/404'
          500:
            $ref: '#/components/responses/500'
      """
      chart = cast(Slice, self.datamodel.get(pk, self._base_filters))
      if not chart:
          return self.response_404()
  
      current_user = get_current_user()
      url = get_url_path("Superset.slice", slice_id=chart.id)
      if kwargs["rison"].get("force", False):
          logger.info(
              "Triggering thumbnail compute (chart id: %s) ASYNC",
              str(chart.id),
          )
          cache_chart_thumbnail.delay(
              current_user=current_user,
              chart_id=chart.id,
              force=True,
          )
          return self.response(202, message="OK Async")
      # fetch the chart screenshot using the current user and cache if set
      screenshot = ChartScreenshot(url, chart.digest).get_from_cache(
          cache=thumbnail_cache
      )
      # If not screenshot then send request to compute thumb to celery
      if not screenshot:
          self.incr_stats("async", self.thumbnail.__name__)
          logger.info(
              "Triggering thumbnail compute (chart id: %s) ASYNC",
              str(chart.id),
          )
          cache_chart_thumbnail.delay(
              current_user=current_user,
              chart_id=chart.id,
              force=True,
          )
          return self.response(202, message="OK Async")
      # If digests
      if chart.digest != digest:
          self.incr_stats("redirect", self.thumbnail.__name__)
          return redirect(
              url_for(
                  f"{self.__class__.__name__}.thumbnail",
                  pk=pk,
                  digest=chart.digest,
              )
          )
      self.incr_stats("from_cache", self.thumbnail.__name__)
      return Response(
          FileWrapper(screenshot),
          mimetype="image/png",
          direct_passthrough=True,
      )
  
imports: import json
  import logging
  from datetime import datetime
  from io import BytesIO
  from typing import Any, cast, Optional
  from zipfile import is_zipfile, ZipFile
  from flask import redirect, request, Response, send_file, url_for
  from flask_appbuilder.api import expose, protect, rison, safe
  from flask_appbuilder.hooks import before_request
  from flask_appbuilder.models.sqla.interface import SQLAInterface
  from flask_babel import ngettext
  from marshmallow import ValidationError
  from werkzeug.wrappers import Response
  from werkzeug.wsgi import FileWrapper
  from superset import app, is_feature_enabled, thumbnail_cache
  from superset.charts.filters import ChartAllTextFilter, ChartCertifiedFilter, ChartCreatedByMeFilter, ChartFavoriteFilter, ChartFilter, ChartHasCreatedByFilter, ChartOwnedCreatedFavoredByMeFilter, ChartTagFilter
  from superset.charts.schemas import CHART_SCHEMAS, ChartCacheWarmUpRequestSchema, ChartPostSchema, ChartPutSchema, get_delete_ids_schema, get_export_ids_schema, get_fav_star_ids_schema, openapi_spec_methods_override, screenshot_query_schema, thumbnail_query_schema
  from superset.commands.chart.create import CreateChartCommand
  from superset.commands.chart.delete import DeleteChartCommand
  from superset.commands.chart.exceptions import ChartCreateFailedError, ChartDeleteFailedError, ChartForbiddenError, ChartInvalidError, ChartNotFoundError, ChartUpdateFailedError, DashboardsForbiddenError
  from superset.commands.chart.export import ExportChartsCommand
  from superset.commands.chart.importers.dispatcher import ImportChartsCommand
  from superset.commands.chart.update import UpdateChartCommand
  from superset.commands.chart.warm_up_cache import ChartWarmUpCacheCommand
  from superset.commands.exceptions import CommandException
  from superset.commands.importers.exceptions import IncorrectFormatError, NoValidFilesFoundError
  from superset.commands.importers.v1.utils import get_contents_from_bundle
  from superset.constants import MODEL_API_RW_METHOD_PERMISSION_MAP, RouteMethod
  from superset.daos.chart import ChartDAO
  from superset.extensions import event_logger
  from superset.models.slice import Slice
  from superset.tasks.thumbnails import cache_chart_thumbnail
  from superset.tasks.utils import get_current_user
  from superset.utils.screenshots import ChartScreenshot, DEFAULT_CHART_WINDOW_SIZE
  from superset.utils.urls import get_url_path
  from superset.views.base_api import BaseSupersetModelRestApi, RelatedFieldFilter, requires_form_data, requires_json, statsd_metrics
  from superset.views.filters import BaseFilterRelatedUsers, FilterRelatedOwners
label_desc: Use image node_id 8 for calling the ChartRestApi obj's underlying member method code with example usage: obj.thumbnail(pk, digest) and returns: Response, self, self, self, redirect