We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
sphinxext.bokeh_plot missing linenos option implementation
According to the [docs](http://bokeh.pydata.org/en/latest/docs/reference/sphinxext.html#module-bokeh.sphinxext.bokeh_plot) for sphinxext.bokeh_plot, there's a linenos option. However, this appears to be missing, as building
```
.. bokeh-plot::
   :linenos:

    from bokeh.plotting import figure, output_file, show

    output_file("example.html")

    x = [1, 2, 3, 4, 5]
    y = [6, 7, 6, 4, 5]

    p = figure(title="example", plot_width=300, plot_height=300)
    p.line(x, y, line_width=2)
    p.circle(x, y, size=10, fill_color="white")

    show(p)
```
results in the following sphinx error: `ERROR: Error in "bokeh-plot" directive:
unknown option: "linenos".`

Version Info:

Python version : 3.6.0 | packaged by conda-forge | (default, Jan 14 2017, 03:13:00)
IPython version : 5.1.0
Bokeh version : 0.12.4
BokehJS static path : /Users/Atom/.anaconda/envs/py3/lib/python3.6/site-packages/bokeh/server/static
node.js version : v6.3.1
npm version : 3.10.3
jupyter --version : 4.2.1
jupyter notebook --version : 4.3.1
os version : macOS 10.12.3
browser verision: Google Chrome Version 56.0.2924.87 (64-bit)
sphinx version: 1.5.3

This is a really awesome sphinx extension!

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `bokeh/sphinxext/bokeh_plot.py`
Content:
```
1 """ Include Bokeh plots in Sphinx HTML documentation.
2 
3 For other output types, the placeholder text ``[graph]`` will
4 be generated.
5 
6 The ``bokeh-plot`` directive can be used by either supplying:
7 
8 **A path to a source file** as the argument to the directive::
9 
10     .. bokeh-plot:: path/to/plot.py
11 
12 
13 **Inline code** as the content of the directive::
14 
15  .. bokeh-plot::
16 
17      from bokeh.plotting import figure, output_file, show
18 
19      output_file("example.html")
20 
21      x = [1, 2, 3, 4, 5]
22      y = [6, 7, 6, 4, 5]
23 
24      p = figure(title="example", plot_width=300, plot_height=300)
25      p.line(x, y, line_width=2)
26      p.circle(x, y, size=10, fill_color="white")
27 
28      show(p)
29 
30 This directive also works in conjunction with Sphinx autodoc, when
31 used in docstrings.
32 
33 The ``bokeh-plot`` directive accepts the following options:
34 
35 source-position : enum('above', 'below', 'none')
36     Where to locate the the block of formatted source
37     code (if anywhere).
38 
39 linenos : bool
40     Whether to display line numbers along with the source.
41 
42 Examples
43 --------
44 
45 The inline example code above produces the following output:
46 
47 .. bokeh-plot::
48 
49     from bokeh.plotting import figure, output_file, show
50 
51     output_file("example.html")
52 
53     x = [1, 2, 3, 4, 5]
54     y = [6, 7, 6, 4, 5]
55 
56     p = figure(title="example", plot_width=300, plot_height=300)
57     p.line(x, y, line_width=2)
58     p.circle(x, y, size=10, fill_color="white")
59 
60     show(p)
61 
62 """
63 from __future__ import absolute_import
64 
65 import ast
66 import hashlib
67 from os import getenv
68 from os.path import basename, dirname, join
69 import re
70 
71 from docutils import nodes
72 from docutils.parsers.rst import Directive, Parser
73 from docutils.parsers.rst.directives import choice
74 
75 from sphinx.errors import SphinxError
76 from sphinx.util import console, copyfile, ensuredir
77 from sphinx.util.nodes import set_source_info
78 
79 from ..document import Document
80 from ..embed import autoload_static
81 from ..resources import Resources
82 from ..settings import settings
83 from ..util.string import decode_utf8
84 from .example_handler import ExampleHandler
85 from .templates import PLOT_PAGE
86 
87 if settings.docs_cdn() == "local":
88     resources = Resources(mode="server", root_url="/en/latest/")
89 else:
90     resources = Resources(mode="cdn")
91 
92 GOOGLE_API_KEY = getenv('GOOGLE_API_KEY')
93 if GOOGLE_API_KEY is None:
94     if settings.docs_missing_api_key_ok():
95         GOOGLE_API_KEY = "MISSING_API_KEY"
96     else:
97         raise SphinxError("The GOOGLE_API_KEY environment variable is not set. Set GOOGLE_API_KEY to a valid API key, "
98                           "or set BOKEH_DOCS_MISSING_API_KEY_OK=yes to build anyway (with broken GMaps)")
99 
100 CODING = re.compile(r"^# -\*- coding: (.*) -\*-$", re.M)
101 
102 class PlotScriptError(SphinxError):
103     """ Error during script parsing. """
104 
105     category = 'PlotScript error'
106 
107 def _process_script(source, filename, auxdir, js_name):
108     # This is lame, but seems to be required for python 2
109     source = CODING.sub("", source)
110 
111     # quick and dirty way to inject Google API key
112     if "GOOGLE_API_KEY" in source:
113         run_source = source.replace("GOOGLE_API_KEY", GOOGLE_API_KEY)
114     else:
115         run_source = source
116 
117     c = ExampleHandler(source=run_source, filename=filename)
118     d = Document()
119     c.modify_document(d)
120     if c.error:
121         raise PlotScriptError(c.error_detail)
122 
123     script_path = join("/scripts", js_name)
124     js_path = join(auxdir, js_name)
125     js, script = autoload_static(d.roots[0], resources, script_path)
126 
127     with open(js_path, "w") as f:
128         f.write(js)
129 
130     return (script, js, js_path, source)
131 
132 class PlotScriptParser(Parser):
133     """ This Parser recognizes .py files in the Sphinx source tree,
134     assuming that they contain bokeh examples
135 
136     Note: it is important that the .py files are parsed first. This is
137     accomplished by reordering the doc names in the env_before_read_docs callback
138 
139     """
140 
141     supported = ('python',)
142 
143     def parse(self, source, document):
144         """ Parse ``source``, write results to ``document``.
145 
146         """
147         # This is lame, but seems to be required for python 2
148         source = CODING.sub("", source)
149 
150         env = document.settings.env
151         filename = env.doc2path(env.docname) # e.g. full path to docs/user_guide/examples/layout_vertical
152 
153         # This code splits the source into two parts: the docstring (or None if
154         # there is not one), and the remaining source code after
155         m = ast.parse(source)
156         docstring = ast.get_docstring(m)
157         if docstring is not None:
158             lines = source.split("\n")
159             lineno = m.body[0].lineno # assumes docstring is m.body[0]
160             source = "\n".join(lines[lineno:])
161 
162         js_name = "bokeh-plot-%s.js" % hashlib.md5(env.docname.encode('utf-8')).hexdigest()
163 
164         (script, js, js_path, source) = _process_script(source, filename, env.bokeh_plot_auxdir, js_name)
165 
166         env.bokeh_plot_files[env.docname] = (script, js, js_path, source)
167 
168         rst = PLOT_PAGE.render(source=source,
169                                filename=basename(filename),
170                                docstring=docstring,
171                                script=script)
172 
173         document['bokeh_plot_include_bokehjs'] = True
174 
175         # can't use super, Sphinx Parser classes don't inherit object
176         Parser.parse(self, rst, document)
177 
178 class BokehPlotDirective(Directive):
179 
180     has_content = True
181     optional_arguments = 2
182 
183     option_spec = {
184         'source-position': lambda x: choice(x, ('below', 'above', 'none')),
185     }
186 
187     def run(self):
188 
189         env = self.state.document.settings.env
190         app = env.app
191 
192         # filename *or* python code content, but not both
193         if self.arguments and self.content:
194             raise SphinxError("bokeh-plot:: directive can't have both args and content")
195 
196         # process inline examples here
197         if self.content:
198             app.debug("[bokeh-plot] handling inline example in %r", env.docname)
199             source = '\n'.join(self.content)
200             # need docname not to look like a path
201             docname = env.docname.replace("/", "-")
202             serialno = env.new_serialno(env.docname)
203             js_name = "bokeh-plot-%s-inline-%d.js" % (docname, serialno)
204             # the code runner just needs a real path to cd to, this will do
205             path = join(env.bokeh_plot_auxdir, js_name)
206 
207             (script, js, js_path, source) = _process_script(source, path, env.bokeh_plot_auxdir, js_name)
208             env.bokeh_plot_files[js_name] = (script, js, js_path, source)
209 
210         # process example files here
211         else:
212             example_path = self.arguments[0][:-3]  # remove the ".py"
213 
214             # if it's an "internal" example, the python parser has already handled it
215             if example_path in env.bokeh_plot_files:
216                 app.debug("[bokeh-plot] handling internal example in %r: %s", env.docname, self.arguments[0])
217                 (script, js, js_path, source) = env.bokeh_plot_files[example_path]
218 
219             # handle examples external to the docs source, e.g. gallery examples
220             else:
221                 app.debug("[bokeh-plot] handling external example in %r: %s", env.docname, self.arguments[0])
222                 source = open(self.arguments[0]).read()
223                 source = decode_utf8(source)
224                 docname = env.docname.replace("/", "-")
225                 serialno = env.new_serialno(env.docname)
226                 js_name = "bokeh-plot-%s-external-%d.js" % (docname, serialno)
227                 (script, js, js_path, source) = _process_script(source, self.arguments[0], env.bokeh_plot_auxdir, js_name)
228                 env.bokeh_plot_files[js_name] = (script, js, js_path, source)
229 
230         # use the source file name to construct a friendly target_id
231         target_id = "%s.%s" % (env.docname, basename(js_path))
232         target = nodes.target('', '', ids=[target_id])
233         result = [target]
234 
235         code = nodes.literal_block(source, source, language="python", linenos=False, classes=[])
236         set_source_info(self, code)
237 
238         source_position = self.options.get('source-position', 'below')
239 
240         if source_position == "above": result += [code]
241 
242         result += [nodes.raw('', script, format="html")]
243 
244         if source_position == "below": result += [code]
245 
246         return result
247 
248 def env_before_read_docs(app, env, docnames):
249     docnames.sort(key=lambda x: 2 if "extension" in x else 0 if "examples" in x else 1)
250 
251 def builder_inited(app):
252     app.env.bokeh_plot_auxdir = join(app.env.doctreedir, 'bokeh_plot')
253     ensuredir(app.env.bokeh_plot_auxdir) # sphinx/_build/doctrees/bokeh_plot
254 
255     if not hasattr(app.env, 'bokeh_plot_files'):
256         app.env.bokeh_plot_files = {}
257 
258 def html_page_context(app, pagename, templatename, context, doctree):
259     """ Add BokehJS to pages that contain plots.
260 
261     """
262     if doctree and doctree.get('bokeh_plot_include_bokehjs'):
263         context['bokeh_css_files'] = resources.css_files
264         context['bokeh_js_files'] = resources.js_files
265 
266 def build_finished(app, exception):
267     files = set()
268 
269     for (script, js, js_path, source) in app.env.bokeh_plot_files.values():
270         files.add(js_path)
271 
272     files_iter = app.status_iterator(sorted(files),
273                                      'copying bokeh-plot files... ',
274                                      console.brown,
275                                      len(files),
276                                      lambda x: basename(x))
277 
278     for file in files_iter:
279         target = join(app.builder.outdir, "scripts", basename(file))
280         ensuredir(dirname(target))
281         try:
282             copyfile(file, target)
283         except OSError as e:
284             raise SphinxError('cannot copy local file %r, reason: %s' % (file, e))
285 
286 def env_purge_doc(app, env, docname):
287     """ Remove local files for a given document.
288 
289     """
290     if docname in env.bokeh_plot_files:
291         del env.bokeh_plot_files[docname]
292 
293 def setup(app):
294     app.add_source_parser('.py', PlotScriptParser)
295 
296     app.add_directive('bokeh-plot', BokehPlotDirective)
297 
298     app.connect('env-before-read-docs', env_before_read_docs)
299     app.connect('builder-inited',       builder_inited)
300     app.connect('html-page-context',    html_page_context)
301     app.connect('build-finished',       build_finished)
302     app.connect('env-purge-doc',        env_purge_doc)
303
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/bokeh/sphinxext/bokeh_plot.py b/bokeh/sphinxext/bokeh_plot.py
--- a/bokeh/sphinxext/bokeh_plot.py
+++ b/bokeh/sphinxext/bokeh_plot.py
@@ -36,7 +36,7 @@
     Where to locate the the block of formatted source
     code (if anywhere).
 
-linenos : bool
+linenos : flag
     Whether to display line numbers along with the source.
 
 Examples
@@ -70,7 +70,7 @@
 
 from docutils import nodes
 from docutils.parsers.rst import Directive, Parser
-from docutils.parsers.rst.directives import choice
+from docutils.parsers.rst.directives import choice, flag
 
 from sphinx.errors import SphinxError
 from sphinx.util import console, copyfile, ensuredir
@@ -182,6 +182,7 @@
 
     option_spec = {
         'source-position': lambda x: choice(x, ('below', 'above', 'none')),
+        'linenos': lambda x: True if flag(x) is None else False,
     }
 
     def run(self):
@@ -232,7 +233,8 @@
         target = nodes.target('', '', ids=[target_id])
         result = [target]
 
-        code = nodes.literal_block(source, source, language="python", linenos=False, classes=[])
+        linenos = self.options.get('linenos', False)
+        code = nodes.literal_block(source, source, language="python", linenos=linenos, classes=[])
         set_source_info(self, code)
 
         source_position = self.options.get('source-position', 'below')

{"golden_diff": "diff --git a/bokeh/sphinxext/bokeh_plot.py b/bokeh/sphinxext/bokeh_plot.py\n--- a/bokeh/sphinxext/bokeh_plot.py\n+++ b/bokeh/sphinxext/bokeh_plot.py\n@@ -36,7 +36,7 @@\n     Where to locate the the block of formatted source\n     code (if anywhere).\n \n-linenos : bool\n+linenos : flag\n     Whether to display line numbers along with the source.\n \n Examples\n@@ -70,7 +70,7 @@\n \n from docutils import nodes\n from docutils.parsers.rst import Directive, Parser\n-from docutils.parsers.rst.directives import choice\n+from docutils.parsers.rst.directives import choice, flag\n \n from sphinx.errors import SphinxError\n from sphinx.util import console, copyfile, ensuredir\n@@ -182,6 +182,7 @@\n \n     option_spec = {\n         'source-position': lambda x: choice(x, ('below', 'above', 'none')),\n+        'linenos': lambda x: True if flag(x) is None else False,\n     }\n \n     def run(self):\n@@ -232,7 +233,8 @@\n         target = nodes.target('', '', ids=[target_id])\n         result = [target]\n \n-        code = nodes.literal_block(source, source, language=\"python\", linenos=False, classes=[])\n+        linenos = self.options.get('linenos', False)\n+        code = nodes.literal_block(source, source, language=\"python\", linenos=linenos, classes=[])\n         set_source_info(self, code)\n \n         source_position = self.options.get('source-position', 'below')\n", "issue": "sphinxext.bokeh_plot missing linenos option implementation\nAccording to the [docs](http://bokeh.pydata.org/en/latest/docs/reference/sphinxext.html#module-bokeh.sphinxext.bokeh_plot) for sphinxext.bokeh_plot, there's a linenos option. However, this appears to be missing, as building\r\n```\r\n.. bokeh-plot::\r\n   :linenos:\r\n\r\n    from bokeh.plotting import figure, output_file, show\r\n\r\n    output_file(\"example.html\")\r\n\r\n    x = [1, 2, 3, 4, 5]\r\n    y = [6, 7, 6, 4, 5]\r\n\r\n    p = figure(title=\"example\", plot_width=300, plot_height=300)\r\n    p.line(x, y, line_width=2)\r\n    p.circle(x, y, size=10, fill_color=\"white\")\r\n\r\n    show(p)\r\n```\r\nresults in the following sphinx error: `ERROR: Error in \"bokeh-plot\" directive:\r\nunknown option: \"linenos\".`\r\n\r\nVersion Info:\r\n\r\nPython version : 3.6.0 | packaged by conda-forge | (default, Jan 14 2017, 03:13:00)\r\nIPython version : 5.1.0\r\nBokeh version : 0.12.4\r\nBokehJS static path : /Users/Atom/.anaconda/envs/py3/lib/python3.6/site-packages/bokeh/server/static\r\nnode.js version : v6.3.1\r\nnpm version : 3.10.3\r\njupyter --version : 4.2.1\r\njupyter notebook --version : 4.3.1\r\nos version : macOS 10.12.3\r\nbrowser verision: Google Chrome Version 56.0.2924.87 (64-bit)\r\nsphinx version: 1.5.3\r\n\r\nThis is a really awesome sphinx extension!\n", "before_files": [{"content": "\"\"\" Include Bokeh plots in Sphinx HTML documentation.\n\nFor other output types, the placeholder text ``[graph]`` will\nbe generated.\n\nThe ``bokeh-plot`` directive can be used by either supplying:\n\n**A path to a source file** as the argument to the directive::\n\n    .. bokeh-plot:: path/to/plot.py\n\n\n**Inline code** as the content of the directive::\n\n .. bokeh-plot::\n\n     from bokeh.plotting import figure, output_file, show\n\n     output_file(\"example.html\")\n\n     x = [1, 2, 3, 4, 5]\n     y = [6, 7, 6, 4, 5]\n\n     p = figure(title=\"example\", plot_width=300, plot_height=300)\n     p.line(x, y, line_width=2)\n     p.circle(x, y, size=10, fill_color=\"white\")\n\n     show(p)\n\nThis directive also works in conjunction with Sphinx autodoc, when\nused in docstrings.\n\nThe ``bokeh-plot`` directive accepts the following options:\n\nsource-position : enum('above', 'below', 'none')\n    Where to locate the the block of formatted source\n    code (if anywhere).\n\nlinenos : bool\n    Whether to display line numbers along with the source.\n\nExamples\n--------\n\nThe inline example code above produces the following output:\n\n.. bokeh-plot::\n\n    from bokeh.plotting import figure, output_file, show\n\n    output_file(\"example.html\")\n\n    x = [1, 2, 3, 4, 5]\n    y = [6, 7, 6, 4, 5]\n\n    p = figure(title=\"example\", plot_width=300, plot_height=300)\n    p.line(x, y, line_width=2)\n    p.circle(x, y, size=10, fill_color=\"white\")\n\n    show(p)\n\n\"\"\"\nfrom __future__ import absolute_import\n\nimport ast\nimport hashlib\nfrom os import getenv\nfrom os.path import basename, dirname, join\nimport re\n\nfrom docutils import nodes\nfrom docutils.parsers.rst import Directive, Parser\nfrom docutils.parsers.rst.directives import choice\n\nfrom sphinx.errors import SphinxError\nfrom sphinx.util import console, copyfile, ensuredir\nfrom sphinx.util.nodes import set_source_info\n\nfrom ..document import Document\nfrom ..embed import autoload_static\nfrom ..resources import Resources\nfrom ..settings import settings\nfrom ..util.string import decode_utf8\nfrom .example_handler import ExampleHandler\nfrom .templates import PLOT_PAGE\n\nif settings.docs_cdn() == \"local\":\n    resources = Resources(mode=\"server\", root_url=\"/en/latest/\")\nelse:\n    resources = Resources(mode=\"cdn\")\n\nGOOGLE_API_KEY = getenv('GOOGLE_API_KEY')\nif GOOGLE_API_KEY is None:\n    if settings.docs_missing_api_key_ok():\n        GOOGLE_API_KEY = \"MISSING_API_KEY\"\n    else:\n        raise SphinxError(\"The GOOGLE_API_KEY environment variable is not set. Set GOOGLE_API_KEY to a valid API key, \"\n                          \"or set BOKEH_DOCS_MISSING_API_KEY_OK=yes to build anyway (with broken GMaps)\")\n\nCODING = re.compile(r\"^# -\\*- coding: (.*) -\\*-$\", re.M)\n\nclass PlotScriptError(SphinxError):\n    \"\"\" Error during script parsing. \"\"\"\n\n    category = 'PlotScript error'\n\ndef _process_script(source, filename, auxdir, js_name):\n    # This is lame, but seems to be required for python 2\n    source = CODING.sub(\"\", source)\n\n    # quick and dirty way to inject Google API key\n    if \"GOOGLE_API_KEY\" in source:\n        run_source = source.replace(\"GOOGLE_API_KEY\", GOOGLE_API_KEY)\n    else:\n        run_source = source\n\n    c = ExampleHandler(source=run_source, filename=filename)\n    d = Document()\n    c.modify_document(d)\n    if c.error:\n        raise PlotScriptError(c.error_detail)\n\n    script_path = join(\"/scripts\", js_name)\n    js_path = join(auxdir, js_name)\n    js, script = autoload_static(d.roots[0], resources, script_path)\n\n    with open(js_path, \"w\") as f:\n        f.write(js)\n\n    return (script, js, js_path, source)\n\nclass PlotScriptParser(Parser):\n    \"\"\" This Parser recognizes .py files in the Sphinx source tree,\n    assuming that they contain bokeh examples\n\n    Note: it is important that the .py files are parsed first. This is\n    accomplished by reordering the doc names in the env_before_read_docs callback\n\n    \"\"\"\n\n    supported = ('python',)\n\n    def parse(self, source, document):\n        \"\"\" Parse ``source``, write results to ``document``.\n\n        \"\"\"\n        # This is lame, but seems to be required for python 2\n        source = CODING.sub(\"\", source)\n\n        env = document.settings.env\n        filename = env.doc2path(env.docname) # e.g. full path to docs/user_guide/examples/layout_vertical\n\n        # This code splits the source into two parts: the docstring (or None if\n        # there is not one), and the remaining source code after\n        m = ast.parse(source)\n        docstring = ast.get_docstring(m)\n        if docstring is not None:\n            lines = source.split(\"\\n\")\n            lineno = m.body[0].lineno # assumes docstring is m.body[0]\n            source = \"\\n\".join(lines[lineno:])\n\n        js_name = \"bokeh-plot-%s.js\" % hashlib.md5(env.docname.encode('utf-8')).hexdigest()\n\n        (script, js, js_path, source) = _process_script(source, filename, env.bokeh_plot_auxdir, js_name)\n\n        env.bokeh_plot_files[env.docname] = (script, js, js_path, source)\n\n        rst = PLOT_PAGE.render(source=source,\n                               filename=basename(filename),\n                               docstring=docstring,\n                               script=script)\n\n        document['bokeh_plot_include_bokehjs'] = True\n\n        # can't use super, Sphinx Parser classes don't inherit object\n        Parser.parse(self, rst, document)\n\nclass BokehPlotDirective(Directive):\n\n    has_content = True\n    optional_arguments = 2\n\n    option_spec = {\n        'source-position': lambda x: choice(x, ('below', 'above', 'none')),\n    }\n\n    def run(self):\n\n        env = self.state.document.settings.env\n        app = env.app\n\n        # filename *or* python code content, but not both\n        if self.arguments and self.content:\n            raise SphinxError(\"bokeh-plot:: directive can't have both args and content\")\n\n        # process inline examples here\n        if self.content:\n            app.debug(\"[bokeh-plot] handling inline example in %r\", env.docname)\n            source = '\\n'.join(self.content)\n            # need docname not to look like a path\n            docname = env.docname.replace(\"/\", \"-\")\n            serialno = env.new_serialno(env.docname)\n            js_name = \"bokeh-plot-%s-inline-%d.js\" % (docname, serialno)\n            # the code runner just needs a real path to cd to, this will do\n            path = join(env.bokeh_plot_auxdir, js_name)\n\n            (script, js, js_path, source) = _process_script(source, path, env.bokeh_plot_auxdir, js_name)\n            env.bokeh_plot_files[js_name] = (script, js, js_path, source)\n\n        # process example files here\n        else:\n            example_path = self.arguments[0][:-3]  # remove the \".py\"\n\n            # if it's an \"internal\" example, the python parser has already handled it\n            if example_path in env.bokeh_plot_files:\n                app.debug(\"[bokeh-plot] handling internal example in %r: %s\", env.docname, self.arguments[0])\n                (script, js, js_path, source) = env.bokeh_plot_files[example_path]\n\n            # handle examples external to the docs source, e.g. gallery examples\n            else:\n                app.debug(\"[bokeh-plot] handling external example in %r: %s\", env.docname, self.arguments[0])\n                source = open(self.arguments[0]).read()\n                source = decode_utf8(source)\n                docname = env.docname.replace(\"/\", \"-\")\n                serialno = env.new_serialno(env.docname)\n                js_name = \"bokeh-plot-%s-external-%d.js\" % (docname, serialno)\n                (script, js, js_path, source) = _process_script(source, self.arguments[0], env.bokeh_plot_auxdir, js_name)\n                env.bokeh_plot_files[js_name] = (script, js, js_path, source)\n\n        # use the source file name to construct a friendly target_id\n        target_id = \"%s.%s\" % (env.docname, basename(js_path))\n        target = nodes.target('', '', ids=[target_id])\n        result = [target]\n\n        code = nodes.literal_block(source, source, language=\"python\", linenos=False, classes=[])\n        set_source_info(self, code)\n\n        source_position = self.options.get('source-position', 'below')\n\n        if source_position == \"above\": result += [code]\n\n        result += [nodes.raw('', script, format=\"html\")]\n\n        if source_position == \"below\": result += [code]\n\n        return result\n\ndef env_before_read_docs(app, env, docnames):\n    docnames.sort(key=lambda x: 2 if \"extension\" in x else 0 if \"examples\" in x else 1)\n\ndef builder_inited(app):\n    app.env.bokeh_plot_auxdir = join(app.env.doctreedir, 'bokeh_plot')\n    ensuredir(app.env.bokeh_plot_auxdir) # sphinx/_build/doctrees/bokeh_plot\n\n    if not hasattr(app.env, 'bokeh_plot_files'):\n        app.env.bokeh_plot_files = {}\n\ndef html_page_context(app, pagename, templatename, context, doctree):\n    \"\"\" Add BokehJS to pages that contain plots.\n\n    \"\"\"\n    if doctree and doctree.get('bokeh_plot_include_bokehjs'):\n        context['bokeh_css_files'] = resources.css_files\n        context['bokeh_js_files'] = resources.js_files\n\ndef build_finished(app, exception):\n    files = set()\n\n    for (script, js, js_path, source) in app.env.bokeh_plot_files.values():\n        files.add(js_path)\n\n    files_iter = app.status_iterator(sorted(files),\n                                     'copying bokeh-plot files... ',\n                                     console.brown,\n                                     len(files),\n                                     lambda x: basename(x))\n\n    for file in files_iter:\n        target = join(app.builder.outdir, \"scripts\", basename(file))\n        ensuredir(dirname(target))\n        try:\n            copyfile(file, target)\n        except OSError as e:\n            raise SphinxError('cannot copy local file %r, reason: %s' % (file, e))\n\ndef env_purge_doc(app, env, docname):\n    \"\"\" Remove local files for a given document.\n\n    \"\"\"\n    if docname in env.bokeh_plot_files:\n        del env.bokeh_plot_files[docname]\n\ndef setup(app):\n    app.add_source_parser('.py', PlotScriptParser)\n\n    app.add_directive('bokeh-plot', BokehPlotDirective)\n\n    app.connect('env-before-read-docs', env_before_read_docs)\n    app.connect('builder-inited',       builder_inited)\n    app.connect('html-page-context',    html_page_context)\n    app.connect('build-finished',       build_finished)\n    app.connect('env-purge-doc',        env_purge_doc)\n", "path": "bokeh/sphinxext/bokeh_plot.py"}], "after_files": [{"content": "\"\"\" Include Bokeh plots in Sphinx HTML documentation.\n\nFor other output types, the placeholder text ``[graph]`` will\nbe generated.\n\nThe ``bokeh-plot`` directive can be used by either supplying:\n\n**A path to a source file** as the argument to the directive::\n\n    .. bokeh-plot:: path/to/plot.py\n\n\n**Inline code** as the content of the directive::\n\n .. bokeh-plot::\n\n     from bokeh.plotting import figure, output_file, show\n\n     output_file(\"example.html\")\n\n     x = [1, 2, 3, 4, 5]\n     y = [6, 7, 6, 4, 5]\n\n     p = figure(title=\"example\", plot_width=300, plot_height=300)\n     p.line(x, y, line_width=2)\n     p.circle(x, y, size=10, fill_color=\"white\")\n\n     show(p)\n\nThis directive also works in conjunction with Sphinx autodoc, when\nused in docstrings.\n\nThe ``bokeh-plot`` directive accepts the following options:\n\nsource-position : enum('above', 'below', 'none')\n    Where to locate the the block of formatted source\n    code (if anywhere).\n\nlinenos : flag\n    Whether to display line numbers along with the source.\n\nExamples\n--------\n\nThe inline example code above produces the following output:\n\n.. bokeh-plot::\n\n    from bokeh.plotting import figure, output_file, show\n\n    output_file(\"example.html\")\n\n    x = [1, 2, 3, 4, 5]\n    y = [6, 7, 6, 4, 5]\n\n    p = figure(title=\"example\", plot_width=300, plot_height=300)\n    p.line(x, y, line_width=2)\n    p.circle(x, y, size=10, fill_color=\"white\")\n\n    show(p)\n\n\"\"\"\nfrom __future__ import absolute_import\n\nimport ast\nimport hashlib\nfrom os import getenv\nfrom os.path import basename, dirname, join\nimport re\n\nfrom docutils import nodes\nfrom docutils.parsers.rst import Directive, Parser\nfrom docutils.parsers.rst.directives import choice, flag\n\nfrom sphinx.errors import SphinxError\nfrom sphinx.util import console, copyfile, ensuredir\nfrom sphinx.util.nodes import set_source_info\n\nfrom ..document import Document\nfrom ..embed import autoload_static\nfrom ..resources import Resources\nfrom ..settings import settings\nfrom ..util.string import decode_utf8\nfrom .example_handler import ExampleHandler\nfrom .templates import PLOT_PAGE\n\nif settings.docs_cdn() == \"local\":\n    resources = Resources(mode=\"server\", root_url=\"/en/latest/\")\nelse:\n    resources = Resources(mode=\"cdn\")\n\nGOOGLE_API_KEY = getenv('GOOGLE_API_KEY')\nif GOOGLE_API_KEY is None:\n    if settings.docs_missing_api_key_ok():\n        GOOGLE_API_KEY = \"MISSING_API_KEY\"\n    else:\n        raise SphinxError(\"The GOOGLE_API_KEY environment variable is not set. Set GOOGLE_API_KEY to a valid API key, \"\n                          \"or set BOKEH_DOCS_MISSING_API_KEY_OK=yes to build anyway (with broken GMaps)\")\n\nCODING = re.compile(r\"^# -\\*- coding: (.*) -\\*-$\", re.M)\n\nclass PlotScriptError(SphinxError):\n    \"\"\" Error during script parsing. \"\"\"\n\n    category = 'PlotScript error'\n\ndef _process_script(source, filename, auxdir, js_name):\n    # This is lame, but seems to be required for python 2\n    source = CODING.sub(\"\", source)\n\n    # quick and dirty way to inject Google API key\n    if \"GOOGLE_API_KEY\" in source:\n        run_source = source.replace(\"GOOGLE_API_KEY\", GOOGLE_API_KEY)\n    else:\n        run_source = source\n\n    c = ExampleHandler(source=run_source, filename=filename)\n    d = Document()\n    c.modify_document(d)\n    if c.error:\n        raise PlotScriptError(c.error_detail)\n\n    script_path = join(\"/scripts\", js_name)\n    js_path = join(auxdir, js_name)\n    js, script = autoload_static(d.roots[0], resources, script_path)\n\n    with open(js_path, \"w\") as f:\n        f.write(js)\n\n    return (script, js, js_path, source)\n\nclass PlotScriptParser(Parser):\n    \"\"\" This Parser recognizes .py files in the Sphinx source tree,\n    assuming that they contain bokeh examples\n\n    Note: it is important that the .py files are parsed first. This is\n    accomplished by reordering the doc names in the env_before_read_docs callback\n\n    \"\"\"\n\n    supported = ('python',)\n\n    def parse(self, source, document):\n        \"\"\" Parse ``source``, write results to ``document``.\n\n        \"\"\"\n        # This is lame, but seems to be required for python 2\n        source = CODING.sub(\"\", source)\n\n        env = document.settings.env\n        filename = env.doc2path(env.docname) # e.g. full path to docs/user_guide/examples/layout_vertical\n\n        # This code splits the source into two parts: the docstring (or None if\n        # there is not one), and the remaining source code after\n        m = ast.parse(source)\n        docstring = ast.get_docstring(m)\n        if docstring is not None:\n            lines = source.split(\"\\n\")\n            lineno = m.body[0].lineno # assumes docstring is m.body[0]\n            source = \"\\n\".join(lines[lineno:])\n\n        js_name = \"bokeh-plot-%s.js\" % hashlib.md5(env.docname.encode('utf-8')).hexdigest()\n\n        (script, js, js_path, source) = _process_script(source, filename, env.bokeh_plot_auxdir, js_name)\n\n        env.bokeh_plot_files[env.docname] = (script, js, js_path, source)\n\n        rst = PLOT_PAGE.render(source=source,\n                               filename=basename(filename),\n                               docstring=docstring,\n                               script=script)\n\n        document['bokeh_plot_include_bokehjs'] = True\n\n        # can't use super, Sphinx Parser classes don't inherit object\n        Parser.parse(self, rst, document)\n\nclass BokehPlotDirective(Directive):\n\n    has_content = True\n    optional_arguments = 2\n\n    option_spec = {\n        'source-position': lambda x: choice(x, ('below', 'above', 'none')),\n        'linenos': lambda x: True if flag(x) is None else False,\n    }\n\n    def run(self):\n\n        env = self.state.document.settings.env\n        app = env.app\n\n        # filename *or* python code content, but not both\n        if self.arguments and self.content:\n            raise SphinxError(\"bokeh-plot:: directive can't have both args and content\")\n\n        # process inline examples here\n        if self.content:\n            app.debug(\"[bokeh-plot] handling inline example in %r\", env.docname)\n            source = '\\n'.join(self.content)\n            # need docname not to look like a path\n            docname = env.docname.replace(\"/\", \"-\")\n            serialno = env.new_serialno(env.docname)\n            js_name = \"bokeh-plot-%s-inline-%d.js\" % (docname, serialno)\n            # the code runner just needs a real path to cd to, this will do\n            path = join(env.bokeh_plot_auxdir, js_name)\n\n            (script, js, js_path, source) = _process_script(source, path, env.bokeh_plot_auxdir, js_name)\n            env.bokeh_plot_files[js_name] = (script, js, js_path, source)\n\n        # process example files here\n        else:\n            example_path = self.arguments[0][:-3]  # remove the \".py\"\n\n            # if it's an \"internal\" example, the python parser has already handled it\n            if example_path in env.bokeh_plot_files:\n                app.debug(\"[bokeh-plot] handling internal example in %r: %s\", env.docname, self.arguments[0])\n                (script, js, js_path, source) = env.bokeh_plot_files[example_path]\n\n            # handle examples external to the docs source, e.g. gallery examples\n            else:\n                app.debug(\"[bokeh-plot] handling external example in %r: %s\", env.docname, self.arguments[0])\n                source = open(self.arguments[0]).read()\n                source = decode_utf8(source)\n                docname = env.docname.replace(\"/\", \"-\")\n                serialno = env.new_serialno(env.docname)\n                js_name = \"bokeh-plot-%s-external-%d.js\" % (docname, serialno)\n                (script, js, js_path, source) = _process_script(source, self.arguments[0], env.bokeh_plot_auxdir, js_name)\n                env.bokeh_plot_files[js_name] = (script, js, js_path, source)\n\n        # use the source file name to construct a friendly target_id\n        target_id = \"%s.%s\" % (env.docname, basename(js_path))\n        target = nodes.target('', '', ids=[target_id])\n        result = [target]\n\n        linenos = self.options.get('linenos', False)\n        code = nodes.literal_block(source, source, language=\"python\", linenos=linenos, classes=[])\n        set_source_info(self, code)\n\n        source_position = self.options.get('source-position', 'below')\n\n        if source_position == \"above\": result += [code]\n\n        result += [nodes.raw('', script, format=\"html\")]\n\n        if source_position == \"below\": result += [code]\n\n        return result\n\ndef env_before_read_docs(app, env, docnames):\n    docnames.sort(key=lambda x: 2 if \"extension\" in x else 0 if \"examples\" in x else 1)\n\ndef builder_inited(app):\n    app.env.bokeh_plot_auxdir = join(app.env.doctreedir, 'bokeh_plot')\n    ensuredir(app.env.bokeh_plot_auxdir) # sphinx/_build/doctrees/bokeh_plot\n\n    if not hasattr(app.env, 'bokeh_plot_files'):\n        app.env.bokeh_plot_files = {}\n\ndef html_page_context(app, pagename, templatename, context, doctree):\n    \"\"\" Add BokehJS to pages that contain plots.\n\n    \"\"\"\n    if doctree and doctree.get('bokeh_plot_include_bokehjs'):\n        context['bokeh_css_files'] = resources.css_files\n        context['bokeh_js_files'] = resources.js_files\n\ndef build_finished(app, exception):\n    files = set()\n\n    for (script, js, js_path, source) in app.env.bokeh_plot_files.values():\n        files.add(js_path)\n\n    files_iter = app.status_iterator(sorted(files),\n                                     'copying bokeh-plot files... ',\n                                     console.brown,\n                                     len(files),\n                                     lambda x: basename(x))\n\n    for file in files_iter:\n        target = join(app.builder.outdir, \"scripts\", basename(file))\n        ensuredir(dirname(target))\n        try:\n            copyfile(file, target)\n        except OSError as e:\n            raise SphinxError('cannot copy local file %r, reason: %s' % (file, e))\n\ndef env_purge_doc(app, env, docname):\n    \"\"\" Remove local files for a given document.\n\n    \"\"\"\n    if docname in env.bokeh_plot_files:\n        del env.bokeh_plot_files[docname]\n\ndef setup(app):\n    app.add_source_parser('.py', PlotScriptParser)\n\n    app.add_directive('bokeh-plot', BokehPlotDirective)\n\n    app.connect('env-before-read-docs', env_before_read_docs)\n    app.connect('builder-inited',       builder_inited)\n    app.connect('html-page-context',    html_page_context)\n    app.connect('build-finished',       build_finished)\n    app.connect('env-purge-doc',        env_purge_doc)\n", "path": "bokeh/sphinxext/bokeh_plot.py"}]}