text: #-----------------------------------------------------------------------------
  # Copyright (c) 2012 - 2019, Anaconda, Inc., and Bokeh Contributors.
  # All rights reserved.
  #
  # The full license is in the file LICENSE.txt, distributed with this software.
  #-----------------------------------------------------------------------------
  ''' Thoroughly document Bokeh model classes.
  
  The ``bokeh-model`` directive will automatically document all the attributes
  (including Bokeh properties) of a Bokeh Model subclass. A JSON prototype showing
  all the possible JSON fields will also be generated.
  
  This directive takes the name of a Bokeh model class as an argument and its
  module as an option:
  
  .. code-block:: rest
  
      .. bokeh-model:: Foo
          :module: bokeh.sphinxext.sample
  
  Examples
  --------
  
  For the following definition of ``bokeh.sphinxext.sample.Foo``:
  
  .. code-block:: python
  
      class Foo(Model):
          """ This is a Foo model. """
          index = Either(Auto, Enum('abc', 'def', 'xzy'), help="doc for index")
          value = Tuple(Float, Float, help="doc for value")
  
  
  the above usage yields the output:
  
      .. bokeh-model:: Foo
          :module: bokeh.sphinxext.sample
  
  The ``bokeh-model`` direction may be used explicitly, but it can also be used
  in conjunction with the :ref:`bokeh.sphinxext.bokeh_autodoc` extension.
  
  '''
  
  #-----------------------------------------------------------------------------
  # Boilerplate
  #-----------------------------------------------------------------------------
  import logging
  log = logging.getLogger(__name__)
  
  #-----------------------------------------------------------------------------
  # Imports
  #-----------------------------------------------------------------------------
  
  # Standard library imports
  import importlib
  import json
  import warnings
  
  # External imports
  from docutils.parsers.rst.directives import unchanged
  
  from sphinx.errors import SphinxError
  
  # Bokeh imports
  from ..model import MetaModel
  from ..util.warnings import BokehDeprecationWarning
  from .bokeh_directive import BokehDirective, py_sig_re
  from .templates import MODEL_DETAIL
  
  #-----------------------------------------------------------------------------
  # Globals and constants
  #-----------------------------------------------------------------------------
  
  __all__ = (
      'BokehModelDirective',
      'setup',
  )
  
  #-----------------------------------------------------------------------------
  # General API
  #-----------------------------------------------------------------------------
  
  #-----------------------------------------------------------------------------
  # Dev API
  #-----------------------------------------------------------------------------
  
  class BokehModelDirective(BokehDirective):
  
      has_content = True
      required_arguments = 1
      optional_arguments = 1
      option_spec = {
          'module': unchanged
      }
  
      def run(self):
          sig = " ".join(self.arguments)
  
          m = py_sig_re.match(sig)
          if m is None:
              raise SphinxError("Unable to parse signature for bokeh-model: %r" % sig)
          name_prefix, model_name, arglist, retann = m.groups()
  
          module_name = self.options['module']
  
          try:
              module = importlib.import_module(module_name)
          except ImportError:
              raise SphinxError("Unable to generate reference docs for %s, couldn't import module '%s'" % (model_name, module_name))
  
          model = getattr(module, model_name, None)
          if model is None:
              raise SphinxError("Unable to generate reference docs for %s, no model '%s' in %s" % (model_name, model_name, module_name))
  
          if type(model) != MetaModel:
              raise SphinxError("Unable to generate reference docs for %s, model '%s' is not of type MetaModel" % (model_name, model_name))
  
          # We may need to instantiate deprecated objects as part of documenting
          # them in the reference guide. Suppress any warnings here to keep the
          # docs build clean just for this case
          with warnings.catch_warnings():
              warnings.filterwarnings("ignore", category=BokehDeprecationWarning)
              model_obj = model()
  
          model_json = json.dumps(
              model_obj.to_json(include_defaults=True),
              sort_keys=True,
              indent=2,
              separators=(',', ': ')
          )
  
          rst_text = MODEL_DETAIL.render(
              name=model_name,
              module_name=module_name,
              model_json=model_json,
          )
  
          return self._parse(rst_text, "<bokeh-model>")
  
  def setup(app):
      ''' Required Sphinx extension setup function. '''
      app.add_directive_to_domain('py', 'bokeh-model', BokehModelDirective)
  
  #-----------------------------------------------------------------------------
  # Private API
  #-----------------------------------------------------------------------------
  
  #-----------------------------------------------------------------------------
  # Code
  #-----------------------------------------------------------------------------
  