Skip to content

Commit 7c4002b

Browse files
committed
Autogenerate ServerProcess documentation instead of duplicating it
Avoid duplication in documentation
1 parent fef3695 commit 7c4002b

File tree

3 files changed

+70
-223
lines changed

3 files changed

+70
-223
lines changed
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
from autodoc_traits import ConfigurableDocumenter, TraitDocumenter
2+
from sphinx.application import Sphinx
3+
from sphinx.ext.autodoc import SUPPRESS, ClassDocumenter, ObjectMember
4+
from sphinx.util.typing import ExtensionMetadata
5+
from traitlets import Undefined
6+
7+
8+
class ServerProcessConfigurableDocumenter(ConfigurableDocumenter):
9+
objtype = "serverprocessconfigurable"
10+
directivetype = "class"
11+
priority = 100
12+
13+
def get_object_members(self, want_all):
14+
"""
15+
Only document members in this class
16+
"""
17+
config_trait_members = self.object.class_traits(config=True).items()
18+
members = [ObjectMember(name, trait) for (name, trait) in config_trait_members]
19+
return False, members
20+
21+
def should_suppress_directive_header():
22+
return True
23+
24+
# Skip over autodoc_traits otherwise it'll prepend c.ServerProcess
25+
# to the annotation
26+
def add_directive_header(self, sig):
27+
print(f"{sig=}")
28+
self.options.annotation = SUPPRESS
29+
super(ClassDocumenter, self).add_directive_header(sig)
30+
31+
32+
class ServerProcessTraitDocumenter(TraitDocumenter):
33+
objtype = "serverprocesstrait"
34+
directivetype = "attribute"
35+
priority = 100 # AttributeDocumenter has 10
36+
member_order = 0 # AttributeDocumenter has 60
37+
38+
def add_directive_header(self, sig):
39+
default_value = self.object.default_value
40+
if default_value is Undefined:
41+
default_value = ""
42+
else:
43+
default_value = repr(default_value)
44+
45+
traitlets_type = self.object.__class__.__name__
46+
self.options.annotation = f"{traitlets_type}({default_value})"
47+
# Skip over autodoc_traits otherwise it'll prepend c.ServerProcess
48+
# to the annotation
49+
super(TraitDocumenter, self).add_directive_header(sig)
50+
51+
52+
def setup(app: Sphinx) -> ExtensionMetadata:
53+
app.setup_extension("autodoc_traits")
54+
app.add_autodocumenter(ServerProcessConfigurableDocumenter)
55+
app.add_autodocumenter(ServerProcessTraitDocumenter)
56+
return {
57+
"version": "0.1",
58+
"parallel_read_safe": True,
59+
"parallel_write_safe": True,
60+
}

docs/source/conf.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
# Configuration reference: https://www.sphinx-doc.org/en/master/usage/configuration.html
44
#
55
import datetime
6+
import sys
7+
from pathlib import Path
68

79
# -- Project information -----------------------------------------------------
810
# ref: https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
@@ -18,11 +20,17 @@
1820
# Add any Sphinx extension module names here, as strings. They can be extensions
1921
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
2022
#
23+
24+
# Custom extensions included this repo
25+
extensions_dir = Path(__file__).absolute().parent.parent / "extensions"
26+
sys.path.append(str(extensions_dir))
27+
2128
extensions = [
2229
"myst_parser",
2330
"sphinx_copybutton",
2431
"sphinxext.opengraph",
2532
"sphinxext.rediraffe",
33+
"serverprocess_documenter",
2634
]
2735
root_doc = "index"
2836
source_suffix = [".md"]

docs/source/server-process.md

Lines changed: 2 additions & 223 deletions
Original file line numberDiff line numberDiff line change
@@ -15,232 +15,11 @@ as separate packages.
1515
Server Processes are configured with a dictionary of key value
1616
pairs.
1717

18-
(server-process:cmd)=
18+
```{eval-rst}
1919
20-
### `command`
21-
22-
One of:
23-
24-
- A list of strings that is the command used to start the
25-
process. The following template strings will be replaced:
26-
27-
- `{port}` the port that the process should listen on. This will be 0 if it
28-
should use a Unix socket instead.
29-
- `{unix_socket}` the path at which the process should listen on a Unix
30-
socket. This will be an empty string if it should use a TCP port.
31-
- `{base_url}` the base URL of the notebook. For example, if the application
32-
needs to know its full path it can be constructed from
33-
`{base_url}/proxy/{port}`
34-
35-
- A callable that takes any {ref}`callable arguments <server-process:callable-arguments>`,
36-
and returns a list of strings that are used & treated same as above.
37-
38-
If the command is not specified or is an empty list, the server process is
39-
assumed to be started ahead of time and already available to be proxied to.
40-
41-
### `timeout`
42-
43-
Timeout in seconds for the process to become ready, default `5`.
44-
45-
A process is considered 'ready' when it can return a valid HTTP response on the
46-
port it is supposed to start at.
47-
48-
### `environment`
49-
50-
One of:
51-
52-
- A dictionary of strings that are passed in as the environment to
53-
the started process, in addition to the environment of the notebook
54-
process itself. The strings `{port}`, `{unix_socket}` and
55-
`{base_url}` will be replaced as for **command**.
56-
- A callable that takes any {ref}`callable arguments <server-process:callable-arguments>`,
57-
and returns a dictionary of strings that are used & treated same as above.
58-
59-
### `absolute_url`
60-
61-
_True_ if the URL as seen by the proxied application should be the full URL
62-
sent by the user. _False_ if the URL as seen by the proxied application should
63-
see the URL after the parts specific to jupyter-server-proxy have been stripped.
64-
65-
For example, with the following config:
66-
67-
```python
68-
c.ServerProxy.servers = {
69-
"test-server": {
70-
"command": ["python3", "-m", "http.server", "{port}"],
71-
"absolute_url": False
72-
}
73-
}
20+
.. autoserverprocessconfigurable:: jupyter_server_proxy.config.ServerProcess
7421
```
7522

76-
When a user requests `/test-server/some-url`, the proxied server will see it
77-
as a request for `/some-url` - the `/test-server` part is stripped out.
78-
79-
If `absolute_url` is set to `True` instead, the proxied server will see it
80-
as a request for `/test-server/some-url` instead - without any stripping.
81-
82-
This is very useful with applications that require a `base_url` to be set.
83-
84-
Defaults to _False_.
85-
86-
### `port`
87-
88-
Set the port that the service will listen on. The default is to
89-
automatically select an unused port.
90-
91-
(server-process:unix-socket)=
92-
93-
### `unix_socket`
94-
95-
This option uses a Unix socket on a filesystem path, instead of a TCP
96-
port. It can be passed as a string specifying the socket path, or _True_ for
97-
Jupyter Server Proxy to create a temporary directory to hold the socket,
98-
ensuring that only the user running Jupyter can connect to it.
99-
100-
If this is used, the `{unix_socket}` argument in the command template
101-
(see {ref}`server-process:cmd`) will be a filesystem path. The server should
102-
create a Unix socket bound to this path and listen for HTTP requests on it.
103-
The `port` configuration key will be ignored.
104-
105-
```{note}
106-
Proxying websockets over a Unix socket requires Tornado >= 6.3.
107-
```
108-
109-
### `mappath`
110-
111-
Map request paths to proxied paths.
112-
Either a dictionary of request paths to proxied paths,
113-
or a callable that takes parameter `path` and returns the proxied path.
114-
115-
### `launcher_entry`
116-
117-
A dictionary with options on if / how an entry in the classic Jupyter Notebook
118-
'New' dropdown or the JupyterLab launcher should be added. It can contain
119-
the following keys:
120-
121-
1. **enabled**
122-
Set to True (default) to make an entry in the launchers. Set to False to have no
123-
explicit entry.
124-
2. **icon_path**
125-
Full path to an svg icon that could be used with a launcher. Currently only used by the
126-
JupyterLab launcher, when category is "Notebook" (default) or "Console".
127-
3. **title**
128-
Title to be used for the launcher entry. Defaults to the name of the server if missing.
129-
4. **path_info**
130-
The trailing path that is appended to the user's server URL to access the proxied server.
131-
By default it is the name of the server followed by a trailing slash.
132-
5. **category**
133-
The category for the launcher item. Currently only used by the JupyterLab launcher.
134-
By default it is "Notebook".
135-
136-
### `new_browser_tab`
137-
138-
_JupyterLab only_ - _True_ (default) if the proxied server URL should be opened in a new browser tab.
139-
_False_ if the proxied server URL should be opened in a new JupyterLab tab.
140-
141-
If _False_, the proxied server needs to allow its pages to be rendered in an iframe. This
142-
is generally done by configuring the web server `X-Frame-Options` to `SAMEORIGIN`.
143-
For more information, refer to
144-
[MDN Web docs on X-Frame-Options](https://developer.mozilla.org/docs/Web/HTTP/Headers/X-Frame-Options).
145-
146-
Note that applications might use a different terminology to refer to frame options.
147-
For example, RStudio uses the term _frame origin_ and require the flag
148-
`--www-frame-origin=same` to allow rendering of its pages in an iframe.
149-
150-
### `request_headers_override`
151-
152-
One of:
153-
154-
- A dictionary of strings that are passed in as HTTP headers to the proxy
155-
request. The strings `{port}`, `{unix_socket}` and `{base_url}` will be
156-
replaced as for **command**.
157-
- A callable that takes any {ref}`callable arguments <server-process:callable-arguments>`,
158-
and returns a dictionary of strings that are used & treated same as above.
159-
160-
### `update_last_activity`
161-
162-
Whether to report activity from the proxy to Jupyter Server. If _True_, Jupyter Server
163-
will be notified of new activity. This is primarily used by JupyterHub for idle detection and culling.
164-
165-
Useful if you want to have a seperate way of determining activity through a
166-
proxied application.
167-
168-
Defaults to _True_.
169-
170-
(server-process:callable-arguments)=
171-
172-
### `raw_socket_proxy`
173-
174-
_True_ to proxy only websocket connections into raw stream connections.
175-
_False_ (default) if the proxied server speaks full HTTP.
176-
177-
If _True_, the proxied server is treated a raw TCP (or unix socket) server that
178-
does not use HTTP.
179-
In this mode, only websockets are handled, and messages are sent to the backend
180-
server as raw stream data. This is similar to running a
181-
[websockify](https://github.com/novnc/websockify) wrapper.
182-
All other HTTP requests return 405.
183-
184-
### Callable arguments
185-
186-
Certain config options accept callables, as documented above. This should return
187-
the same type of object that the option normally expects.
188-
When you use a callable this way, it can ask for any arguments it needs
189-
by simply declaring it - only arguments the callable asks for will be passed to it.
190-
191-
For example, with the following config:
192-
193-
```python
194-
def _cmd_callback():
195-
return ["some-command"]
196-
197-
server_config = {
198-
"command": _cmd_callback
199-
}
200-
```
201-
202-
No arguments will be passed to `_cmd_callback`, since it doesn't ask for any. However,
203-
with:
204-
205-
```python
206-
def _cmd_callback(port):
207-
return ["some-command", "--port=" + str(port)]
208-
209-
server_config = {
210-
"command": _cmd_callback
211-
}
212-
```
213-
214-
The `port` argument will be passed to the callable. This is a simple form of dependency
215-
injection that helps us add more parameters in the future without breaking backwards
216-
compatibility.
217-
218-
#### Available arguments
219-
220-
Unless otherwise documented for specific options, the arguments available for
221-
callables are:
222-
223-
1. **port**
224-
The TCP port on which the server should listen, or is listening.
225-
This is 0 if a Unix socket is used instead of TCP.
226-
2. **unix_socket**
227-
The path of a Unix socket on which the server should listen, or is listening.
228-
This is an empty string if a TCP socket is used.
229-
3. **base_url**
230-
The base URL of the notebook
231-
232-
If any of the returned strings, lists or dictionaries contain strings
233-
of form `{<argument-name>}`, they will be replaced with the value
234-
of the argument. For example, if your function is:
235-
236-
```python
237-
def _openrefine_cmd():
238-
return ["openrefine", "-p", "{port}"]
239-
```
240-
241-
The `{port}` will be replaced with the appropriate port before
242-
the command is started
243-
24423
## Specifying config via traitlets
24524

24625
[Traitlets](https://traitlets.readthedocs.io/) are the configuration

0 commit comments

Comments
 (0)