__init__.py 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. """The Jupyter notebook format
  2. Use this module to read or write notebook files as particular nbformat versions.
  3. """
  4. # Copyright (c) IPython Development Team.
  5. # Distributed under the terms of the Modified BSD License.
  6. from __future__ import annotations
  7. from pathlib import Path
  8. from traitlets.log import get_logger
  9. from . import v1, v2, v3, v4
  10. from ._version import __version__, version_info
  11. from .sentinel import Sentinel
  12. __all__ = [
  13. "versions",
  14. "validate",
  15. "ValidationError",
  16. "convert",
  17. "from_dict",
  18. "NotebookNode",
  19. "current_nbformat",
  20. "current_nbformat_minor",
  21. "NBFormatError",
  22. "NO_CONVERT",
  23. "reads",
  24. "read",
  25. "writes",
  26. "write",
  27. "version_info",
  28. "__version__",
  29. "Sentinel",
  30. ]
  31. versions = {
  32. 1: v1,
  33. 2: v2,
  34. 3: v3,
  35. 4: v4,
  36. }
  37. from . import reader # noqa: E402
  38. from .converter import convert # noqa: E402
  39. from .notebooknode import NotebookNode, from_dict # noqa: E402
  40. from .v4 import nbformat as current_nbformat # noqa: E402
  41. from .v4 import nbformat_minor as current_nbformat_minor # noqa: E402
  42. from .validator import ValidationError, validate # noqa: E402
  43. class NBFormatError(ValueError):
  44. pass
  45. # no-conversion singleton
  46. NO_CONVERT = Sentinel(
  47. "NO_CONVERT",
  48. __name__,
  49. """Value to prevent nbformat to convert notebooks to most recent version.
  50. """,
  51. )
  52. def reads(s, as_version, capture_validation_error=None, **kwargs):
  53. """Read a notebook from a string and return the NotebookNode object as the given version.
  54. The string can contain a notebook of any version.
  55. The notebook will be returned `as_version`, converting, if necessary.
  56. Notebook format errors will be logged.
  57. Parameters
  58. ----------
  59. s : unicode
  60. The raw unicode string to read the notebook from.
  61. as_version : int
  62. The version of the notebook format to return.
  63. The notebook will be converted, if necessary.
  64. Pass nbformat.NO_CONVERT to prevent conversion.
  65. capture_validation_error : dict, optional
  66. If provided, a key of "ValidationError" with a
  67. value of the ValidationError instance will be added
  68. to the dictionary.
  69. Returns
  70. -------
  71. nb : NotebookNode
  72. The notebook that was read.
  73. """
  74. nb = reader.reads(s, **kwargs)
  75. if as_version is not NO_CONVERT:
  76. nb = convert(nb, as_version)
  77. try:
  78. validate(nb)
  79. except ValidationError as e:
  80. get_logger().error("Notebook JSON is invalid: %s", e)
  81. if isinstance(capture_validation_error, dict):
  82. capture_validation_error["ValidationError"] = e
  83. return nb
  84. def writes(nb, version=NO_CONVERT, capture_validation_error=None, **kwargs):
  85. """Write a notebook to a string in a given format in the given nbformat version.
  86. Any notebook format errors will be logged.
  87. Parameters
  88. ----------
  89. nb : NotebookNode
  90. The notebook to write.
  91. version : int, optional
  92. The nbformat version to write.
  93. If unspecified, or specified as nbformat.NO_CONVERT,
  94. the notebook's own version will be used and no conversion performed.
  95. capture_validation_error : dict, optional
  96. If provided, a key of "ValidationError" with a
  97. value of the ValidationError instance will be added
  98. to the dictionary.
  99. Returns
  100. -------
  101. s : unicode
  102. The notebook as a JSON string.
  103. """
  104. if version is not NO_CONVERT:
  105. nb = convert(nb, version)
  106. else:
  107. version, _ = reader.get_version(nb)
  108. try:
  109. validate(nb)
  110. except ValidationError as e:
  111. get_logger().error("Notebook JSON is invalid: %s", e)
  112. if isinstance(capture_validation_error, dict):
  113. capture_validation_error["ValidationError"] = e
  114. return versions[version].writes_json(nb, **kwargs)
  115. def read(fp, as_version, capture_validation_error=None, **kwargs):
  116. """Read a notebook from a file as a NotebookNode of the given version.
  117. The string can contain a notebook of any version.
  118. The notebook will be returned `as_version`, converting, if necessary.
  119. Notebook format errors will be logged.
  120. Parameters
  121. ----------
  122. fp : file or str
  123. A file-like object with a read method that returns unicode (use
  124. ``io.open()`` in Python 2), or a path to a file.
  125. as_version : int
  126. The version of the notebook format to return.
  127. The notebook will be converted, if necessary.
  128. Pass nbformat.NO_CONVERT to prevent conversion.
  129. capture_validation_error : dict, optional
  130. If provided, a key of "ValidationError" with a
  131. value of the ValidationError instance will be added
  132. to the dictionary.
  133. Returns
  134. -------
  135. nb : NotebookNode
  136. The notebook that was read.
  137. """
  138. try:
  139. buf = fp.read()
  140. except AttributeError:
  141. with open(fp, encoding="utf8") as f: # noqa: PTH123
  142. return reads(f.read(), as_version, capture_validation_error, **kwargs)
  143. return reads(buf, as_version, capture_validation_error, **kwargs)
  144. def write(nb, fp, version=NO_CONVERT, capture_validation_error=None, **kwargs):
  145. """Write a notebook to a file in a given nbformat version.
  146. The file-like object must accept unicode input.
  147. Parameters
  148. ----------
  149. nb : NotebookNode
  150. The notebook to write.
  151. fp : file or str
  152. Any file-like object with a write method that accepts unicode, or
  153. a path to write a file.
  154. version : int, optional
  155. The nbformat version to write.
  156. If nb is not this version, it will be converted.
  157. If unspecified, or specified as nbformat.NO_CONVERT,
  158. the notebook's own version will be used and no conversion performed.
  159. capture_validation_error : dict, optional
  160. If provided, a key of "ValidationError" with a
  161. value of the ValidationError instance will be added
  162. to the dictionary.
  163. """
  164. s = writes(nb, version, capture_validation_error, **kwargs)
  165. if isinstance(s, bytes):
  166. s = s.decode("utf8")
  167. try:
  168. fp.write(s)
  169. if not s.endswith("\n"):
  170. fp.write("\n")
  171. except AttributeError:
  172. with Path(fp).open("w", encoding="utf8") as f:
  173. f.write(s)
  174. if not s.endswith("\n"):
  175. f.write("\n")