first commit

This commit is contained in:
Ayxan
2022-05-23 00:16:32 +04:00
commit d660f2a4ca
24786 changed files with 4428337 additions and 0 deletions

View File

@@ -0,0 +1,91 @@
"""The main API for the v2 notebook format.
Authors:
* Brian Granger
"""
# -----------------------------------------------------------------------------
# Copyright (C) 2008-2011 The IPython Development Team
#
# Distributed under the terms of the BSD License. The full license is in
# the file COPYING, distributed as part of this software.
# -----------------------------------------------------------------------------
# -----------------------------------------------------------------------------
# Imports
# -----------------------------------------------------------------------------
import os
from .convert import downgrade, upgrade
from .nbbase import (
NotebookNode,
new_author,
new_code_cell,
new_metadata,
new_notebook,
new_output,
new_text_cell,
new_worksheet,
)
from .nbjson import reads as read_json
from .nbjson import reads as reads_json
from .nbjson import to_notebook as to_notebook_json
from .nbjson import writes as write_json
from .nbjson import writes as writes_json
from .nbpy import reads as read_py
from .nbpy import reads as reads_py
from .nbpy import to_notebook as to_notebook_py
from .nbpy import writes as write_py
from .nbpy import writes as writes_py
# Implementation removed, vulnerable to DoS attacks
from .nbxml import reads as read_xml
from .nbxml import reads as reads_xml
from .nbxml import to_notebook as to_notebook_xml
# -----------------------------------------------------------------------------
# Code
# -----------------------------------------------------------------------------
nbformat = 2
nbformat_minor = 0
def parse_filename(fname):
"""Parse a notebook filename.
This function takes a notebook filename and returns the notebook
format (json/py) and the notebook name. This logic can be
summarized as follows:
* notebook.ipynb -> (notebook.ipynb, notebook, json)
* notebook.json -> (notebook.json, notebook, json)
* notebook.py -> (notebook.py, notebook, py)
* notebook -> (notebook.ipynb, notebook, json)
Parameters
----------
fname : unicode
The notebook filename. The filename can use a specific filename
extention (.ipynb, .json, .py) or none, in which case .ipynb will
be assumed.
Returns
-------
(fname, name, format) : (unicode, unicode, unicode)
The filename, notebook name and format.
"""
basename, ext = os.path.splitext(fname)
if ext == ".ipynb":
format = "json"
elif ext == ".json":
format = "json"
elif ext == ".py":
format = "py"
else:
basename = fname
fname = fname + ".ipynb"
format = "json"
return fname, basename, format

View File

@@ -0,0 +1,62 @@
"""Code for converting notebooks to and from the v2 format.
Authors:
* Brian Granger
* Jonathan Frederic
"""
# -----------------------------------------------------------------------------
# Copyright (C) 2008-2011 The IPython Development Team
#
# Distributed under the terms of the BSD License. The full license is in
# the file COPYING, distributed as part of this software.
# -----------------------------------------------------------------------------
# -----------------------------------------------------------------------------
# Imports
# -----------------------------------------------------------------------------
from .nbbase import new_code_cell, new_notebook, new_text_cell, new_worksheet
# -----------------------------------------------------------------------------
# Code
# -----------------------------------------------------------------------------
def upgrade(nb, from_version=1):
"""Convert a notebook to the v2 format.
Parameters
----------
nb : NotebookNode
The Python representation of the notebook to convert.
from_version : int
The version of the notebook to convert from.
"""
if from_version == 1:
newnb = new_notebook()
ws = new_worksheet()
for cell in nb.cells:
if cell.cell_type == "code":
newcell = new_code_cell(
input=cell.get("code"), prompt_number=cell.get("prompt_number")
)
elif cell.cell_type == "text":
newcell = new_text_cell("markdown", source=cell.get("text"))
ws.cells.append(newcell)
newnb.worksheets.append(ws)
return newnb
else:
raise ValueError("Cannot convert a notebook from v%s to v2" % from_version)
def downgrade(nb):
"""Convert a v2 notebook to v1.
Parameters
----------
nb : NotebookNode
The Python representation of the notebook to convert.
"""
raise Exception("Downgrade from notebook v2 to v1 is not supported.")

View File

@@ -0,0 +1,187 @@
"""The basic dict based notebook format.
The Python representation of a notebook is a nested structure of
dictionary subclasses that support attribute access.
The functions in this module are merely
helpers to build the structs in the right form.
Authors:
* Brian Granger
"""
# -----------------------------------------------------------------------------
# Copyright (C) 2008-2011 The IPython Development Team
#
# Distributed under the terms of the BSD License. The full license is in
# the file COPYING, distributed as part of this software.
# -----------------------------------------------------------------------------
# -----------------------------------------------------------------------------
# Imports
# -----------------------------------------------------------------------------
from .._struct import Struct
# -----------------------------------------------------------------------------
# Code
# -----------------------------------------------------------------------------
class NotebookNode(Struct):
pass
def from_dict(d):
if isinstance(d, dict):
newd = NotebookNode()
for k, v in d.items():
newd[k] = from_dict(v)
return newd
elif isinstance(d, (tuple, list)):
return [from_dict(i) for i in d]
else:
return d
def new_output(
output_type=None,
output_text=None,
output_png=None,
output_html=None,
output_svg=None,
output_latex=None,
output_json=None,
output_javascript=None,
output_jpeg=None,
prompt_number=None,
etype=None,
evalue=None,
traceback=None,
):
"""Create a new code cell with input and output"""
output = NotebookNode()
if output_type is not None:
output.output_type = str(output_type)
if output_type != "pyerr":
if output_text is not None:
output.text = str(output_text)
if output_png is not None:
output.png = bytes(output_png)
if output_jpeg is not None:
output.jpeg = bytes(output_jpeg)
if output_html is not None:
output.html = str(output_html)
if output_svg is not None:
output.svg = str(output_svg)
if output_latex is not None:
output.latex = str(output_latex)
if output_json is not None:
output.json = str(output_json)
if output_javascript is not None:
output.javascript = str(output_javascript)
if output_type == "pyout":
if prompt_number is not None:
output.prompt_number = int(prompt_number)
if output_type == "pyerr":
if etype is not None:
output.etype = str(etype)
if evalue is not None:
output.evalue = str(evalue)
if traceback is not None:
output.traceback = [str(frame) for frame in list(traceback)]
return output
def new_code_cell(input=None, prompt_number=None, outputs=None, language="python", collapsed=False):
"""Create a new code cell with input and output"""
cell = NotebookNode()
cell.cell_type = "code"
if language is not None:
cell.language = str(language)
if input is not None:
cell.input = str(input)
if prompt_number is not None:
cell.prompt_number = int(prompt_number)
if outputs is None:
cell.outputs = []
else:
cell.outputs = outputs
if collapsed is not None:
cell.collapsed = bool(collapsed)
return cell
def new_text_cell(cell_type, source=None, rendered=None):
"""Create a new text cell."""
cell = NotebookNode()
if source is not None:
cell.source = str(source)
if rendered is not None:
cell.rendered = str(rendered)
cell.cell_type = cell_type
return cell
def new_worksheet(name=None, cells=None):
"""Create a worksheet by name with with a list of cells."""
ws = NotebookNode()
if name is not None:
ws.name = str(name)
if cells is None:
ws.cells = []
else:
ws.cells = list(cells)
return ws
def new_notebook(metadata=None, worksheets=None):
"""Create a notebook by name, id and a list of worksheets."""
nb = NotebookNode()
nb.nbformat = 2
if worksheets is None:
nb.worksheets = []
else:
nb.worksheets = list(worksheets)
if metadata is None:
nb.metadata = new_metadata()
else:
nb.metadata = NotebookNode(metadata)
return nb
def new_metadata(name=None, authors=None, license=None, created=None, modified=None, gistid=None):
"""Create a new metadata node."""
metadata = NotebookNode()
if name is not None:
metadata.name = str(name)
if authors is not None:
metadata.authors = list(authors)
if created is not None:
metadata.created = str(created)
if modified is not None:
metadata.modified = str(modified)
if license is not None:
metadata.license = str(license)
if gistid is not None:
metadata.gistid = str(gistid)
return metadata
def new_author(name=None, email=None, affiliation=None, url=None):
"""Create a new author."""
author = NotebookNode()
if name is not None:
author.name = str(name)
if email is not None:
author.email = str(email)
if affiliation is not None:
author.affiliation = str(affiliation)
if url is not None:
author.url = str(url)
return author

View File

@@ -0,0 +1,72 @@
"""Read and write notebooks in JSON format.
Authors:
* Brian Granger
"""
# -----------------------------------------------------------------------------
# Copyright (C) 2008-2011 The IPython Development Team
#
# Distributed under the terms of the BSD License. The full license is in
# the file COPYING, distributed as part of this software.
# -----------------------------------------------------------------------------
# -----------------------------------------------------------------------------
# Imports
# -----------------------------------------------------------------------------
import copy
import json
from .nbbase import from_dict
from .rwbase import (
NotebookReader,
NotebookWriter,
rejoin_lines,
restore_bytes,
split_lines,
)
# -----------------------------------------------------------------------------
# Code
# -----------------------------------------------------------------------------
class BytesEncoder(json.JSONEncoder):
"""A JSON encoder that accepts b64 (and other *ascii*) bytestrings."""
def default(self, obj):
if isinstance(obj, bytes):
return obj.decode("ascii")
return json.JSONEncoder.default(self, obj)
class JSONReader(NotebookReader):
def reads(self, s, **kwargs):
nb = json.loads(s, **kwargs)
nb = self.to_notebook(nb, **kwargs)
return nb
def to_notebook(self, d, **kwargs):
return restore_bytes(rejoin_lines(from_dict(d)))
class JSONWriter(NotebookWriter):
def writes(self, nb, **kwargs):
kwargs["cls"] = BytesEncoder
kwargs["indent"] = 1
kwargs["sort_keys"] = True
if kwargs.pop("split_lines", True):
nb = split_lines(copy.deepcopy(nb))
return json.dumps(nb, **kwargs)
_reader = JSONReader()
_writer = JSONWriter()
reads = _reader.reads
read = _reader.read
to_notebook = _reader.to_notebook
write = _writer.write
writes = _writer.writes

View File

@@ -0,0 +1,151 @@
"""Read and write notebooks as regular .py files.
Authors:
* Brian Granger
"""
# -----------------------------------------------------------------------------
# Copyright (C) 2008-2011 The IPython Development Team
#
# Distributed under the terms of the BSD License. The full license is in
# the file COPYING, distributed as part of this software.
# -----------------------------------------------------------------------------
# -----------------------------------------------------------------------------
# Imports
# -----------------------------------------------------------------------------
import re
from typing import List
from .nbbase import new_code_cell, new_notebook, new_text_cell, new_worksheet
from .rwbase import NotebookReader, NotebookWriter
# -----------------------------------------------------------------------------
# Code
# -----------------------------------------------------------------------------
_encoding_declaration_re = re.compile(r"^#.*coding[:=]\s*([-\w.]+)")
class PyReaderError(Exception):
pass
class PyReader(NotebookReader):
def reads(self, s, **kwargs):
return self.to_notebook(s, **kwargs)
def to_notebook(self, s, **kwargs):
lines = s.splitlines()
cells = []
cell_lines: List[str] = []
state = "codecell"
for line in lines:
if line.startswith("# <nbformat>") or _encoding_declaration_re.match(line):
pass
elif line.startswith("# <codecell>"):
cell = self.new_cell(state, cell_lines)
if cell is not None:
cells.append(cell)
state = "codecell"
cell_lines = []
elif line.startswith("# <htmlcell>"):
cell = self.new_cell(state, cell_lines)
if cell is not None:
cells.append(cell)
state = "htmlcell"
cell_lines = []
elif line.startswith("# <markdowncell>"):
cell = self.new_cell(state, cell_lines)
if cell is not None:
cells.append(cell)
state = "markdowncell"
cell_lines = []
else:
cell_lines.append(line)
if cell_lines and state == "codecell":
cell = self.new_cell(state, cell_lines)
if cell is not None:
cells.append(cell)
ws = new_worksheet(cells=cells)
nb = new_notebook(worksheets=[ws])
return nb
def new_cell(self, state, lines):
if state == "codecell":
input = "\n".join(lines)
input = input.strip("\n")
if input:
return new_code_cell(input=input)
elif state == "htmlcell":
text = self._remove_comments(lines)
if text:
return new_text_cell("html", source=text)
elif state == "markdowncell":
text = self._remove_comments(lines)
if text:
return new_text_cell("markdown", source=text)
def _remove_comments(self, lines):
new_lines = []
for line in lines:
if line.startswith("#"):
new_lines.append(line[2:])
else:
new_lines.append(line)
text = "\n".join(new_lines)
text = text.strip("\n")
return text
def split_lines_into_blocks(self, lines):
if len(lines) == 1:
yield lines[0]
raise StopIteration()
import ast
source = "\n".join(lines)
code = ast.parse(source)
starts = [x.lineno - 1 for x in code.body]
for i in range(len(starts) - 1):
yield "\n".join(lines[starts[i] : starts[i + 1]]).strip("\n")
yield "\n".join(lines[starts[-1] :]).strip("\n")
class PyWriter(NotebookWriter):
def writes(self, nb, **kwargs):
lines = ["# -*- coding: utf-8 -*-"]
lines.extend(["# <nbformat>2</nbformat>", ""])
for ws in nb.worksheets:
for cell in ws.cells:
if cell.cell_type == "code":
input = cell.get("input")
if input is not None:
lines.extend(["# <codecell>", ""])
lines.extend(input.splitlines())
lines.append("")
elif cell.cell_type == "html":
input = cell.get("source")
if input is not None:
lines.extend(["# <htmlcell>", ""])
lines.extend(["# " + line for line in input.splitlines()])
lines.append("")
elif cell.cell_type == "markdown":
input = cell.get("source")
if input is not None:
lines.extend(["# <markdowncell>", ""])
lines.extend(["# " + line for line in input.splitlines()])
lines.append("")
lines.append("")
return str("\n".join(lines))
_reader = PyReader()
_writer = PyWriter()
reads = _reader.reads
read = _reader.read
to_notebook = _reader.to_notebook
write = _writer.write
writes = _writer.writes

View File

@@ -0,0 +1,30 @@
"""REMOVED: Read and write notebook files as XML.
"""
REMOVED_MSG = """\
Reading notebooks as XML has been removed to harden security and avoid
possible denial-of-service attacks.
The XML notebook format was deprecated before the Jupyter (previously IPython)
Notebook was ever released. We are not aware of anyone using it, so we have
removed it.
If you were using this code, and you need to continue using it, feel free to
fork an earlier version of the nbformat package and maintain it yourself.
The issue which prompted this removal is:
https://github.com/jupyter/nbformat/issues/132
"""
def reads(s, **kwargs):
raise Exception(REMOVED_MSG)
def read(fp, **kwargs):
raise Exception(REMOVED_MSG)
def to_notebook(root, **kwargs):
raise Exception(REMOVED_MSG)

View File

@@ -0,0 +1,164 @@
"""Base classes and utilities for readers and writers.
Authors:
* Brian Granger
"""
# -----------------------------------------------------------------------------
# Copyright (C) 2008-2011 The IPython Development Team
#
# Distributed under the terms of the BSD License. The full license is in
# the file COPYING, distributed as part of this software.
# -----------------------------------------------------------------------------
# -----------------------------------------------------------------------------
# Imports
# -----------------------------------------------------------------------------
from base64 import decodebytes, encodebytes
# -----------------------------------------------------------------------------
# Code
# -----------------------------------------------------------------------------
def restore_bytes(nb):
"""Restore bytes of image data from unicode-only formats.
Base64 encoding is handled elsewhere. Bytes objects in the notebook are
always b64-encoded. We DO NOT encode/decode around file formats.
"""
for ws in nb.worksheets:
for cell in ws.cells:
if cell.cell_type == "code":
for output in cell.outputs:
if "png" in output:
output.png = output.png.encode("ascii")
if "jpeg" in output:
output.jpeg = output.jpeg.encode("ascii")
return nb
# output keys that are likely to have multiline values
_multiline_outputs = ["text", "html", "svg", "latex", "javascript", "json"]
def rejoin_lines(nb):
"""rejoin multiline text into strings
For reversing effects of ``split_lines(nb)``.
This only rejoins lines that have been split, so if text objects were not split
they will pass through unchanged.
Used when reading JSON files that may have been passed through split_lines.
"""
for ws in nb.worksheets:
for cell in ws.cells:
if cell.cell_type == "code":
if "input" in cell and isinstance(cell.input, list):
cell.input = "\n".join(cell.input)
for output in cell.outputs:
for key in _multiline_outputs:
item = output.get(key, None)
if isinstance(item, list):
output[key] = "\n".join(item)
else: # text cell
for key in ["source", "rendered"]:
item = cell.get(key, None)
if isinstance(item, list):
cell[key] = "\n".join(item)
return nb
def split_lines(nb):
"""split likely multiline text into lists of strings
For file output more friendly to line-based VCS. ``rejoin_lines(nb)`` will
reverse the effects of ``split_lines(nb)``.
Used when writing JSON files.
"""
for ws in nb.worksheets:
for cell in ws.cells:
if cell.cell_type == "code":
if "input" in cell and isinstance(cell.input, str):
cell.input = cell.input.splitlines()
for output in cell.outputs:
for key in _multiline_outputs:
item = output.get(key, None)
if isinstance(item, str):
output[key] = item.splitlines()
else: # text cell
for key in ["source", "rendered"]:
item = cell.get(key, None)
if isinstance(item, str):
cell[key] = item.splitlines()
return nb
# b64 encode/decode are never actually used, because all bytes objects in
# the notebook are already b64-encoded, and we don't need/want to double-encode
def base64_decode(nb):
"""Restore all bytes objects in the notebook from base64-encoded strings.
Note: This is never used
"""
for ws in nb.worksheets:
for cell in ws.cells:
if cell.cell_type == "code":
for output in cell.outputs:
if "png" in output:
if isinstance(output.png, str):
output.png = output.png.encode("ascii")
output.png = decodebytes(output.png)
if "jpeg" in output:
if isinstance(output.jpeg, str):
output.jpeg = output.jpeg.encode("ascii")
output.jpeg = decodebytes(output.jpeg)
return nb
def base64_encode(nb):
"""Base64 encode all bytes objects in the notebook.
These will be b64-encoded unicode strings
Note: This is never used
"""
for ws in nb.worksheets:
for cell in ws.cells:
if cell.cell_type == "code":
for output in cell.outputs:
if "png" in output:
output.png = encodebytes(output.png).decode("ascii")
if "jpeg" in output:
output.jpeg = encodebytes(output.jpeg).decode("ascii")
return nb
class NotebookReader:
"""A class for reading notebooks."""
def reads(self, s, **kwargs):
"""Read a notebook from a string."""
raise NotImplementedError("loads must be implemented in a subclass")
def read(self, fp, **kwargs):
"""Read a notebook from a file like object"""
return self.read(fp.read(), **kwargs)
class NotebookWriter:
"""A class for writing notebooks."""
def writes(self, nb, **kwargs):
"""Write a notebook to a string."""
raise NotImplementedError("loads must be implemented in a subclass")
def write(self, nb, fp, **kwargs):
"""Write a notebook to a file like object"""
return fp.write(self.writes(nb, **kwargs))