|
"""API for converting notebooks between versions.""" |
|
|
|
|
|
|
|
from __future__ import annotations |
|
|
|
from . import versions |
|
from .reader import get_version |
|
from .validator import ValidationError |
|
|
|
|
|
def convert(nb, to_version): |
|
"""Convert a notebook node object to a specific version. Assumes that |
|
all the versions starting from 1 to the latest major X are implemented. |
|
In other words, there should never be a case where v1 v2 v3 v5 exist without |
|
a v4. Also assumes that all conversions can be made in one step increments |
|
between major versions and ignores minor revisions. |
|
|
|
Parameters |
|
---------- |
|
nb : NotebookNode |
|
to_version : int |
|
Major revision to convert the notebook to. Can either be an upgrade or |
|
a downgrade. |
|
|
|
Raises |
|
------ |
|
ValueError |
|
Notebook failed to convert. |
|
ValueError |
|
The version specified is invalid or doesn't exist. |
|
ValidationError |
|
Conversion failed due to missing expected attributes. |
|
""" |
|
|
|
|
|
(version, version_minor) = get_version(nb) |
|
|
|
|
|
if version == to_version: |
|
return nb |
|
|
|
|
|
if to_version in versions: |
|
|
|
|
|
|
|
if to_version > version: |
|
step_version = version + 1 |
|
convert_function = versions[step_version].upgrade |
|
else: |
|
step_version = version - 1 |
|
convert_function = versions[version].downgrade |
|
|
|
try: |
|
|
|
converted = convert_function(nb) |
|
if converted.get("nbformat", 1) == version: |
|
msg = "Failed to convert notebook from v%d to v%d." % (version, step_version) |
|
raise ValueError(msg) |
|
except AttributeError as e: |
|
msg = f"Notebook could not be converted from version {version} to version {step_version} because it's missing a key: {e}" |
|
raise ValidationError(msg) from None |
|
|
|
|
|
return convert(converted, to_version) |
|
raise ValueError( |
|
"Cannot convert notebook to v%d because that version doesn't exist" % (to_version) |
|
) |
|
|