Show More
@@ -0,0 +1,100 b'' | |||||
|
1 | """API for reading notebooks. | |||
|
2 | ||||
|
3 | Authors: | |||
|
4 | ||||
|
5 | * Jonathan Frederic | |||
|
6 | """ | |||
|
7 | ||||
|
8 | #----------------------------------------------------------------------------- | |||
|
9 | # Copyright (C) 2013 The IPython Development Team | |||
|
10 | # | |||
|
11 | # Distributed under the terms of the BSD License. The full license is in | |||
|
12 | # the file COPYING, distributed as part of this software. | |||
|
13 | #----------------------------------------------------------------------------- | |||
|
14 | ||||
|
15 | #----------------------------------------------------------------------------- | |||
|
16 | # Imports | |||
|
17 | #----------------------------------------------------------------------------- | |||
|
18 | ||||
|
19 | import json | |||
|
20 | ||||
|
21 | versions = {} | |||
|
22 | for i in range(3): | |||
|
23 | versions[i+1] = __import__('v{0}'.format(i+1)) | |||
|
24 | ||||
|
25 | #----------------------------------------------------------------------------- | |||
|
26 | # Code | |||
|
27 | #----------------------------------------------------------------------------- | |||
|
28 | ||||
|
29 | class NotJSONError(ValueError): | |||
|
30 | pass | |||
|
31 | ||||
|
32 | def parse_json(s, **kwargs): | |||
|
33 | """Parse a JSON string into a dict.""" | |||
|
34 | try: | |||
|
35 | nb_dict = json.loads(s, **kwargs) | |||
|
36 | except ValueError: | |||
|
37 | raise NotJSONError("Notebook does not appear to be JSON: %r" % s[:16]) | |||
|
38 | return nb_dict | |||
|
39 | ||||
|
40 | # High level API | |||
|
41 | ||||
|
42 | def get_version(nb): | |||
|
43 | """Get the version of a notebook. | |||
|
44 | ||||
|
45 | Parameters | |||
|
46 | ---------- | |||
|
47 | nb : dict | |||
|
48 | NotebookNode or dict containing notebook data. | |||
|
49 | ||||
|
50 | Returns | |||
|
51 | ------- | |||
|
52 | Tuple containing major (int) and minor (int) version numbers | |||
|
53 | """ | |||
|
54 | major = nb.get('nbformat', 1) | |||
|
55 | minor = nb.get('nbformat_minor', 0) | |||
|
56 | return (major, minor) | |||
|
57 | ||||
|
58 | ||||
|
59 | def reads(s, format='ipynb', **kwargs): | |||
|
60 | """Read a notebook from a 'ipynb' (json) string and return the | |||
|
61 | NotebookNode object. | |||
|
62 | ||||
|
63 | This function properly reads notebooks of any version. No version | |||
|
64 | conversion is performed. | |||
|
65 | ||||
|
66 | Parameters | |||
|
67 | ---------- | |||
|
68 | s : unicode | |||
|
69 | The raw unicode string to read the notebook from. | |||
|
70 | ||||
|
71 | Returns | |||
|
72 | ------- | |||
|
73 | nb : NotebookNode | |||
|
74 | The notebook that was read. | |||
|
75 | """ | |||
|
76 | nb_dict = parse_json(s, **kwargs) | |||
|
77 | (major, minor) = get_version(nb_dict) | |||
|
78 | if major in versions: | |||
|
79 | return versions[major].to_notebook_json(nb, minor=minor) | |||
|
80 | else: | |||
|
81 | raise NBFormatError('Unsupported nbformat version %s' % major) | |||
|
82 | ||||
|
83 | ||||
|
84 | def read(fp, **kwargs): | |||
|
85 | """Read a notebook from a file and return the NotebookNode object. | |||
|
86 | ||||
|
87 | This function properly reads notebooks of any version. No version | |||
|
88 | conversion is performed. | |||
|
89 | ||||
|
90 | Parameters | |||
|
91 | ---------- | |||
|
92 | fp : file | |||
|
93 | Any file-like object with a read method. | |||
|
94 | ||||
|
95 | Returns | |||
|
96 | ------- | |||
|
97 | nb : NotebookNode | |||
|
98 | The notebook that was read. | |||
|
99 | """ | |||
|
100 | return reads(fp.read(), format, **kwargs) |
@@ -6,7 +6,7 b' Authors:' | |||||
6 | """ |
|
6 | """ | |
7 |
|
7 | |||
8 | #----------------------------------------------------------------------------- |
|
8 | #----------------------------------------------------------------------------- | |
9 |
# Copyright (C) 20 |
|
9 | # Copyright (C) 2013 The IPython Development Team | |
10 | # |
|
10 | # | |
11 | # Distributed under the terms of the BSD License. The full license is in |
|
11 | # Distributed under the terms of the BSD License. The full license is in | |
12 | # the file COPYING, distributed as part of this software. |
|
12 | # the file COPYING, distributed as part of this software. | |
@@ -18,51 +18,56 b' Authors:' | |||||
18 |
|
18 | |||
19 | import re |
|
19 | import re | |
20 |
|
20 | |||
21 | import IPython.nbformat as nbformat |
|
21 | from .reader import get_version, versions | |
22 |
|
||||
23 | #----------------------------------------------------------------------------- |
|
|||
24 | # Constants |
|
|||
25 | #----------------------------------------------------------------------------- |
|
|||
26 |
|
||||
27 | # Get the convert modules for each major revision. |
|
|||
28 | VERSION_REGEX = re.compile("v[0-9]+") |
|
|||
29 | version_modules = {} |
|
|||
30 | for module in dir(nbformat): |
|
|||
31 | if VERSION_REGEX.match(module): |
|
|||
32 | version_modules[int(module[1:])] = eval('nbformat.' + module + '.convert') |
|
|||
33 |
|
||||
34 | # Get the number of minor versions in each major version and create an ordered |
|
|||
35 | # list. |
|
|||
36 | versions = [] |
|
|||
37 | for major in version_modules.keys().sort(): |
|
|||
38 | current_minor = 0 |
|
|||
39 | if hasattr(version_modules[major], 'nbformat_minor'): |
|
|||
40 | current_minor = version_modules[major].nbformat_minor |
|
|||
41 |
|
||||
42 | for minor in range(0, current_minor + 1): |
|
|||
43 | versions.append((major, minor)) |
|
|||
44 |
|
22 | |||
45 | #----------------------------------------------------------------------------- |
|
23 | #----------------------------------------------------------------------------- | |
46 | # Functions |
|
24 | # Functions | |
47 | #----------------------------------------------------------------------------- |
|
25 | #----------------------------------------------------------------------------- | |
48 |
|
26 | |||
49 |
def convert(nb, to_ |
|
27 | def convert(nb, to_version): | |
50 |
"""Convert a notebook node object to a specific version |
|
28 | """Convert a notebook node object to a specific version. Assumes that | |
|
29 | all the versions starting from 1 to the latest major X are implemented. | |||
|
30 | In other words, there should never be a case where v1 v2 v3 v5 exist without | |||
|
31 | a v4. Also assumes that all conversions can be made in one step increments | |||
|
32 | between major versions and ignores minor revisions. | |||
|
33 | ||||
|
34 | PARAMETERS: | |||
|
35 | ----------- | |||
|
36 | nb : NotebookNode | |||
|
37 | to_version : int | |||
|
38 | Major revision to convert the notebook to. Can either be an upgrade or | |||
|
39 | a downgrade. | |||
|
40 | """ | |||
51 |
|
41 | |||
52 | # Get input notebook version. |
|
42 | # Get input notebook version. | |
53 | major = nb.get('nbformat', 1) |
|
43 | (version, version_minor) = get_version(nb) | |
54 | minor = nb.get('nbformat_minor', 0) # v3+ |
|
44 | version_numbers = versions.keys() | |
55 |
|
45 | |||
56 | # Check if destination is current version, if so return contents |
|
46 | # Check if destination is current version, if so return contents | |
57 | if to_major == major and to_minor == minor: |
|
47 | if version == to_version: | |
58 | return nb |
|
48 | return nb | |
59 | elif (to_major, to_minor) in versions: |
|
|||
60 | index = versions.indexof((major, minor)) |
|
|||
61 |
|
49 | |||
62 | if to_major > major or (to_major == major and to_minor > minor): |
|
50 | # If the version exist, try to convert to it one step at a time. | |
63 | to_index = index + 1 |
|
51 | elif to_version in version_numbers: | |
|
52 | ||||
|
53 | # Get the the version that this recursion will convert to as a step | |||
|
54 | # closer to the final revision. Make sure the newer of the conversion | |||
|
55 | # functions is used to perform the conversion. | |||
|
56 | if to_version > version: | |||
|
57 | step_version = version + 1 | |||
|
58 | convert_function = versions[step_version].upgrade | |||
64 | else: |
|
59 | else: | |
65 |
|
|
60 | step_version = version - 1 | |
|
61 | convert_function = versions[version].downgrade | |||
|
62 | ||||
|
63 | # Convert and make sure version changed during conversion. | |||
|
64 | converted = convert_function(nb) #todo | |||
|
65 | if converted.get('nbformat', 1) == version: | |||
|
66 | raise Exception("Cannot convert notebook from v%d to v%d. Operation" \ | |||
|
67 | "failed silently." % (major, step_version)) | |||
66 |
|
68 | |||
|
69 | # Recuresively convert until target version is reached. | |||
|
70 | return convert(converted, to_version) | |||
67 | else: |
|
71 | else: | |
68 |
raise Exception("Cannot convert notebook to v%d |
|
72 | raise Exception("Cannot convert notebook to v%d because that " \ | |
|
73 | "version doesn't exist" % (to_version)) |
@@ -3,6 +3,7 b'' | |||||
3 | Authors: |
|
3 | Authors: | |
4 |
|
4 | |||
5 | * Brian Granger |
|
5 | * Brian Granger | |
|
6 | * Jonathan Frederic | |||
6 | """ |
|
7 | """ | |
7 |
|
8 | |||
8 | #----------------------------------------------------------------------------- |
|
9 | #----------------------------------------------------------------------------- | |
@@ -17,14 +18,10 b' Authors:' | |||||
17 | #----------------------------------------------------------------------------- |
|
18 | #----------------------------------------------------------------------------- | |
18 |
|
19 | |||
19 | from __future__ import print_function |
|
20 | from __future__ import print_function | |
20 | import json |
|
21 | ||
21 | from xml.etree import ElementTree as ET |
|
22 | from xml.etree import ElementTree as ET | |
22 | import re |
|
23 | import re | |
23 |
|
24 | |||
24 | from IPython.nbformat import v3 |
|
|||
25 | from IPython.nbformat import v2 |
|
|||
26 | from IPython.nbformat import v1 |
|
|||
27 |
|
||||
28 | from IPython.nbformat.v3 import ( |
|
25 | from IPython.nbformat.v3 import ( | |
29 | NotebookNode, |
|
26 | NotebookNode, | |
30 | new_code_cell, new_text_cell, new_notebook, new_output, new_worksheet, |
|
27 | new_code_cell, new_text_cell, new_notebook, new_output, new_worksheet, | |
@@ -32,6 +29,9 b' from IPython.nbformat.v3 import (' | |||||
32 | nbformat_minor, |
|
29 | nbformat_minor, | |
33 | ) |
|
30 | ) | |
34 |
|
31 | |||
|
32 | import reader | |||
|
33 | from .convert import convert | |||
|
34 | ||||
35 | #----------------------------------------------------------------------------- |
|
35 | #----------------------------------------------------------------------------- | |
36 | # Code |
|
36 | # Code | |
37 | #----------------------------------------------------------------------------- |
|
37 | #----------------------------------------------------------------------------- | |
@@ -43,20 +43,6 b' current_nbformat_minor = nbformat_minor' | |||||
43 | class NBFormatError(ValueError): |
|
43 | class NBFormatError(ValueError): | |
44 | pass |
|
44 | pass | |
45 |
|
45 | |||
46 | class NotJSONError(ValueError): |
|
|||
47 | pass |
|
|||
48 |
|
||||
49 |
|
||||
50 | def parse_json(s, **kwargs): |
|
|||
51 | """Parse a string into a (nbformat, dict) tuple.""" |
|
|||
52 | try: |
|
|||
53 | d = json.loads(s, **kwargs) |
|
|||
54 | except ValueError: |
|
|||
55 | raise NotJSONError("Notebook does not appear to be JSON: %r" % s[:16]) |
|
|||
56 | nbf = d.get('nbformat', 1) |
|
|||
57 | nbm = d.get('nbformat_minor', 0) |
|
|||
58 | return nbf, nbm, d |
|
|||
59 |
|
||||
60 |
|
46 | |||
61 | def parse_py(s, **kwargs): |
|
47 | def parse_py(s, **kwargs): | |
62 | """Parse a string into a (nbformat, string) tuple.""" |
|
48 | """Parse a string into a (nbformat, string) tuple.""" | |
@@ -76,39 +62,26 b' def parse_py(s, **kwargs):' | |||||
76 |
|
62 | |||
77 | def reads_json(s, **kwargs): |
|
63 | def reads_json(s, **kwargs): | |
78 | """Read a JSON notebook from a string and return the NotebookNode object.""" |
|
64 | """Read a JSON notebook from a string and return the NotebookNode object.""" | |
79 | nbf, minor, d = parse_json(s, **kwargs) |
|
65 | return convert(reader.reads(nb), current_nbformat) | |
80 | if nbf == 1: |
|
|||
81 | nb = v1.to_notebook_json(d, **kwargs) |
|
|||
82 | nb = v3.convert_to_this_nbformat(nb, orig_version=1) |
|
|||
83 | elif nbf == 2: |
|
|||
84 | nb = v2.to_notebook_json(d, **kwargs) |
|
|||
85 | nb = v3.convert_to_this_nbformat(nb, orig_version=2) |
|
|||
86 | elif nbf == 3: |
|
|||
87 | nb = v3.to_notebook_json(d, **kwargs) |
|
|||
88 | nb = v3.convert_to_this_nbformat(nb, orig_version=3, orig_minor=minor) |
|
|||
89 | else: |
|
|||
90 | raise NBFormatError('Unsupported JSON nbformat version %s (supported version: %i)' % (nbf, 3)) |
|
|||
91 | return nb |
|
|||
92 |
|
66 | |||
93 |
|
67 | |||
94 | def writes_json(nb, **kwargs): |
|
68 | def writes_json(nb, **kwargs): | |
95 |
return |
|
69 | return reader.versions[current_nbformat].writes_json(nb, **kwargs) | |
96 |
|
70 | |||
97 |
|
71 | |||
98 | def reads_py(s, **kwargs): |
|
72 | def reads_py(s, **kwargs): | |
99 | """Read a .py notebook from a string and return the NotebookNode object.""" |
|
73 | """Read a .py notebook from a string and return the NotebookNode object.""" | |
100 | nbf, nbm, s = parse_py(s, **kwargs) |
|
74 | nbf, nbm, s = parse_py(s, **kwargs) | |
101 | if nbf == 2: |
|
75 | if nbf == 2 or nbf == 3: | |
102 |
nb = |
|
76 | nb = reader.versions[nbf].to_notebook_py(s, **kwargs) | |
103 | elif nbf == 3: |
|
|||
104 | nb = v3.to_notebook_py(s, **kwargs) |
|
|||
105 | else: |
|
77 | else: | |
106 | raise NBFormatError('Unsupported PY nbformat version: %i' % nbf) |
|
78 | raise NBFormatError('Unsupported PY nbformat version: %i' % nbf) | |
107 | return nb |
|
79 | return nb | |
108 |
|
80 | |||
109 |
|
81 | |||
110 | def writes_py(nb, **kwargs): |
|
82 | def writes_py(nb, **kwargs): | |
111 | return v3.writes_py(nb, **kwargs) |
|
83 | # nbformat 3 is the latest format that supports py | |
|
84 | return reader.versions[3].writes_py(nb, **kwargs) | |||
112 |
|
85 | |||
113 |
|
86 | |||
114 | # High level API |
|
87 | # High level API |
@@ -20,5 +20,4 b' from .nbjson import reads as reads_json, writes as writes_json' | |||||
20 | from .nbjson import reads as read_json, writes as write_json |
|
20 | from .nbjson import reads as read_json, writes as write_json | |
21 | from .nbjson import to_notebook as to_notebook_json |
|
21 | from .nbjson import to_notebook as to_notebook_json | |
22 |
|
22 | |||
23 |
from .convert import |
|
23 | from .convert import downgrade, upgrade | |
24 |
|
@@ -11,6 +11,6 b'' | |||||
11 | # Code |
|
11 | # Code | |
12 | #----------------------------------------------------------------------------- |
|
12 | #----------------------------------------------------------------------------- | |
13 |
|
13 | |||
14 |
def |
|
14 | def upgrade(nb, orig_version=None): | |
15 | raise ValueError('Cannot convert to v1 notebook format') |
|
15 | raise ValueError('Cannot convert to v1 notebook format') | |
16 |
|
16 |
@@ -34,7 +34,7 b' from .nbpy import reads as reads_py, writes as writes_py' | |||||
34 | from .nbpy import reads as read_py, writes as write_py |
|
34 | from .nbpy import reads as read_py, writes as write_py | |
35 | from .nbpy import to_notebook as to_notebook_py |
|
35 | from .nbpy import to_notebook as to_notebook_py | |
36 |
|
36 | |||
37 |
from .convert import |
|
37 | from .convert import downgrade, upgrade | |
38 |
|
38 | |||
39 | #----------------------------------------------------------------------------- |
|
39 | #----------------------------------------------------------------------------- | |
40 | # Code |
|
40 | # Code |
@@ -3,6 +3,7 b'' | |||||
3 | Authors: |
|
3 | Authors: | |
4 |
|
4 | |||
5 | * Brian Granger |
|
5 | * Brian Granger | |
|
6 | * Jonathan Frederic | |||
6 | """ |
|
7 | """ | |
7 |
|
8 | |||
8 | #----------------------------------------------------------------------------- |
|
9 | #----------------------------------------------------------------------------- | |
@@ -24,7 +25,7 b' from .nbbase import (' | |||||
24 | # Code |
|
25 | # Code | |
25 | #----------------------------------------------------------------------------- |
|
26 | #----------------------------------------------------------------------------- | |
26 |
|
27 | |||
27 | def convert_to_this_nbformat(nb, orig_version=1): |
|
28 | def upgrade(nb, from_version=1): | |
28 | """Convert a notebook to the v2 format. |
|
29 | """Convert a notebook to the v2 format. | |
29 |
|
30 | |||
30 | Parameters |
|
31 | Parameters | |
@@ -48,3 +49,13 b' def convert_to_this_nbformat(nb, orig_version=1):' | |||||
48 | else: |
|
49 | else: | |
49 | raise ValueError('Cannot convert a notebook from v%s to v2' % orig_version) |
|
50 | raise ValueError('Cannot convert a notebook from v%s to v2' % orig_version) | |
50 |
|
51 | |||
|
52 | ||||
|
53 | def downgrade(nb): | |||
|
54 | """Convert a v2 notebook to v1. | |||
|
55 | ||||
|
56 | Parameters | |||
|
57 | ---------- | |||
|
58 | nb : NotebookNode | |||
|
59 | The Python representation of the notebook to convert. | |||
|
60 | """ | |||
|
61 | raise Exception("Downgrade from notebook v2 to v1 is not supported.") |
@@ -30,7 +30,7 b' from .nbpy import reads as reads_py, writes as writes_py' | |||||
30 | from .nbpy import reads as read_py, writes as write_py |
|
30 | from .nbpy import reads as read_py, writes as write_py | |
31 | from .nbpy import to_notebook as to_notebook_py |
|
31 | from .nbpy import to_notebook as to_notebook_py | |
32 |
|
32 | |||
33 |
from .convert import |
|
33 | from .convert import downgrade, upgrade | |
34 |
|
34 | |||
35 | #----------------------------------------------------------------------------- |
|
35 | #----------------------------------------------------------------------------- | |
36 | # Code |
|
36 | # Code |
@@ -3,6 +3,8 b'' | |||||
3 | Authors: |
|
3 | Authors: | |
4 |
|
4 | |||
5 | * Brian Granger |
|
5 | * Brian Granger | |
|
6 | * Min RK | |||
|
7 | * Jonathan Frederic | |||
6 | """ |
|
8 | """ | |
7 |
|
9 | |||
8 | #----------------------------------------------------------------------------- |
|
10 | #----------------------------------------------------------------------------- | |
@@ -27,33 +29,62 b' from IPython.nbformat import v2' | |||||
27 | # Code |
|
29 | # Code | |
28 | #----------------------------------------------------------------------------- |
|
30 | #----------------------------------------------------------------------------- | |
29 |
|
31 | |||
30 |
def |
|
32 | def upgrade(nb, from_version=2, from_minor=0): | |
31 |
"""Convert a notebook to |
|
33 | """Convert a notebook to v3. | |
32 |
|
34 | |||
33 | Parameters |
|
35 | Parameters | |
34 | ---------- |
|
36 | ---------- | |
35 | nb : NotebookNode |
|
37 | nb : NotebookNode | |
36 | The Python representation of the notebook to convert. |
|
38 | The Python representation of the notebook to convert. | |
37 |
|
|
39 | from_version : int | |
38 | The original version of the notebook to convert. |
|
40 | The original version of the notebook to convert. | |
39 |
|
|
41 | from_minor : int | |
40 | The original minor version of the notebook to convert (only relevant for v >= 3). |
|
42 | The original minor version of the notebook to convert (only relevant for v >= 3). | |
41 | """ |
|
43 | """ | |
42 |
if |
|
44 | if from_version == 2: | |
43 | nb = v2.convert_to_this_nbformat(nb) |
|
|||
44 | orig_version = 2 |
|
|||
45 | if orig_version == 2: |
|
|||
46 | # Mark the original nbformat so consumers know it has been converted. |
|
45 | # Mark the original nbformat so consumers know it has been converted. | |
47 | nb.nbformat = nbformat |
|
46 | nb.nbformat = nbformat | |
48 | nb.nbformat_minor = nbformat_minor |
|
47 | nb.nbformat_minor = nbformat_minor | |
49 |
|
48 | |||
50 | nb.orig_nbformat = 2 |
|
49 | nb.orig_nbformat = 2 | |
51 | return nb |
|
50 | return nb | |
52 |
elif |
|
51 | elif from_version == 3: | |
53 |
if |
|
52 | if from_minor != nbformat_minor: | |
54 |
nb.orig_nbformat_minor = |
|
53 | nb.orig_nbformat_minor = from_minor | |
55 | nb.nbformat_minor = nbformat_minor |
|
54 | nb.nbformat_minor = nbformat_minor | |
56 | return nb |
|
55 | return nb | |
57 | else: |
|
56 | else: | |
58 |
raise ValueError('Cannot convert a notebook from v%s to v3' |
|
57 | raise ValueError('Cannot convert a notebook directly from v%s to v3. ' \ | |
|
58 | 'Try using the IPython.nbformat.convert module.' % from_version) | |||
|
59 | ||||
59 |
|
60 | |||
|
61 | def heading_to_md(cell): | |||
|
62 | """turn heading cell into corresponding markdown""" | |||
|
63 | cell.cell_type = "markdown" | |||
|
64 | level = cell.pop('level', 1) | |||
|
65 | cell.source = '#'*level + ' ' + cell.source | |||
|
66 | ||||
|
67 | ||||
|
68 | def raw_to_md(cell): | |||
|
69 | """let raw passthrough as markdown""" | |||
|
70 | cell.cell_type = "markdown" | |||
|
71 | ||||
|
72 | ||||
|
73 | def downgrade(nb): | |||
|
74 | """Convert a v3 notebook to v2. | |||
|
75 | ||||
|
76 | Parameters | |||
|
77 | ---------- | |||
|
78 | nb : NotebookNode | |||
|
79 | The Python representation of the notebook to convert. | |||
|
80 | """ | |||
|
81 | if nb.nbformat != 3: | |||
|
82 | return nb | |||
|
83 | nb.nbformat = 2 | |||
|
84 | for ws in nb.worksheets: | |||
|
85 | for cell in ws.cells: | |||
|
86 | if cell.cell_type == 'heading': | |||
|
87 | heading_to_md(cell) | |||
|
88 | elif cell.cell_type == 'raw': | |||
|
89 | raw_to_md(cell) | |||
|
90 | return nb No newline at end of file |
General Comments 0
You need to be logged in to leave comments.
Login now