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

Fixed handling of non-executed cells in jupyter notebooks #123

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
4 changes: 2 additions & 2 deletions pweave/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,12 @@ def weave(file, doctype=None, informat=None, kernel="python3", plot=True,

doc.weave()

def tangle(file, informat = None):
def tangle(file, informat = None, kernel = "python3", output = None):
"""Tangles a noweb file i.e. extracts code from code chunks to a .py file

:param file: ``string`` the pweave document containing the code
"""
doc = Pweb(file, kernel = None, informat = informat)
doc = Pweb(file, kernel = kernel, informat = informat, output = output)
doc.tangle()


Expand Down
3 changes: 2 additions & 1 deletion pweave/formatters/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ class PwebFormatter(object):
"""Base class for all not-notebook formatters"""

def __init__(self, executed, *, kernel = "python3", language = "python",
kernel_spec = {},
mimetype = None, source = None, theme = None,
figdir = "figures", wd = "."):

Expand Down Expand Up @@ -212,7 +213,7 @@ def format_codechunks(self, chunk):
if chunk['echo']:
chunk["content"] = self.fix_linefeeds(chunk["content"])
result += '%(codestart)s%(content)s%(codeend)s' % chunk

if chunk['results'] != 'hidden':
stream_result = {"output_type" : "stream", "text" : ""}
other_result = ""
Expand Down
36 changes: 21 additions & 15 deletions pweave/formatters/jupyter_notebook.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,20 @@
class PwebNotebookFormatter(object):

def __init__(self, executed, *, kernel = "python3", language = "python",
kernel_spec = {},
mimetype = "text/markdown", source = None, theme = None,
figdir = None, wd = None):

self.notebook = {"metadata" : {
"kernel_info" : {
"name" : kernel
},
"language_info": {
# if language_info is defined, its name field is required.
"name": language
}
},
"nbformat": 4,
"nbformat_minor": 0,
"cells": [ ]
self.notebook = {"metadata" : {"kernel_info" : {"name" : kernel},
"language_info": {
# if language_info is defined,
# its name field is required.
"name": language
},
"kernelspec" : kernel_spec },
"nbformat": 4,
"nbformat_minor": 0,
"cells": [ ]
}

self.execution_count = 1
Expand Down Expand Up @@ -46,11 +45,17 @@ def format(self):
"source": chunk["content"],
}
)
if chunk["type"] == "code":
if chunk["type"] == "code" and chunk["echo"]:
if chunk["evaluate"]:
ec = self.execution_count
else:
ec = None


self.notebook["cells"].append(
{
"cell_type": "code",
"execution_count" : self.execution_count,
"execution_count" : ec,
"metadata": {
"collapsed": False,
"autoscroll": "auto",
Expand All @@ -60,7 +65,8 @@ def format(self):
"outputs" : chunk["result"]
}
)
self.execution_count +=1
if chunk['evaluate']:
self.execution_count +=1
self.notebook = nbformat.from_dict(self.notebook)

def getformatted(self):
Expand Down
28 changes: 26 additions & 2 deletions pweave/processors/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,25 @@ def _runcode(self, chunk):

# Add defaultoptions to parsed options
if chunk['type'] == 'code':


for key in chunk["options"].keys():
opt = chunk["options"][key]
if isinstance(opt,str):
procString = self.loadinline(opt)

# There is probably a more elegant solution
# This will only work with boolean values
if procString == 'True':
procVal = True
elif procString == 'False':
procVal = False
else:
procVal = procString

chunk["options"][key] = procVal


defaults = rcParams["chunk"]["defaultoptions"].copy()
defaults.update(chunk["options"])
chunk.update(defaults)
Expand Down Expand Up @@ -125,6 +144,7 @@ def _runcode(self, chunk):


if chunk['type'] == 'code':
chunk['content'] = self.loadinline(chunk['content'])
sys.stdout.write("Processing chunk %(number)s named %(name)s from line %(start_line)s\n" % chunk)

old_content = None
Expand All @@ -138,7 +158,7 @@ def _runcode(self, chunk):
self.pending_code = ""

if not chunk['evaluate']:
chunk['result'] = ''
chunk['result'] = []
return chunk

self.pre_run_hook(chunk)
Expand Down Expand Up @@ -246,7 +266,7 @@ def loadinline(self, content):
if not elem.startswith('<%'):
continue
if elem.startswith('<%='):
code_str = elem.replace('<%=', '').replace('%>', '').lstrip()
code_str = self.get_code_str(elem)
result = self.load_inline_string(code_str).strip()
splitted[i] = result
continue
Expand All @@ -256,6 +276,10 @@ def loadinline(self, content):
splitted[i] = result
return ''.join(splitted)

def get_code_str(self,elem):
code_str = elem.replace('<%=', '').replace('%>', '').lstrip()
return code_str

def add_echo(self, code_str):
return 'print(%s),' % code_str

Expand Down
25 changes: 21 additions & 4 deletions pweave/pweb.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ class Pweb(object):

def __init__(self, source, doctype = None, *, informat = None, kernel = "python3",
output = None, figdir = 'figures', mimetype = None):

self.source = source
name, ext = os.path.splitext(os.path.basename(source))
self.basename = name
Expand All @@ -38,7 +39,8 @@ def __init__(self, source, doctype = None, *, informat = None, kernel = "python3
self.sink = None
self.kernel = None
self.language = None

self.kernel_spec = {}

if mimetype is None:
self.mimetype = MimeTypes.guess_mimetype(self.source)
else:
Expand Down Expand Up @@ -80,7 +82,10 @@ def setkernel(self, kernel):
"""Set the kernel for jupyter_client"""
self.kernel = kernel
if kernel is not None:
self.language = kernelspec.get_kernel_spec(kernel).language
ks = kernelspec.get_kernel_spec(kernel)
self.language = ks.language
self.kernel_spec = ks.to_dict()
self.kernel_spec['name'] = kernel

def getformat(self):
"""Get current format dictionary. See: http://mpastell.com/pweave/customizing.html"""
Expand Down Expand Up @@ -149,6 +154,7 @@ def setformat(self, doctype = None, Formatter = None):
self.formatter = Formatter([],
kernel = self.kernel,
language = self.language,
kernel_spec = self.kernel_spec,
mimetype = self.mimetype.type,
source = self.source,
theme = self.theme,
Expand Down Expand Up @@ -195,15 +201,26 @@ def weave(self):

def tangle(self):
"""Tangle the document"""

# Execute what code should be executed before writing
if self.kernel is not None:
self.run()
chunks = self.executed
else:
chunks = self.parsed

if self.output is None:
target = os.path.join(self.wd, self.basename + '.py')
code = [x for x in self.parsed if x['type'] == 'code']
else:
target = self.output
code = [x for x in chunks if x['type'] == 'code']
main = '\nif __name__ == "__main__":'
for x in code:
if 'main' in x['options'] and x['options']['main']:
x['content'] = x['content'].replace("\n", "\n ")
x['content'] = "".join([main, x['content']])
code = [x['content'] for x in code]

code = [x['content'] for x in code if x['options']['echo'] == True]
f = open(target, 'w')
f.write('\n'.join(code) + "\n")
f.close()
Expand Down
3 changes: 3 additions & 0 deletions pweave/readers.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ def getoptions(self, line):
splitted[0] = 'name = "%s"' % splitted[0]
optstring = ','.join(splitted)

optstring = optstring.replace("<%","'<%").replace("%>","%>'")
opt_scope = {}
exec("chunkoptions = dict(" + optstring + ")", opt_scope)
chunkoptions = opt_scope["chunkoptions"]
Expand Down Expand Up @@ -253,6 +254,8 @@ def getoptions(self, line):
splitted[0] = 'name = "%s"' % splitted[0]
optstring = ','.join(splitted)



opt_scope = {}
exec("chunkoptions = dict(" + optstring + ")", opt_scope)
chunkoptions = opt_scope["chunkoptions"]
Expand Down