class_docstr: The TensorBoard WSGI app that delegates to a set of TBPlugin.
class_docstr_tok: ["The","TensorBoard","WSGI","app","that","delegates","to","a","set","of","TBPlugin","."]
docstr: Constructs TensorBoardWSGI instance.
  
  Args:
    plugins: A list of base_plugin.TBPlugin subclass instances.
    path_prefix: A prefix of the path when app isn't served from root.
    data_provider: `tensorboard.data.provider.DataProvider` or
      `None`; if present, will inform the "active" state of
      `/plugins_listing`.
    experimental_plugins: A list of plugin names that are only provided
        experimentally. The corresponding plugins will only be activated for
        a user if the user has specified the plugin with the experimentalPlugin
        query parameter in the URL.
    auth_providers: Optional mapping whose values are `AuthProvider`
      values and whose keys are used by (e.g.) data providers to specify
      `AuthProvider`s via the `AuthContext.get` interface.
      Defaults to `{}`.
    experimental_middlewares: Optional list of WSGI middlewares to apply
      directly around the core TensorBoard app itself. Defaults to `[]`.
      This parameter is experimental and may be reworked or removed.
  
  Returns:
    A WSGI application for the set of all TBPlugin instances.
  
  Raises:
    ValueError: If some plugin has no plugin_name
    ValueError: If some plugin has an invalid plugin_name (plugin
        names must only contain [A-Za-z0-9_.-])
    ValueError: If two plugins have the same plugin_name
    ValueError: If some plugin handles a route that does not start
        with a slash
  
  :type plugins: list[base_plugin.TBPlugin]
docstr_tok: ["Constructs","TensorBoardWSGI","instance",".","Args",":","plugins",":","A","list","of","base_plugin.TBPlugin","subclass","instances",".","path_prefix",":","A","prefix","of","the","path","when","app","is","n't","served","from","root",".","data_provider",":","`","tensorboard.data.provider.DataProvider","`","or","`","None","`",";","if","present",",","will","inform","the","``","active","''","state","of","`","\/plugins_listing","`",".","experimental_plugins",":","A","list","of","plugin","names","that","are","only","provided","experimentally",".","The","corresponding","plugins","will","only","be","activated","for","a","user","if","the","user","has","specified","the","plugin","with","the","experimentalPlugin","query","parameter","in","the","URL",".","auth_providers",":","Optional","mapping","whose","values","are","`","AuthProvider","`","values","and","whose","keys","are","used","by","(","e.g",".",")","data","providers","to","specify","`","AuthProvider","`","s","via","the","`","AuthContext.get","`","interface",".","Defaults","to","`","{","}","`",".","experimental_middlewares",":","Optional","list","of","WSGI","middlewares","to","apply","directly","around","the","core","TensorBoard","app","itself",".","Defaults","to","`","[","]","`",".","This","parameter","is","experimental","and","may","be","reworked","or","removed",".","Returns",":","A","WSGI","application","for","the","set","of","all","TBPlugin","instances",".","Raises",":","ValueError",":","If","some","plugin","has","no","plugin_name","ValueError",":","If","some","plugin","has","an","invalid","plugin_name","(","plugin","names","must","only","contain","[","A-Za-z0-9_.-","]",")","ValueError",":","If","two","plugins","have","the","same","plugin_name","ValueError",":","If","some","plugin","handles","a","route","that","does","not","start","with","a","slash",":","type","plugins",":","list","[","base_plugin.TBPlugin","]"]
code: def __init__(
      self,
      plugins,
      path_prefix="",
      data_provider=None,
      experimental_plugins=None,
      auth_providers=None,
      experimental_middlewares=None,
  ):
      """Constructs TensorBoardWSGI instance.
  
      Args:
        plugins: A list of base_plugin.TBPlugin subclass instances.
        path_prefix: A prefix of the path when app isn't served from root.
        data_provider: `tensorboard.data.provider.DataProvider` or
          `None`; if present, will inform the "active" state of
          `/plugins_listing`.
        experimental_plugins: A list of plugin names that are only provided
            experimentally. The corresponding plugins will only be activated for
            a user if the user has specified the plugin with the experimentalPlugin
            query parameter in the URL.
        auth_providers: Optional mapping whose values are `AuthProvider`
          values and whose keys are used by (e.g.) data providers to specify
          `AuthProvider`s via the `AuthContext.get` interface.
          Defaults to `{}`.
        experimental_middlewares: Optional list of WSGI middlewares to apply
          directly around the core TensorBoard app itself. Defaults to `[]`.
          This parameter is experimental and may be reworked or removed.
  
      Returns:
        A WSGI application for the set of all TBPlugin instances.
  
      Raises:
        ValueError: If some plugin has no plugin_name
        ValueError: If some plugin has an invalid plugin_name (plugin
            names must only contain [A-Za-z0-9_.-])
        ValueError: If two plugins have the same plugin_name
        ValueError: If some plugin handles a route that does not start
            with a slash
  
      :type plugins: list[base_plugin.TBPlugin]
      """
      self._plugins = plugins
      self._path_prefix = path_prefix
      self._data_provider = data_provider
      self._experimental_plugins = frozenset(experimental_plugins or ())
      self._auth_providers = auth_providers or {}
      self._extra_middlewares = list(experimental_middlewares or [])
      if self._path_prefix.endswith("/"):
          # Should have been fixed by `fix_flags`.
          raise ValueError(
              "Trailing slash in path prefix: %r" % self._path_prefix
          )
  
      self.exact_routes = {
          # TODO(@chihuahua): Delete this RPC once we have skylark rules that
          # obviate the need for the frontend to determine which plugins are
          # active.
          DATA_PREFIX
          + PLUGINS_LISTING_ROUTE: self._serve_plugins_listing,
          DATA_PREFIX + PLUGIN_ENTRY_ROUTE: self._serve_plugin_entry,
      }
      unordered_prefix_routes = {}
  
      # Serve the routes from the registered plugins using their name as the route
      # prefix. For example if plugin z has two routes /a and /b, they will be
      # served as /data/plugin/z/a and /data/plugin/z/b.
      plugin_names_encountered = set()
      for plugin in self._plugins:
          if plugin.plugin_name is None:
              raise ValueError("Plugin %s has no plugin_name" % plugin)
          if not _VALID_PLUGIN_RE.match(plugin.plugin_name):
              raise ValueError(
                  "Plugin %s has invalid name %r"
                  % (plugin, plugin.plugin_name)
              )
          if plugin.plugin_name in plugin_names_encountered:
              raise ValueError(
                  "Duplicate plugins for name %s" % plugin.plugin_name
              )
          plugin_names_encountered.add(plugin.plugin_name)
  
          try:
              plugin_apps = plugin.get_plugin_apps()
          except Exception as e:  # pylint: disable=broad-except
              if (
                  type(plugin) is core_plugin.CorePlugin
              ):  # pylint: disable=unidiomatic-typecheck
                  raise
              logger.warning(
                  "Plugin %s failed. Exception: %s",
                  plugin.plugin_name,
                  str(e),
              )
              continue
          for route, app in plugin_apps.items():
              if not route.startswith("/"):
                  raise ValueError(
                      "Plugin named %r handles invalid route %r: "
                      "route does not start with a slash"
                      % (plugin.plugin_name, route)
                  )
              if (
                  type(plugin) is core_plugin.CorePlugin
              ):  # pylint: disable=unidiomatic-typecheck
                  path = route
              else:
                  path = (
                      DATA_PREFIX
                      + PLUGIN_PREFIX
                      + "/"
                      + plugin.plugin_name
                      + route
                  )
  
              if path.endswith("/*"):
                  # Note we remove the '*' but leave the slash in place.
                  path = path[:-1]
                  if "*" in path:
                      # note we re-add the removed * in the format string
                      raise ValueError(
                          "Plugin %r handles invalid route '%s*': Only "
                          "trailing wildcards are supported "
                          "(i.e., `/.../*`)"
                          % (plugin.plugin_name, path)
                      )
                  unordered_prefix_routes[path] = app
              else:
                  if "*" in path:
                      raise ValueError(
                          "Plugin %r handles invalid route %r: Only "
                          "trailing wildcards are supported "
                          "(i.e., `/.../*`)"
                          % (plugin.plugin_name, path)
                      )
                  self.exact_routes[path] = app
  
      # Wildcard routes will be checked in the given order, so we sort them
      # longest to shortest so that a more specific route will take precedence
      # over a more general one (e.g., a catchall route `/*` should come last).
      self.prefix_routes = collections.OrderedDict(
          sorted(
              unordered_prefix_routes.items(),
              key=lambda x: len(x[0]),
              reverse=True,
          )
      )
  
      self._app = self._create_wsgi_app()
  
imports: import base64
  import collections
  import hashlib
  import io
  import json
  import re
  import textwrap
  import time
  from urllib import parse
  import zipfile
  from werkzeug import wrappers
  from tensorboard import errors
  from tensorboard import plugin_util
  from tensorboard.backend import auth_context_middleware
  from tensorboard.backend import client_feature_flags
  from tensorboard.backend import empty_path_redirect
  from tensorboard.backend import experiment_id
  from tensorboard.backend import experimental_plugin
  from tensorboard.backend import http_util
  from tensorboard.backend import path_prefix
  from tensorboard.backend import security_validator
  from tensorboard.plugins import base_plugin
  from tensorboard.plugins.core import core_plugin
  from tensorboard.util import tb_logging
label_desc: Use image node_id 1 to create a new TensorBoardWSGI object  with example: obj = TensorBoardWSGI(plugins, path_prefix, data_provider, experimental_plugins, auth_providers, experimental_middlewares)