class_docstr: Interact with dash apps inside jupyter notebooks.
class_docstr_tok: ["Interact","with","dash","apps","inside","jupyter","notebooks","."]
docstr: :type app: dash.Dash
  :param mode: How to display the app on the notebook. One Of:
      ``"external"``: The URL of the app will be displayed in the notebook
          output cell. Clicking this URL will open the app in the default
          web browser.
      ``"inline"``: The app will be displayed inline in the notebook output cell
          in an iframe.
      ``"jupyterlab"``: The app will be displayed in a dedicate tab in the
          JupyterLab interface. Requires JupyterLab and the `jupyterlab-dash`
          extension.
  :param width: Width of app when displayed using mode="inline"
  :param height: Height of app when displayed using mode="inline"
  :param host: Host of the server
  :param port: Port used by the server
  :param server_url: Use if a custom url is required to display the app.
docstr_tok: [":","type","app",":","dash.Dash",":","param","mode",":","How","to","display","the","app","on","the","notebook",".","One","Of",":","``","``","external","''","``",":","The","URL","of","the","app","will","be","displayed","in","the","notebook","output","cell",".","Clicking","this","URL","will","open","the","app","in","the","default","web","browser",".","``","``","inline","''","``",":","The","app","will","be","displayed","inline","in","the","notebook","output","cell","in","an","iframe",".","``","``","jupyterlab","''","``",":","The","app","will","be","displayed","in","a","dedicate","tab","in","the","JupyterLab","interface",".","Requires","JupyterLab","and","the","`","jupyterlab-dash","`","extension",".",":","param","width",":","Width","of","app","when","displayed","using","mode=","''","inline","''",":","param","height",":","Height","of","app","when","displayed","using","mode=","''","inline","''",":","param","host",":","Host","of","the","server",":","param","port",":","Port","used","by","the","server",":","param","server_url",":","Use","if","a","custom","url","is","required","to","display","the","app","."]
code: def run_app(
      self,
      app,
      mode: JupyterDisplayMode = None,
      width="100%",
      height=650,
      host="127.0.0.1",
      port=8050,
      server_url=None,
  ):
      """
      :type app: dash.Dash
      :param mode: How to display the app on the notebook. One Of:
          ``"external"``: The URL of the app will be displayed in the notebook
              output cell. Clicking this URL will open the app in the default
              web browser.
          ``"inline"``: The app will be displayed inline in the notebook output cell
              in an iframe.
          ``"jupyterlab"``: The app will be displayed in a dedicate tab in the
              JupyterLab interface. Requires JupyterLab and the `jupyterlab-dash`
              extension.
      :param width: Width of app when displayed using mode="inline"
      :param height: Height of app when displayed using mode="inline"
      :param host: Host of the server
      :param port: Port used by the server
      :param server_url: Use if a custom url is required to display the app.
      """
      # Validate / infer display mode
      if self.in_colab:
          valid_display_values = ["inline", "external"]
      else:
          valid_display_values = [
              "jupyterlab",
              "inline",
              "external",
              "tab",
              "_none",
          ]
  
      if mode is None:
          mode = self.default_mode
      elif not isinstance(mode, str):
          raise ValueError(
              f"The mode argument must be a string\n"
              f"    Received value of type {type(mode)}: {repr(mode)}"
          )
      else:
          mode = mode.lower()
          if mode not in valid_display_values:
              raise ValueError(
                  f"Invalid display argument {mode}\n"
                  f"    Valid arguments: {valid_display_values}"
              )
  
      # Terminate any existing server using this port
      old_server = self._servers.get((host, port))
      if old_server:
          old_server.shutdown()
          del self._servers[(host, port)]
  
      # Configure pathname prefix
      if "base_subpath" in _jupyter_config:
          requests_pathname_prefix = (
              _jupyter_config["base_subpath"].rstrip("/")
              + "/proxy/{port}/"
          )
      else:
          requests_pathname_prefix = app.config.get(
              "requests_pathname_prefix", None
          )
  
      if requests_pathname_prefix is not None:
          requests_pathname_prefix = requests_pathname_prefix.format(
              port=port
          )
      else:
          requests_pathname_prefix = "/"
  
      # FIXME Move config initialization to main dash __init__
      # low-level setter to circumvent Dash's config locking
      # normally it's unsafe to alter requests_pathname_prefix this late, but
      # Jupyter needs some unusual behavior.
      dict.__setitem__(
          app.config,
          "requests_pathname_prefix",
          requests_pathname_prefix,
      )
  
      # # Compute server_url url
      if server_url is None:
          if "server_url" in _jupyter_config:
              server_url = _jupyter_config["server_url"].rstrip("/")
          else:
              domain_base = os.environ.get("DASH_DOMAIN_BASE", None)
              if domain_base:
                  # Dash Enterprise sets DASH_DOMAIN_BASE environment variable
                  server_url = "https://" + domain_base
              else:
                  server_url = f"http://{host}:{port}"
      else:
          server_url = server_url.rstrip("/")
  
      # server_url = "http://{host}:{port}".format(host=host, port=port)
  
      dashboard_url = f"{server_url}{requests_pathname_prefix}"
  
      # prevent partial import of orjson when it's installed and mode=jupyterlab
      # TODO: why do we need this? Why only in this mode? Importing here in
      # all modes anyway, in case there's a way it can pop up in another mode
      try:
          # pylint: disable=C0415,W0611
          import orjson  # noqa: F401
      except ImportError:
          pass
  
      err_q = queue.Queue()
  
      server = make_server(
          host, port, app.server, threaded=True, processes=0
      )
      logging.getLogger("werkzeug").setLevel(logging.ERROR)
  
      @retry(
          stop_max_attempt_number=15,
          wait_exponential_multiplier=100,
          wait_exponential_max=1000,
      )
      def run():
          try:
              server.serve_forever()
          except SystemExit:
              pass
          except Exception as error:
              err_q.put(error)
              raise error
  
      thread = threading.Thread(target=run)
      thread.daemon = True
      thread.start()
  
      self._servers[(host, port)] = server
  
      # Wait for server to start up
      alive_url = (
          f"http://{host}:{port}/_alive_{JupyterDash.alive_token}"
      )
  
      def _get_error():
          try:
              err = err_q.get_nowait()
              if err:
                  raise err
          except queue.Empty:
              pass
  
      # Wait for app to respond to _alive endpoint
      @retry(
          stop_max_attempt_number=15,
          wait_exponential_multiplier=10,
          wait_exponential_max=1000,
      )
      def wait_for_app():
          _get_error()
          try:
              req = requests.get(alive_url)
              res = req.content.decode()
              if req.status_code != 200:
                  raise Exception(res)
  
              if res != "Alive":
                  url = f"http://{host}:{port}"
                  raise OSError(
                      f"Address '{url}' already in use.\n"
                      "    Try passing a different port to run_server."
                  )
          except requests.ConnectionError as err:
              _get_error()
              raise err
  
      try:
          wait_for_app()
  
          if self.in_colab:
              JupyterDash._display_in_colab(
                  dashboard_url, port, mode, width, height
              )
          else:
              JupyterDash._display_in_jupyter(
                  dashboard_url, port, mode, width, height
              )
      except Exception as final_error:  # pylint: disable=broad-except
          msg = str(final_error)
          if msg.startswith("<!"):
              display(HTML(msg))
          else:
              raise final_error
  
imports: import asyncio
  import io
  import inspect
  import logging
  import os
  import queue
  import uuid
  import sys
  import threading
  import time
  import traceback
  from typing_extensions import Literal
  from werkzeug.serving import make_server
label_desc: Use image node_id 3 for calling the JupyterDash obj's underlying member method code with example usage: obj.run_app(app, mode, width, height, host, port, server_url) without return types