Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

timings & timestamps for input cells #686

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 64 additions & 5 deletions src/nbsphinx.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import json
import os
import re
import datetime
import subprocess
import sys
from urllib.parse import unquote
Expand Down Expand Up @@ -122,6 +123,10 @@
{{ resources.codecell_lexer }}
{%- endif -%}
{{ insert_empty_lines(cell.source) }}
{%- if cell.metadata.ExecuteTime %}
:execution-start: {{ cell.metadata.ExecuteTime.start_time }}
:execution-end: {{ cell.metadata.ExecuteTime.end_time }}
{%- endif %}
{%- if cell.execution_count %}
:execution-count: {{ cell.execution_count }}
{%- endif %}
Expand Down Expand Up @@ -532,7 +537,7 @@
display: -webkit-flex;
display: flex;
align-items: flex-start;
margin: 0;
margin: 7px 0 0 0;
width: 100%%;
}
@media (max-width: %(nbsphinx_responsive_width)s) {
Expand Down Expand Up @@ -620,7 +625,7 @@
div.nbinput.container div.input_area {
border: 1px solid #e0e0e0;
border-radius: 2px;
/*background: #f5f5f5;*/
background: #f5f5f5;
}

/* override MathJax center alignment in output cells */
Expand Down Expand Up @@ -741,6 +746,27 @@
div.rendered_html tbody tr:hover {
background: rgba(66, 165, 245, 0.2);
}

/* Execution timestamps & timigs */
.timing {
margin-top: 7px 0 0 0;
border-top: 1px solid #CCC;
padding-top: 3px;
padding-left: 5px!important;
background-color: var(--pst-color-surface, transparent);
color: var(--pst-color-text-base, #777777);
}

.timing > p {
font-size: 70%%!important;
font-family: monospace;
margin-bottom: 0px;
padding-bottom: 3px;
}

div[class*="highlight-"] {
margin: 0px!important;
}
"""

CSS_STRING_READTHEDOCS = """
Expand Down Expand Up @@ -1152,8 +1178,32 @@ class FancyOutputNode(docutils.nodes.Element):

def _create_code_nodes(directive):
"""Create nodes for an input or output code cell."""

def get_timestamp(start, end):

time_format = '%Y-%m-%dT%H:%M:%S.%fZ'
t_start = datetime.datetime.strptime(start, time_format)
t_end = datetime.datetime.strptime(end, time_format)
duration = (t_end - t_start).total_seconds()
hours, remainder = divmod(duration, 3600)
minutes, seconds = divmod(remainder, 60)

duration_str = ''.join((
f'{hours:.0f}h' if hours else '',
f' {minutes:.0f}m' if minutes else '',
f' {seconds:.2f}s' if seconds > 1. else '',
f'{round(seconds % 1)}ms' if duration < 1. else '',
))

finished = t_end.strftime('%H:%M:%S %Y-%m-%d')

return f'executed in {duration_str}, finished {finished}'


directive.state.document['nbsphinx_include_css'] = True
execution_count = directive.options.get('execution-count')
execution_start = directive.options.get('execution-start')
execution_end = directive.options.get('execution-end')
config = directive.state.document.settings.env.config
if isinstance(directive, NbInput):
outer_classes = ['nbinput']
Expand Down Expand Up @@ -1183,17 +1233,23 @@ def _create_code_nodes(directive):
prompt_node = docutils.nodes.container(classes=['prompt', 'empty'])
# NB: Prompts are added manually in LaTeX output
outer_node += sphinx.addnodes.only('', prompt_node, expr='html')
inner_node = docutils.nodes.container(classes=inner_classes)

if isinstance(directive, NbInput):
text = '\n'.join(directive.content.data)
if directive.arguments:
language = directive.arguments[0]
else:
language = 'none'
inner_node = docutils.nodes.literal_block(
text, text, language=language, classes=inner_classes)
inner_node += docutils.nodes.literal_block(
text, text, language=language)
if config.nbsphinx_timings and execution_start:
timestamp = get_timestamp(execution_start, execution_end)
timestamp_par = docutils.nodes.paragraph(text = timestamp)
timing_div = docutils.nodes.container(
'', timestamp_par, classes=['timing'])
inner_node += timing_div
else:
inner_node = docutils.nodes.container(classes=inner_classes)
sphinx.util.nodes.nested_parse_with_titles(
directive.state, directive.content, inner_node)

Expand Down Expand Up @@ -1232,6 +1288,8 @@ class NbInput(rst.Directive):
optional_arguments = 1 # lexer name
final_argument_whitespace = False
option_spec = {
'execution-start': rst.directives.unchanged,
'execution-end': rst.directives.unchanged,
'execution-count': rst.directives.positive_int,
'empty-lines-before': rst.directives.nonnegative_int,
'empty-lines-after': rst.directives.nonnegative_int,
Expand Down Expand Up @@ -2384,6 +2442,7 @@ def setup(app):
app.add_config_value('nbsphinx_widgets_options', {}, rebuild='html')
app.add_config_value('nbsphinx_thumbnails', {}, rebuild='html')
app.add_config_value('nbsphinx_assume_equations', True, rebuild='env')
app.add_config_value('nbsphinx_timings', True, rebuild='html')

app.add_directive('nbinput', NbInput)
app.add_directive('nboutput', NbOutput)
Expand Down