Creates a dispatcher Flask app.

        :param depth:
            Depth of sub-dispatch plots. If negative all levels are plotted.
        :type depth: int, optional

        :param node_data:
            Data node attributes to view.
        :type node_data: tuple[str], optional

        :param node_function:
            Function node attributes to view.
        :type node_function: tuple[str], optional

        :param directory:
            Where is the generated Flask app root located?
        :type directory: str, optional

        :param sites:
            A set of :class:`~schedula.utils.drw.Site` to maintain alive the
            backend server.
        :type sites: set[~schedula.utils.drw.Site], optional

        :param run:
            Run the backend server?
        :type run: bool, optional

        :return:
            A WebMap.
        :rtype: ~schedula.utils.web.WebMap

        Example:

        From a dispatcher like this:

        .. dispatcher:: dsp
           :opt: graph_attr={'ratio': '1'}
           :code:

            >>> from schedula import Dispatcher
            >>> dsp = Dispatcher(name='Dispatcher')
            >>> def fun(a):
            ...     return a + 1, a - 1
            >>> dsp.add_function('fun', fun, ['a'], ['b', 'c'])
            'fun'

        You can create a web server with the following steps::

            >>> webmap = dsp.web()
            >>> print("Starting...\\n"); site = webmap.site().run(); site
            Starting...
            Site(WebMap([(Dispatcher, WebMap())]), host='localhost', ...)
            >>> import requests
            >>> url = '%s/%s/%s' % (site.url, dsp.name, fun.__name__)
            >>> requests.post(url, json={'args': (0,)}).json()['return']
            [1, -1]
            >>> site.shutdown()  # Remember to shutdown the server.
            True

        .. note::
           When :class:`~schedula.utils.drw.Site` is garbage collected the
           server is shutdown automatically.

def web(self, depth=-1, node_data=NONE, node_function=NONE, directory=None,
            sites=None, run=True):
        """
        Creates a dispatcher Flask app.

        :param depth:
            Depth of sub-dispatch plots. If negative all levels are plotted.
        :type depth: int, optional

        :param node_data:
            Data node attributes to view.
        :type node_data: tuple[str], optional

        :param node_function:
            Function node attributes to view.
        :type node_function: tuple[str], optional

        :param directory:
            Where is the generated Flask app root located?
        :type directory: str, optional

        :param sites:
            A set of :class:`~schedula.utils.drw.Site` to maintain alive the
            backend server.
        :type sites: set[~schedula.utils.drw.Site], optional

        :param run:
            Run the backend server?
        :type run: bool, optional

        :return:
            A WebMap.
        :rtype: ~schedula.utils.web.WebMap

        Example:

        From a dispatcher like this:

        .. dispatcher:: dsp
           :opt: graph_attr={'ratio': '1'}
           :code:

            >>> from schedula import Dispatcher
            >>> dsp = Dispatcher(name='Dispatcher')
            >>> def fun(a):
            ...     return a + 1, a - 1
            >>> dsp.add_function('fun', fun, ['a'], ['b', 'c'])
            'fun'

        You can create a web server with the following steps::

            >>> webmap = dsp.web()
            >>> print("Starting...\\n"); site = webmap.site().run(); site
            Starting...
            Site(WebMap([(Dispatcher, WebMap())]), host='localhost', ...)
            >>> import requests
            >>> url = '%s/%s/%s' % (site.url, dsp.name, fun.__name__)
            >>> requests.post(url, json={'args': (0,)}).json()['return']
            [1, -1]
            >>> site.shutdown()  # Remember to shutdown the server.
            True

        .. note::
           When :class:`~schedula.utils.drw.Site` is garbage collected the
           server is shutdown automatically.
        """

        options = {'node_data': node_data, 'node_function': node_function}
        options = {k: v for k, v in options.items() if v is not NONE}
        from .web import WebMap
        from .sol import Solution

        obj = self.dsp if isinstance(self, Solution) else self

        webmap = WebMap()
        webmap.add_items(obj, workflow=False, depth=depth, **options)

        if sites is not None:
            import tempfile
            directory = directory or tempfile.mkdtemp()
            sites.add(webmap.site(directory, view=run))

        return webmap