I am trying to add a new tab in sphinxcontrib-httpexample like curl
, httpie
, python-request
. I have made the required changes and everything is working apart from the output format.
JSON file :
POST /plone/front-page/@aliases HTTP/1.1
Accept: application/json
Authorization: Basic YWRtaW46c2VjcmV0
Content-Type: application/json
{
"items": [
{
"path": "/new-alias"
},
{
"path": "/old-alias"
},
{
"path": "/final-alias"
}
]
}
Python Code (i will add it in this file):
def build_plone_javascript_command(request):
javascript_code = 'createAliasesMutation'
redir_input2 = ''
# Request body
data = maybe_str(request.data())
if data:
if is_json(request.headers.get('Content-Type', '')):
redir_input2 = json.dumps(data, indent=2, sort_keys=True,
separators=(',', ': '))
else:
redir_input2 = data
# Output string
output_string = f"{javascript_code}\n|\nconst aliasesData = {redir_input2};"
return output_string
The python function returns a formatted string and then places it within Sphinx CodeBlock.
Modified Sphinx CodeBlock:
from docutils import nodes
from docutils.parsers.rst import directives
from docutils.statemachine import StringList
from sphinx.directives.code import CodeBlock
from sphinxcontrib.httpexample import builders
from sphinxcontrib.httpexample import parsers
from sphinxcontrib.httpexample import utils
import os
import re
AVAILABLE_BUILDERS = {
'curl': (builders.build_curl_command, 'bash'),
'wget': (builders.build_wget_command, 'bash'),
'httpie': (builders.build_httpie_command, 'bash'),
'requests': (builders.build_requests_command, 'python'),
'python-requests': (builders.build_requests_command, 'python'),
'plone_javascript': (builders.build_plone_javascript_command, 'javascript'),
}
AVAILABLE_FIELDS = [
'query'
]
def choose_builders(arguments):
return [directives.choice(argument, AVAILABLE_BUILDERS)
for argument in (arguments or [])]
class HTTPExample(CodeBlock):
required_arguments = 0
optional_arguments = len(AVAILABLE_BUILDERS)
option_spec = utils.merge_dicts(CodeBlock.option_spec, {
'request': directives.unchanged,
'response': directives.unchanged,
})
def run(self):
config = self.state.document.settings.env.config
# Read enabled builders; Defaults to None
chosen_builders = choose_builders(self.arguments)
# Enable 'http' language for http part
self.arguments = ['http']
# process 'query' reST fields
if self.content:
raw = ('\r\n'.join(self.content)).encode('utf-8')
request = parsers.parse_request(raw)
params, _ = request.extract_fields('query')
params = [(p[1], p[2]) for p in params]
new_path = utils.add_url_params(request.path, params)
self.content[0] = ' '.join(
[request.command, new_path, request.request_version])
# split the request and optional response in the content.
# The separator is two empty lines followed by a line starting with
# 'HTTP/' or 'HTTP '
request_content = StringList()
request_content_no_fields = StringList()
response_content = None
emptylines_count = 0
in_response = False
is_field = r':({}) (.+): (.+)'.format('|'.join(AVAILABLE_FIELDS))
for i, line in enumerate(self.content):
source = self.content.source(i)
if in_response:
response_content.append(line, source)
else:
if emptylines_count >= 2 and \
(line.startswith('HTTP/') or line.startswith('HTTP ')):
in_response = True
response_content = StringList()
response_content.append(line, source)
elif line == '':
emptylines_count += 1
else:
request_content.extend(
StringList([''] * emptylines_count, source))
request_content.append(line, source)
if not re.match(is_field, line):
request_content_no_fields.extend(
StringList([''] * emptylines_count, source))
request_content_no_fields.append(line, source)
emptylines_count = 0
# Load optional external request
cwd = os.path.dirname(self.state.document.current_source)
if 'request' in self.options:
request = utils.resolve_path(self.options['request'], cwd)
with open(request) as fp:
request_content = request_content_no_fields = StringList(
list(map(str.rstrip, fp.readlines())), request)
# Load optional external response
if 'response' in self.options:
response = utils.resolve_path(self.options['response'], cwd)
with open(response) as fp:
response_content = StringList(
list(map(str.rstrip, fp.readlines())), response)
# reset the content to the request, stripped of the reST fields
self.content = request_content_no_fields
# Wrap and render main directive as 'http-example-http'
klass = 'http-example-http'
container = nodes.container('', classes=[klass])
container.append(nodes.caption('', 'http'))
container.extend(super(HTTPExample, self).run())
# Init result node list
result = [container]
# reset the content to just the request
self.content = request_content
# Append builder responses
if request_content_no_fields:
raw = ('\r\n'.join(request_content_no_fields)).encode('utf-8')
for name in chosen_builders:
request = parsers.parse_request(raw, config.httpexample_scheme)
builder_, language = AVAILABLE_BUILDERS[name]
name = 'JavaScript' if name == 'plone_javascript' else name
command = builder_(request)
content = StringList(
[command], request_content_no_fields.source(0))
options = self.options.copy()
options.pop('name', None)
options.pop('caption', None)
block = CodeBlock(
'code-block',
[language],
options,
content,
self.lineno,
self.content_offset,
self.block_text,
self.state,
self.state_machine
)
# Wrap and render main directive as 'http-example-{name}'
klass = 'http-example-{}'.format(name)
container = nodes.container('', classes=[klass])
container.append(nodes.caption('', name))
container.extend(block.run())
# Append to result nodes
result.append(container)
# Append optional response
if response_content:
options = self.options.copy()
options.pop('name', None)
options.pop('caption', None)
block = CodeBlock(
'code-block',
['http'],
options,
response_content,
self.lineno,
self.content_offset,
self.block_text,
self.state,
self.state_machine
)
# Wrap and render main directive as 'http-example-response'
klass = 'http-example-response'
container = nodes.container('', classes=[klass])
container.append(nodes.caption('', 'response'))
container.extend(block.run())
# Append to result nodes
result.append(container)
# Final wrap
container_node = nodes.container('', classes=['http-example'])
container_node.extend(result)
return [container_node]
Output :
createAliasesMutation | const aliasesData = { "items": [ { "datetime": "2022-05-05", "path": "/old-page", "redirect-to": "/front-page" }, { "datetime": "2022-05-05", "path": "/fizzbuzz", "redirect-to": "/front-page" } ] };
Desired Output (something like this):
createAliasesMutation
|
const aliasesData =
{
"items": [
{
"path": "/new-alias"
},
{
"path": "/old-alias"
},
{
"path": "/final-alias"
}
]
}
Literal HTML:
<pre id="codecell19"><span></span><span class="nx">createAliasesMutation</span>
<span class="o">|</span>
<span class="kd">const</span><span class="w"> </span><span class="nx">aliasesData</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="s2">"items"</span><span class="o">:</span><span class="w"> </span><span class="p">[</span>
<span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="s2">"datetime"</span><span class="o">:</span><span class="w"> </span><span class="s2">"2022-05-05"</span><span class="p">,</span>
<span class="w"> </span><span class="s2">"path"</span><span class="o">:</span><span class="w"> </span><span class="s2">"/old-page"</span><span class="p">,</span>
<span class="w"> </span><span class="s2">"redirect-to"</span><span class="o">:</span><span class="w"> </span><span class="s2">"/front-page"</span>
<span class="w"> </span><span class="p">},</span>
<span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="s2">"datetime"</span><span class="o">:</span><span class="w"> </span><span class="s2">"2022-05-05"</span><span class="p">,</span>
<span class="w"> </span><span class="s2">"path"</span><span class="o">:</span><span class="w"> </span><span class="s2">"/fizzbuzz"</span><span class="p">,</span>
<span class="w"> </span><span class="s2">"redirect-to"</span><span class="o">:</span><span class="w"> </span><span class="s2">"/front-page"</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="p">]</span>
<span class="p">};</span>
</pre>
I tried using .replace('\\n','\n')
from this stackoverflow issue but still didnt work.
Edit: I am posting this issue again since I didnt added all the details in my earlier post.
The problem is likely here:
.http-example div[class^='highlight'] pre {
white-space: normal;
}
I'm not sure why they added this, but the white-space
property being set to normal
collapses all white space (including newlines) into a single space. It is the default for most elements, but for pre
, the default is pre
, which is likely what's needed for your use case.