diff --git a/IPython/testing/iptest.py b/IPython/testing/iptest.py index e90eafc..d40762e 100644 --- a/IPython/testing/iptest.py +++ b/IPython/testing/iptest.py @@ -147,7 +147,7 @@ have['zmq'] = test_for('zmq.pyzmq_version_info', min_zmq, callback=lambda x: x() test_group_names = ['parallel', 'kernel', 'kernel.inprocess', 'config', 'core', 'extensions', 'lib', 'terminal', 'testing', 'utils', - 'nbformat', 'qt', 'html', 'nbconvert' + 'qt', 'html', 'nbconvert' ] class TestSection(object): @@ -282,8 +282,6 @@ if not have['tornado']: sec.exclude('nbconvert.post_processors.serve') sec.exclude('nbconvert.post_processors.tests.test_serve') -# nbformat: -test_sections['nbformat'].requires('jsonschema') #----------------------------------------------------------------------------- # Functions and classes diff --git a/jupyter_nbformat/__init__.py b/jupyter_nbformat/__init__.py deleted file mode 100644 index 96f656d..0000000 --- a/jupyter_nbformat/__init__.py +++ /dev/null @@ -1,167 +0,0 @@ -"""The IPython notebook format - -Use this module to read or write notebook files as particular nbformat versions. -""" - -# Copyright (c) IPython Development Team. -# Distributed under the terms of the Modified BSD License. -import io -from IPython.utils import py3compat - -from IPython.utils.log import get_logger - -from . import v1 -from . import v2 -from . import v3 -from . import v4 -from .sentinel import Sentinel - -__all__ = ['versions', 'validate', 'ValidationError', 'convert', 'from_dict', - 'NotebookNode', 'current_nbformat', 'current_nbformat_minor', - 'NBFormatError', 'NO_CONVERT', 'reads', 'read', 'writes', 'write'] - -versions = { - 1: v1, - 2: v2, - 3: v3, - 4: v4, -} - -from .validator import validate, ValidationError -from .converter import convert -from . import reader -from .notebooknode import from_dict, NotebookNode - -from .v4 import ( - nbformat as current_nbformat, - nbformat_minor as current_nbformat_minor, -) - -class NBFormatError(ValueError): - pass - -# no-conversion singleton -NO_CONVERT = Sentinel('NO_CONVERT', __name__, - """Value to prevent nbformat to convert notebooks to most recent version. - """) - - -def reads(s, as_version, **kwargs): - """Read a notebook from a string and return the NotebookNode object as the given version. - - The string can contain a notebook of any version. - The notebook will be returned `as_version`, converting, if necessary. - - Notebook format errors will be logged. - - Parameters - ---------- - s : unicode - The raw unicode string to read the notebook from. - as_version : int - The version of the notebook format to return. - The notebook will be converted, if necessary. - Pass nbformat.NO_CONVERT to prevent conversion. - - Returns - ------- - nb : NotebookNode - The notebook that was read. - """ - nb = reader.reads(s, **kwargs) - if as_version is not NO_CONVERT: - nb = convert(nb, as_version) - try: - validate(nb) - except ValidationError as e: - get_logger().error("Notebook JSON is invalid: %s", e) - return nb - - -def writes(nb, version=NO_CONVERT, **kwargs): - """Write a notebook to a string in a given format in the given nbformat version. - - Any notebook format errors will be logged. - - Parameters - ---------- - nb : NotebookNode - The notebook to write. - version : int, optional - The nbformat version to write. - If unspecified, or specified as nbformat.NO_CONVERT, - the notebook's own version will be used and no conversion performed. - - Returns - ------- - s : unicode - The notebook as a JSON string. - """ - if version is not NO_CONVERT: - nb = convert(nb, version) - else: - version, _ = reader.get_version(nb) - try: - validate(nb) - except ValidationError as e: - get_logger().error("Notebook JSON is invalid: %s", e) - return versions[version].writes_json(nb, **kwargs) - - -def read(fp, as_version, **kwargs): - """Read a notebook from a file as a NotebookNode of the given version. - - The string can contain a notebook of any version. - The notebook will be returned `as_version`, converting, if necessary. - - Notebook format errors will be logged. - - Parameters - ---------- - fp : file or str - Any file-like object with a read method, or a path to a file. - as_version: int - The version of the notebook format to return. - The notebook will be converted, if necessary. - Pass nbformat.NO_CONVERT to prevent conversion. - - Returns - ------- - nb : NotebookNode - The notebook that was read. - """ - if isinstance(fp, py3compat.string_types): - with io.open(fp, encoding='utf-8') as f: - return read(f, as_version, **kwargs) - - return reads(fp.read(), as_version, **kwargs) - - -def write(nb, fp, version=NO_CONVERT, **kwargs): - """Write a notebook to a file in a given nbformat version. - - The file-like object must accept unicode input. - - Parameters - ---------- - nb : NotebookNode - The notebook to write. - fp : file or str - Any file-like object with a write method that accepts unicode, or - a path to write a file. - version : int, optional - The nbformat version to write. - If nb is not this version, it will be converted. - If unspecified, or specified as nbformat.NO_CONVERT, - the notebook's own version will be used and no conversion performed. - """ - if isinstance(fp, py3compat.string_types): - with io.open(fp, 'w', encoding='utf-8') as f: - return write(nb, f, version=version, **kwargs) - - s = writes(nb, version, **kwargs) - if isinstance(s, bytes): - s = s.decode('utf8') - fp.write(s) - if not s.endswith(u'\n'): - fp.write(u'\n') diff --git a/jupyter_nbformat/converter.py b/jupyter_nbformat/converter.py deleted file mode 100644 index a2ea892..0000000 --- a/jupyter_nbformat/converter.py +++ /dev/null @@ -1,54 +0,0 @@ -"""API for converting notebooks between versions.""" - -# Copyright (c) IPython Development Team. -# Distributed under the terms of the Modified BSD License. - -from . import versions -from .reader import get_version - - -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. - """ - - # Get input notebook version. - (version, version_minor) = get_version(nb) - - # Check if destination is target version, if so return contents - if version == to_version: - return nb - - # If the version exist, try to convert to it one step at a time. - elif to_version in versions: - - # Get the the version that this recursion will convert to as a step - # closer to the final revision. Make sure the newer of the conversion - # functions is used to perform the conversion. - if to_version > version: - step_version = version + 1 - convert_function = versions[step_version].upgrade - else: - step_version = version - 1 - convert_function = versions[version].downgrade - - # Convert and make sure version changed during conversion. - converted = convert_function(nb) - if converted.get('nbformat', 1) == version: - raise ValueError("Failed to convert notebook from v%d to v%d." % (version, step_version)) - - # Recursively convert until target version is reached. - return convert(converted, to_version) - else: - raise ValueError("Cannot convert notebook to v%d because that " \ - "version doesn't exist" % (to_version)) diff --git a/jupyter_nbformat/current.py b/jupyter_nbformat/current.py deleted file mode 100644 index bf4adb7..0000000 --- a/jupyter_nbformat/current.py +++ /dev/null @@ -1,192 +0,0 @@ -"""Deprecated API for working with notebooks - -- use IPython.nbformat for read/write/validate public API -- use IPython.nbformat.vX directly for Python API for composing notebooks -""" - -# Copyright (c) IPython Development Team. -# Distributed under the terms of the Modified BSD License. - -from __future__ import print_function - -import re -import warnings - -warnings.warn("""IPython.nbformat.current is deprecated. - -- use IPython.nbformat for read/write/validate public API -- use IPython.nbformat.vX directly to composing notebooks of a particular version -""") - -from IPython.nbformat.v3 import ( - NotebookNode, - new_code_cell, new_text_cell, new_notebook, new_output, new_worksheet, - parse_filename, new_metadata, new_author, new_heading_cell, nbformat, - nbformat_minor, nbformat_schema, to_notebook_json, -) -from IPython.nbformat import v3 as _v_latest - -from .reader import reads as reader_reads -from . import versions -from .converter import convert -from .validator import validate, ValidationError - -from IPython.utils.log import get_logger - -__all__ = ['NotebookNode', 'new_code_cell', 'new_text_cell', 'new_notebook', -'new_output', 'new_worksheet', 'parse_filename', 'new_metadata', 'new_author', -'new_heading_cell', 'nbformat', 'nbformat_minor', 'nbformat_schema', -'to_notebook_json', 'convert', 'validate', 'NBFormatError', 'parse_py', -'reads_json', 'writes_json', 'reads_py', 'writes_py', 'reads', 'writes', 'read', -'write'] - -current_nbformat = nbformat -current_nbformat_minor = nbformat_minor -current_nbformat_module = _v_latest.__name__ - - -class NBFormatError(ValueError): - pass - - -def _warn_format(): - warnings.warn("""Non-JSON file support in nbformat is deprecated. - Use nbconvert to create files of other formats.""") - - -def parse_py(s, **kwargs): - """Parse a string into a (nbformat, string) tuple.""" - nbf = current_nbformat - nbm = current_nbformat_minor - - pattern = r'# (?P\d+[\.\d+]*)' - m = re.search(pattern,s) - if m is not None: - digits = m.group('nbformat').split('.') - nbf = int(digits[0]) - if len(digits) > 1: - nbm = int(digits[1]) - - return nbf, nbm, s - - -def reads_json(nbjson, **kwargs): - """DEPRECATED, use reads""" - warnings.warn("reads_json is deprecated, use reads") - return reads(nbjson) - -def writes_json(nb, **kwargs): - """DEPRECATED, use writes""" - warnings.warn("writes_json is deprecated, use writes") - return writes(nb, **kwargs) - -def reads_py(s, **kwargs): - """DEPRECATED: use nbconvert""" - _warn_format() - nbf, nbm, s = parse_py(s, **kwargs) - if nbf in (2, 3): - nb = versions[nbf].to_notebook_py(s, **kwargs) - else: - raise NBFormatError('Unsupported PY nbformat version: %i' % nbf) - return nb - -def writes_py(nb, **kwargs): - """DEPRECATED: use nbconvert""" - _warn_format() - return versions[3].writes_py(nb, **kwargs) - - -# High level API - - -def reads(s, format='DEPRECATED', version=current_nbformat, **kwargs): - """Read a notebook from a string and return the NotebookNode object. - - This function properly handles notebooks of any version. The notebook - returned will always be in the current version's format. - - Parameters - ---------- - s : unicode - The raw unicode string to read the notebook from. - - Returns - ------- - nb : NotebookNode - The notebook that was read. - """ - if format not in {'DEPRECATED', 'json'}: - _warn_format() - nb = reader_reads(s, **kwargs) - nb = convert(nb, version) - try: - validate(nb) - except ValidationError as e: - get_logger().error("Notebook JSON is invalid: %s", e) - return nb - - -def writes(nb, format='DEPRECATED', version=current_nbformat, **kwargs): - """Write a notebook to a string in a given format in the current nbformat version. - - This function always writes the notebook in the current nbformat version. - - Parameters - ---------- - nb : NotebookNode - The notebook to write. - version : int - The nbformat version to write. - Used for downgrading notebooks. - - Returns - ------- - s : unicode - The notebook string. - """ - if format not in {'DEPRECATED', 'json'}: - _warn_format() - nb = convert(nb, version) - try: - validate(nb) - except ValidationError as e: - get_logger().error("Notebook JSON is invalid: %s", e) - return versions[version].writes_json(nb, **kwargs) - - -def read(fp, format='DEPRECATED', **kwargs): - """Read a notebook from a file and return the NotebookNode object. - - This function properly handles notebooks of any version. The notebook - returned will always be in the current version's format. - - Parameters - ---------- - fp : file - Any file-like object with a read method. - - Returns - ------- - nb : NotebookNode - The notebook that was read. - """ - return reads(fp.read(), **kwargs) - - -def write(nb, fp, format='DEPRECATED', **kwargs): - """Write a notebook to a file in a given format in the current nbformat version. - - This function always writes the notebook in the current nbformat version. - - Parameters - ---------- - nb : NotebookNode - The notebook to write. - fp : file - Any file-like object with a write method. - """ - s = writes(nb, **kwargs) - if isinstance(s, bytes): - s = s.decode('utf8') - return fp.write(s) - diff --git a/jupyter_nbformat/notebooknode.py b/jupyter_nbformat/notebooknode.py deleted file mode 100644 index 76e7141..0000000 --- a/jupyter_nbformat/notebooknode.py +++ /dev/null @@ -1,21 +0,0 @@ -"""NotebookNode - adding attribute access to dicts""" - -from IPython.utils.ipstruct import Struct - -class NotebookNode(Struct): - """A dict-like node with attribute-access""" - pass - -def from_dict(d): - """Convert dict to dict-like NotebookNode - - Recursively converts any dict in the container to a NotebookNode - """ - if isinstance(d, dict): - return NotebookNode({k:from_dict(v) for k,v in d.items()}) - elif isinstance(d, (tuple, list)): - return [from_dict(i) for i in d] - else: - return d - - diff --git a/jupyter_nbformat/reader.py b/jupyter_nbformat/reader.py deleted file mode 100644 index 20ddaef..0000000 --- a/jupyter_nbformat/reader.py +++ /dev/null @@ -1,82 +0,0 @@ -"""API for reading notebooks of different versions""" - -# Copyright (c) IPython Development Team. -# Distributed under the terms of the Modified BSD License. - -import json - -class NotJSONError(ValueError): - pass - -def parse_json(s, **kwargs): - """Parse a JSON string into a dict.""" - try: - nb_dict = json.loads(s, **kwargs) - except ValueError: - # Limit the error message to 80 characters. Display whatever JSON will fit. - raise NotJSONError(("Notebook does not appear to be JSON: %r" % s)[:77] + "...") - return nb_dict - -# High level API - -def get_version(nb): - """Get the version of a notebook. - - Parameters - ---------- - nb : dict - NotebookNode or dict containing notebook data. - - Returns - ------- - Tuple containing major (int) and minor (int) version numbers - """ - major = nb.get('nbformat', 1) - minor = nb.get('nbformat_minor', 0) - return (major, minor) - - -def reads(s, **kwargs): - """Read a notebook from a json string and return the - NotebookNode object. - - This function properly reads notebooks of any version. No version - conversion is performed. - - Parameters - ---------- - s : unicode - The raw unicode string to read the notebook from. - - Returns - ------- - nb : NotebookNode - The notebook that was read. - """ - from . import versions, NBFormatError - - nb_dict = parse_json(s, **kwargs) - (major, minor) = get_version(nb_dict) - if major in versions: - return versions[major].to_notebook_json(nb_dict, minor=minor) - else: - raise NBFormatError('Unsupported nbformat version %s' % major) - - -def read(fp, **kwargs): - """Read a notebook from a file and return the NotebookNode object. - - This function properly reads notebooks of any version. No version - conversion is performed. - - Parameters - ---------- - fp : file - Any file-like object with a read method. - - Returns - ------- - nb : NotebookNode - The notebook that was read. - """ - return reads(fp.read(), **kwargs) diff --git a/jupyter_nbformat/sentinel.py b/jupyter_nbformat/sentinel.py deleted file mode 100644 index dc57a25..0000000 --- a/jupyter_nbformat/sentinel.py +++ /dev/null @@ -1,17 +0,0 @@ -"""Sentinel class for constants with useful reprs""" - -# Copyright (c) IPython Development Team. -# Distributed under the terms of the Modified BSD License. - -class Sentinel(object): - - def __init__(self, name, module, docstring=None): - self.name = name - self.module = module - if docstring: - self.__doc__ = docstring - - - def __repr__(self): - return str(self.module)+'.'+self.name - diff --git a/jupyter_nbformat/sign.py b/jupyter_nbformat/sign.py deleted file mode 100644 index 04400b1..0000000 --- a/jupyter_nbformat/sign.py +++ /dev/null @@ -1,424 +0,0 @@ -"""Utilities for signing notebooks""" - -# Copyright (c) IPython Development Team. -# Distributed under the terms of the Modified BSD License. - -import base64 -from contextlib import contextmanager -from datetime import datetime -import hashlib -from hmac import HMAC -import io -import os - -try: - import sqlite3 -except ImportError: - try: - from pysqlite2 import dbapi2 as sqlite3 - except ImportError: - sqlite3 = None - -from IPython.utils.py3compat import unicode_type, cast_bytes -from IPython.utils.traitlets import Instance, Bytes, Enum, Any, Unicode, Bool, Integer -from IPython.config import LoggingConfigurable, MultipleInstanceError -from IPython.core.application import BaseIPythonApplication, base_flags - -from . import read, write, NO_CONVERT - -try: - # Python 3 - algorithms = hashlib.algorithms_guaranteed -except AttributeError: - algorithms = hashlib.algorithms - - -def yield_everything(obj): - """Yield every item in a container as bytes - - Allows any JSONable object to be passed to an HMAC digester - without having to serialize the whole thing. - """ - if isinstance(obj, dict): - for key in sorted(obj): - value = obj[key] - yield cast_bytes(key) - for b in yield_everything(value): - yield b - elif isinstance(obj, (list, tuple)): - for element in obj: - for b in yield_everything(element): - yield b - elif isinstance(obj, unicode_type): - yield obj.encode('utf8') - else: - yield unicode_type(obj).encode('utf8') - -def yield_code_cells(nb): - """Iterator that yields all cells in a notebook - - nbformat version independent - """ - if nb.nbformat >= 4: - for cell in nb['cells']: - if cell['cell_type'] == 'code': - yield cell - elif nb.nbformat == 3: - for ws in nb['worksheets']: - for cell in ws['cells']: - if cell['cell_type'] == 'code': - yield cell - -@contextmanager -def signature_removed(nb): - """Context manager for operating on a notebook with its signature removed - - Used for excluding the previous signature when computing a notebook's signature. - """ - save_signature = nb['metadata'].pop('signature', None) - try: - yield - finally: - if save_signature is not None: - nb['metadata']['signature'] = save_signature - - -class NotebookNotary(LoggingConfigurable): - """A class for computing and verifying notebook signatures.""" - - profile_dir = Instance("IPython.core.profiledir.ProfileDir", allow_none=True) - def _profile_dir_default(self): - from IPython.core.application import BaseIPythonApplication - app = None - try: - if BaseIPythonApplication.initialized(): - app = BaseIPythonApplication.instance() - except MultipleInstanceError: - pass - if app is None: - # create an app, without the global instance - app = BaseIPythonApplication() - app.initialize(argv=[]) - return app.profile_dir - - db_file = Unicode(config=True, - help="""The sqlite file in which to store notebook signatures. - By default, this will be in your IPython profile. - You can set it to ':memory:' to disable sqlite writing to the filesystem. - """) - def _db_file_default(self): - if self.profile_dir is None: - return ':memory:' - return os.path.join(self.profile_dir.security_dir, u'nbsignatures.db') - - # 64k entries ~ 12MB - cache_size = Integer(65535, config=True, - help="""The number of notebook signatures to cache. - When the number of signatures exceeds this value, - the oldest 25% of signatures will be culled. - """ - ) - db = Any() - def _db_default(self): - if sqlite3 is None: - self.log.warn("Missing SQLite3, all notebooks will be untrusted!") - return - kwargs = dict(detect_types=sqlite3.PARSE_DECLTYPES|sqlite3.PARSE_COLNAMES) - db = sqlite3.connect(self.db_file, **kwargs) - self.init_db(db) - return db - - def init_db(self, db): - db.execute(""" - CREATE TABLE IF NOT EXISTS nbsignatures - ( - id integer PRIMARY KEY AUTOINCREMENT, - algorithm text, - signature text, - path text, - last_seen timestamp - )""") - db.execute(""" - CREATE INDEX IF NOT EXISTS algosig ON nbsignatures(algorithm, signature) - """) - db.commit() - - algorithm = Enum(algorithms, default_value='sha256', config=True, - help="""The hashing algorithm used to sign notebooks.""" - ) - def _algorithm_changed(self, name, old, new): - self.digestmod = getattr(hashlib, self.algorithm) - - digestmod = Any() - def _digestmod_default(self): - return getattr(hashlib, self.algorithm) - - secret_file = Unicode(config=True, - help="""The file where the secret key is stored.""" - ) - def _secret_file_default(self): - if self.profile_dir is None: - return '' - return os.path.join(self.profile_dir.security_dir, 'notebook_secret') - - secret = Bytes(config=True, - help="""The secret key with which notebooks are signed.""" - ) - def _secret_default(self): - # note : this assumes an Application is running - if os.path.exists(self.secret_file): - with io.open(self.secret_file, 'rb') as f: - return f.read() - else: - secret = base64.encodestring(os.urandom(1024)) - self._write_secret_file(secret) - return secret - - def _write_secret_file(self, secret): - """write my secret to my secret_file""" - self.log.info("Writing notebook-signing key to %s", self.secret_file) - with io.open(self.secret_file, 'wb') as f: - f.write(secret) - try: - os.chmod(self.secret_file, 0o600) - except OSError: - self.log.warn( - "Could not set permissions on %s", - self.secret_file - ) - return secret - - def compute_signature(self, nb): - """Compute a notebook's signature - - by hashing the entire contents of the notebook via HMAC digest. - """ - hmac = HMAC(self.secret, digestmod=self.digestmod) - # don't include the previous hash in the content to hash - with signature_removed(nb): - # sign the whole thing - for b in yield_everything(nb): - hmac.update(b) - - return hmac.hexdigest() - - def check_signature(self, nb): - """Check a notebook's stored signature - - If a signature is stored in the notebook's metadata, - a new signature is computed and compared with the stored value. - - Returns True if the signature is found and matches, False otherwise. - - The following conditions must all be met for a notebook to be trusted: - - a signature is stored in the form 'scheme:hexdigest' - - the stored scheme matches the requested scheme - - the requested scheme is available from hashlib - - the computed hash from notebook_signature matches the stored hash - """ - if nb.nbformat < 3: - return False - if self.db is None: - return False - signature = self.compute_signature(nb) - r = self.db.execute("""SELECT id FROM nbsignatures WHERE - algorithm = ? AND - signature = ?; - """, (self.algorithm, signature)).fetchone() - if r is None: - return False - self.db.execute("""UPDATE nbsignatures SET last_seen = ? WHERE - algorithm = ? AND - signature = ?; - """, - (datetime.utcnow(), self.algorithm, signature), - ) - self.db.commit() - return True - - def sign(self, nb): - """Sign a notebook, indicating that its output is trusted on this machine - - Stores hash algorithm and hmac digest in a local database of trusted notebooks. - """ - if nb.nbformat < 3: - return - signature = self.compute_signature(nb) - self.store_signature(signature, nb) - - def store_signature(self, signature, nb): - if self.db is None: - return - self.db.execute("""INSERT OR IGNORE INTO nbsignatures - (algorithm, signature, last_seen) VALUES (?, ?, ?)""", - (self.algorithm, signature, datetime.utcnow()) - ) - self.db.execute("""UPDATE nbsignatures SET last_seen = ? WHERE - algorithm = ? AND - signature = ?; - """, - (datetime.utcnow(), self.algorithm, signature), - ) - self.db.commit() - n, = self.db.execute("SELECT Count(*) FROM nbsignatures").fetchone() - if n > self.cache_size: - self.cull_db() - - def unsign(self, nb): - """Ensure that a notebook is untrusted - - by removing its signature from the trusted database, if present. - """ - signature = self.compute_signature(nb) - self.db.execute("""DELETE FROM nbsignatures WHERE - algorithm = ? AND - signature = ?; - """, - (self.algorithm, signature) - ) - self.db.commit() - - def cull_db(self): - """Cull oldest 25% of the trusted signatures when the size limit is reached""" - self.db.execute("""DELETE FROM nbsignatures WHERE id IN ( - SELECT id FROM nbsignatures ORDER BY last_seen DESC LIMIT -1 OFFSET ? - ); - """, (max(int(0.75 * self.cache_size), 1),)) - - def mark_cells(self, nb, trusted): - """Mark cells as trusted if the notebook's signature can be verified - - Sets ``cell.metadata.trusted = True | False`` on all code cells, - depending on whether the stored signature can be verified. - - This function is the inverse of check_cells - """ - if nb.nbformat < 3: - return - - for cell in yield_code_cells(nb): - cell['metadata']['trusted'] = trusted - - def _check_cell(self, cell, nbformat_version): - """Do we trust an individual cell? - - Return True if: - - - cell is explicitly trusted - - cell has no potentially unsafe rich output - - If a cell has no output, or only simple print statements, - it will always be trusted. - """ - # explicitly trusted - if cell['metadata'].pop("trusted", False): - return True - - # explicitly safe output - if nbformat_version >= 4: - unsafe_output_types = ['execute_result', 'display_data'] - safe_keys = {"output_type", "execution_count", "metadata"} - else: # v3 - unsafe_output_types = ['pyout', 'display_data'] - safe_keys = {"output_type", "prompt_number", "metadata"} - - for output in cell['outputs']: - output_type = output['output_type'] - if output_type in unsafe_output_types: - # if there are any data keys not in the safe whitelist - output_keys = set(output) - if output_keys.difference(safe_keys): - return False - - return True - - def check_cells(self, nb): - """Return whether all code cells are trusted - - If there are no code cells, return True. - - This function is the inverse of mark_cells. - """ - if nb.nbformat < 3: - return False - trusted = True - for cell in yield_code_cells(nb): - # only distrust a cell if it actually has some output to distrust - if not self._check_cell(cell, nb.nbformat): - trusted = False - - return trusted - - -trust_flags = { - 'reset' : ( - {'TrustNotebookApp' : { 'reset' : True}}, - """Delete the trusted notebook cache. - All previously signed notebooks will become untrusted. - """ - ), -} -trust_flags.update(base_flags) -trust_flags.pop('init') - - -class TrustNotebookApp(BaseIPythonApplication): - - description="""Sign one or more IPython notebooks with your key, - to trust their dynamic (HTML, Javascript) output. - - Trusting a notebook only applies to the current IPython profile. - To trust a notebook for use with a profile other than default, - add `--profile [profile name]`. - - Otherwise, you will have to re-execute the notebook to see output. - """ - - examples = """ - ipython trust mynotebook.ipynb and_this_one.ipynb - ipython trust --profile myprofile mynotebook.ipynb - """ - - flags = trust_flags - - reset = Bool(False, config=True, - help="""If True, delete the trusted signature cache. - After reset, all previously signed notebooks will become untrusted. - """ - ) - - notary = Instance(NotebookNotary) - def _notary_default(self): - return NotebookNotary(parent=self, profile_dir=self.profile_dir) - - def sign_notebook(self, notebook_path): - if not os.path.exists(notebook_path): - self.log.error("Notebook missing: %s" % notebook_path) - self.exit(1) - with io.open(notebook_path, encoding='utf8') as f: - nb = read(f, NO_CONVERT) - if self.notary.check_signature(nb): - print("Notebook already signed: %s" % notebook_path) - else: - print("Signing notebook: %s" % notebook_path) - self.notary.sign(nb) - - def generate_new_key(self): - """Generate a new notebook signature key""" - print("Generating new notebook key: %s" % self.notary.secret_file) - self.notary._write_secret_file(os.urandom(1024)) - - def start(self): - if self.reset: - if os.path.exists(self.notary.db_file): - print("Removing trusted signature cache: %s" % self.notary.db_file) - os.remove(self.notary.db_file) - self.generate_new_key() - return - if not self.extra_args: - self.log.critical("Specify at least one notebook to sign.") - self.exit(1) - - for notebook_path in self.extra_args: - self.sign_notebook(notebook_path) - diff --git a/jupyter_nbformat/tests/__init__.py b/jupyter_nbformat/tests/__init__.py deleted file mode 100644 index e69de29..0000000 --- a/jupyter_nbformat/tests/__init__.py +++ /dev/null diff --git a/jupyter_nbformat/tests/base.py b/jupyter_nbformat/tests/base.py deleted file mode 100644 index 32a116c..0000000 --- a/jupyter_nbformat/tests/base.py +++ /dev/null @@ -1,33 +0,0 @@ -""" -Contains base test class for nbformat -""" -#----------------------------------------------------------------------------- -#Copyright (c) 2013, the IPython Development Team. -# -#Distributed under the terms of the Modified BSD License. -# -#The full license is in the file COPYING.txt, distributed with this software. -#----------------------------------------------------------------------------- - -#----------------------------------------------------------------------------- -# Imports -#----------------------------------------------------------------------------- - -import os -import unittest - -import IPython - -#----------------------------------------------------------------------------- -# Classes and functions -#----------------------------------------------------------------------------- - -class TestsBase(unittest.TestCase): - """Base tests class.""" - - def fopen(self, f, mode=u'r'): - return open(os.path.join(self._get_files_path(), f), mode) - - - def _get_files_path(self): - return os.path.dirname(__file__) diff --git a/jupyter_nbformat/tests/invalid.ipynb b/jupyter_nbformat/tests/invalid.ipynb deleted file mode 100644 index 23fc399..0000000 --- a/jupyter_nbformat/tests/invalid.ipynb +++ /dev/null @@ -1,306 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {} - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**Lorem ipsum** dolor sit amet, consectetur adipiscing elit. Nunc luctus bibendum felis dictum sodales. Ut suscipit, orci ut interdum imperdiet, purus ligula mollis *justo*, non malesuada nisl augue eget lorem. Donec bibendum, erat sit amet porttitor aliquam, urna lorem ornare libero, in vehicula diam diam ut ante. Nam non urna rhoncus, accumsan elit sit amet, mollis tellus. Vestibulum nec tellus metus. Vestibulum tempor, ligula et vehicula rhoncus, sapien turpis faucibus lorem, id dapibus turpis mauris ac orci. Sed volutpat vestibulum venenatis." - ] - }, - { - "cell_type": "heading", - "level": 2, - "metadata": {}, - "source": [ - "Printed Using Python" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "bad stream", - "text": [ - "hello\n" - ] - } - ], - "source": [ - "print(\"hello\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Pyout" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "text/html": [ - "\n", - "\n", - "HTML\n" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from IPython.display import HTML\n", - "HTML(\"\"\"\n", - "\n", - "HTML\n", - "\"\"\")" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "application/javascript": [ - "console.log(\"hi\");" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "%%javascript\n", - "console.log(\"hi\");" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Image" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "image/png": [ - "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\n" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from IPython.display import Image\n", - "Image(\"http://ipython.org/_static/IPy_header.png\")" - ] - } - ], - "metadata": {}, - "nbformat": 4, - "nbformat_minor": 0 -} \ No newline at end of file diff --git a/jupyter_nbformat/tests/test2.ipynb b/jupyter_nbformat/tests/test2.ipynb deleted file mode 100644 index 5a5d17c..0000000 --- a/jupyter_nbformat/tests/test2.ipynb +++ /dev/null @@ -1,419 +0,0 @@ -{ - "metadata": { - "name": "01_notebook_introduction" - }, - "nbformat": 2, - "worksheets": [ - { - "cells": [ - { - "cell_type": "markdown", - "source": [ - "# An introduction to the IPython notebook", - "", - "The IPython web notebook is a frontend that allows for new modes", - "of interaction with IPython: this web-based interface allows you to execute Python and IPython", - "commands in each input cell just like you would at the IPython terminal or Qt console, but you can", - "also save an entire session as a document in a file with the `.ipynb` extension.", - "", - "The document you are reading now is precisely an example of one such notebook, and we will show you", - "here how to best use this new interface.", - "", - "The first thing to understand is that a notebook consists of a sequence of 'cells' that can contain ", - "either text (such as this one) or code meant for execution (such as the next one):", - "", - "* Text cells can be written using [Markdown syntax](http://daringfireball.net/projects/markdown/syntax) ", - "(in a future release we will also provide support for reStructuredText and Sphinx integration, and we ", - "welcome help from interested contributors to make that happen).", - "", - "* Code cells take IPython input (i.e. Python code, `%magics`, `!system calls`, etc) like IPython at", - "the terminal or at the Qt Console. The only difference is that in order to execute a cell, you *must*", - "use `Shift-Enter`, as pressing `Enter` will add a new line of text to the cell. When you type ", - "`Shift-Enter`, the cell content is executed, output displayed and a new cell is created below. Try", - "it now by putting your cursor on the next cell and typing `Shift-Enter`:" - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "\"This is the new IPython notebook\"" - ], - "language": "python", - "outputs": [ - { - "output_type": "pyout", - "prompt_number": 1, - "text": [ - "'This is the new IPython notebook'" - ] - } - ], - "prompt_number": 1 - }, - { - "cell_type": "markdown", - "source": [ - "You can re-execute the same cell over and over as many times as you want. Simply put your", - "cursor in the cell again, edit at will, and type `Shift-Enter` to execute. ", - "", - "**Tip:** A cell can also be executed", - "*in-place*, where IPython executes its content but leaves the cursor in the same cell. This is done by", - "typing `Ctrl-Enter` instead, and is useful if you want to quickly run a command to check something ", - "before tping the real content you want to leave in the cell. For example, in the next cell, try issuing", - "several system commands in-place with `Ctrl-Enter`, such as `pwd` and then `ls`:" - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "ls" - ], - "language": "python", - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "00_notebook_tour.ipynb formatting.ipynb sympy_quantum_computing.ipynb", - "01_notebook_introduction.ipynb python-logo.svg trapezoid_rule.ipynb", - "display_protocol.ipynb sympy.ipynb" - ] - } - ], - "prompt_number": 2 - }, - { - "cell_type": "markdown", - "source": [ - "In a cell, you can type anything from a single python expression to an arbitrarily long amount of code ", - "(although for reasons of readability, you should probably limit this to a few dozen lines):" - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "def f(x):", - " \"\"\"My function", - " x : parameter\"\"\"", - " ", - " return x+1", - "", - "print \"f(3) = \", f(3)" - ], - "language": "python", - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "f(3) = 4" - ] - } - ], - "prompt_number": 3 - }, - { - "cell_type": "markdown", - "source": [ - "## User interface", - "", - "When you start a new notebook server with `ipython notebook`, your", - "browser should open into the *Dashboard*, a page listing all notebooks", - "available in the current directory as well as letting you create new", - "notebooks. In this page, you can also drag and drop existing `.py` files", - "over the file list to import them as notebooks (see the manual for ", - "[further details on how these files are ", - "interpreted](http://ipython.org/ipython-doc/stable/interactive/htmlnotebook.html)).", - "", - "Once you open an existing notebook (like this one) or create a new one,", - "you are in the main notebook interface, which consists of a main editing", - "area (where these cells are contained) as well as a collapsible left panel, ", - "a permanent header area at the top, and a pager that rises from the", - "bottom when needed and can be collapsed again." - ] - }, - { - "cell_type": "markdown", - "source": [ - "### Main editing area", - "", - "Here, you can move with the arrow keys or using the ", - "scroll bars. The cursor enters code cells immediately, but only selects", - "text (markdown) cells without entering in them; to enter a text cell,", - "use `Enter`, and `Shift-Enter` to exit it again (just like to execute a ", - "code cell)." - ] - }, - { - "cell_type": "markdown", - "source": [ - "### Left panel", - "", - "This panel contains a number of panes that can be", - "collapsed vertically by clicking on their title bar, and the whole panel", - "can also be collapsed by clicking on the vertical divider (note that you", - "can not *drag* the divider, for now you can only click on it).", - "", - "The *Notebook* section contains actions that pertain to the whole notebook,", - "such as downloading the current notebook either in its original format", - "or as a `.py` script, and printing it. When you click the `Print` button,", - "a new HTML page opens with a static copy of the notebook; you can then", - "use your web browser's mechanisms to save or print this file.", - "", - "The *Cell* section lets you manipulate individual cells, and the names should ", - "be fairly self-explanatory.", - "", - "The *Kernel* section lets you signal the kernel executing your code. ", - "`Interrupt` does the equivalent of hitting `Ctrl-C` at a terminal, and", - "`Restart` fully kills the kernel process and starts a fresh one. Obviously", - "this means that all your previous variables are destroyed, but it also", - "makes it easy to get a fresh kernel in which to re-execute a notebook, perhaps", - "after changing an extension module for which Python's `reload` mechanism", - "does not work. If you check the 'Kill kernel upon exit' box, when you ", - "close the page IPython will automatically shut down the running kernel;", - "otherwise the kernels won't close until you stop the whole ", - "", - "The *Help* section contains links to the documentation of some projects", - "closely related to IPython as well as the minimal keybindings you need to", - "know. But you should use `Ctrl-m h` (or click the `QuickHelp` button at", - "the top) and learn some of the other keybindings, as it will make your ", - "workflow much more fluid and efficient.", - "", - "The *Configuration* section at the bottom lets you change some values", - "related to the display of tooltips and the behavior of the tab completer." - ] - }, - { - "cell_type": "markdown", - "source": [ - "### Header bar", - "", - "The header area at the top allows you to rename an existing ", - "notebook and open up a short help tooltip. This area also indicates", - "with a red **Busy** mark on the right whenever the kernel is busy executing", - "code." - ] - }, - { - "cell_type": "markdown", - "source": [ - "### The pager at the bottom", - "", - "Whenever IPython needs to display additional ", - "information, such as when you type `somefunction?` in a cell, the notebook", - "opens a pane at the bottom where this information is shown. You can keep", - "this pager pane open for reference (it doesn't block input in the main area)", - "or dismiss it by clicking on its divider bar." - ] - }, - { - "cell_type": "markdown", - "source": [ - "### Tab completion and tooltips", - "", - "The notebook uses the same underlying machinery for tab completion that ", - "IPython uses at the terminal, but displays the information differently.", - "Whey you complete with the `Tab` key, IPython shows a drop list with all", - "available completions. If you type more characters while this list is open,", - "IPython automatically eliminates from the list options that don't match the", - "new characters; once there is only one option left you can hit `Tab` once", - "more (or `Enter`) to complete. You can also select the completion you", - "want with the arrow keys or the mouse, and then hit `Enter`.", - "", - "In addition, if you hit `Tab` inside of open parentheses, IPython will ", - "search for the docstring of the last object left of the parens and will", - "display it on a tooltip. For example, type `list(` and you will", - "see the docstring for the builtin `list` constructor:" - ] - }, - { - "cell_type": "code", - "collapsed": true, - "input": [ - "# Position your cursor after the ( and hit the Tab key:", - "list(" - ], - "language": "python", - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "## The frontend/kernel model", - "", - "The IPython notebook works on a client/server model where an *IPython kernel*", - "starts in a separate process and acts as a server to executes the code you type,", - "while the web browser provides acts as a client, providing a front end environment", - "for you to type. But one kernel is capable of simultaneously talking to more than", - "one client, and they do not all need to be of the same kind. All IPython frontends", - "are capable of communicating with a kernel, and any number of them can be active", - "at the same time. In addition to allowing you to have, for example, more than one", - "browser session active, this lets you connect clients with different user interface features.", - "", - "For example, you may want to connect a Qt console to your kernel and use it as a help", - "browser, calling `??` on objects in the Qt console (whose pager is more flexible than the", - "one in the notebook). You can start a new Qt console connected to your current kernel by ", - "using the `%qtconsole` magic, this will automatically detect the necessary connection", - "information.", - "", - "If you want to open one manually, or want to open a text console from a terminal, you can ", - "get your kernel's connection information with the `%connect_info` magic:" - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "%connect_info" - ], - "language": "python", - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "{", - " \"stdin_port\": 53970, ", - " \"ip\": \"127.0.0.1\", ", - " \"hb_port\": 53971, ", - " \"key\": \"30daac61-6b73-4bae-a7d9-9dca538794d5\", ", - " \"shell_port\": 53968, ", - " \"iopub_port\": 53969", - "}", - "", - "Paste the above JSON into a file, and connect with:", - " $> ipython --existing ", - "or, if you are local, you can connect with just:", - " $> ipython --existing kernel-dd85d1cc-c335-44f4-bed8-f1a2173a819a.json ", - "or even just:", - " $> ipython --existing ", - "if this is the most recent IPython session you have started." - ] - } - ], - "prompt_number": 4 - }, - { - "cell_type": "markdown", - "source": [ - "## The kernel's `raw_input` and `%debug`", - "", - "The one feature the notebook currently doesn't support as a client is the ability to send data to the kernel's", - "standard input socket. That is, if the kernel requires information to be typed interactively by calling the", - "builtin `raw_input` function, the notebook will be blocked. This happens for example if you run a script", - "that queries interactively for parameters, and very importantly, is how the interactive IPython debugger that ", - "activates when you type `%debug` works.", - "", - "So, in order to be able to use `%debug` or anything else that requires `raw_input`, you can either use a Qt ", - "console or a terminal console:", - "", - "- From the notebook, typing `%qtconsole` finds all the necessary connection data for you.", - "- From the terminal, first type `%connect_info` while still in the notebook, and then copy and paste the ", - "resulting information, using `qtconsole` or `console` depending on which type of client you want." - ] - }, - { - "cell_type": "markdown", - "source": [ - "## Display of complex objects", - "", - "As the 'tour' notebook shows, the IPython notebook has fairly sophisticated display capabilities. In addition", - "to the examples there, you can study the `display_protocol` notebook in this same examples folder, to ", - "learn how to customize arbitrary objects (in your own code or external libraries) to display in the notebook", - "in any way you want, including graphical forms or mathematical expressions." - ] - }, - { - "cell_type": "markdown", - "source": [ - "## Plotting support", - "", - "As we've explained already, the notebook is just another frontend talking to the same IPython kernel that", - "you're already familiar with, so the same options for plotting support apply.", - "", - "If you start the notebook with `--pylab`, you will get matplotlib's floating, interactive windows and you", - "can call the `display` function to paste figures into the notebook document. If you start it with ", - "`--pylab inline`, all plots will appear inline automatically. In this regard, the notebook works identically", - "to the Qt console.", - "", - "Note that if you start the notebook server with pylab support, *all* kernels are automatically started in", - "pylab mode and with the same choice of backend (i.e. floating windows or inline figures). But you can also", - "start the notebook server simply by typing `ipython notebook`, and then selectively turn on pylab support ", - "only for the notebooks you want by using the `%pylab` magic (see its docstring for details)." - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "%pylab inline", - "plot(rand(100))" - ], - "language": "python", - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "", - "Welcome to pylab, a matplotlib-based Python environment [backend: module://IPython.zmq.pylab.backend_inline].", - "For more information, type 'help(pylab)'." - ] - }, - { - "output_type": "pyout", - "prompt_number": 5, - "text": [ - "[]" - ] - }, - { - "output_type": "display_data", - "png": "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\n" - } - ], - "prompt_number": 5 - }, - { - "cell_type": "markdown", - "source": [ - "## Security", - "", - "By default the notebook only listens on localhost, so it does not expose your computer to attacks coming from", - "the internet. By default the notebook does not require any authentication, but you can configure it to", - "ask for a password before allowing access to the files. ", - "", - "Furthermore, you can require the notebook to encrypt all communications by using SSL and making all connections", - "using the https protocol instead of plain http. This is a good idea if you decide to run your notebook on", - "addresses that are visible from the internet. For further details on how to configure this, see the", - "[security section](http://ipython.org/ipython-doc/stable/interactive/htmlnotebook.html#security) of the ", - "manual.", - "", - "Finally, note that you can also run a notebook with the `--read-only` flag, which lets you provide access", - "to your notebook documents to others without letting them execute code (which can be useful to broadcast", - "a computation to colleagues or students, for example). The read-only flag behaves differently depending", - "on whether the server has a password or not:", - "", - "- Passwordless server: users directly see all notebooks in read-only mode.", - "- Password-protected server: users can see all notebooks in read-only mode, but a login button is available", - "and once a user authenticates, he or she obtains write/execute privileges.", - "", - "The first case above makes it easy to broadcast on the fly an existing notebook by simply starting a *second* ", - "notebook server in the same directory as the first, but in read-only mode. This can be done without having", - "to configure a password first (which requires calling a hashing function and editing a configuration file)." - ] - }, - { - "cell_type": "code", - "collapsed": true, - "input": [], - "language": "python", - "outputs": [] - } - ] - } - ] -} \ No newline at end of file diff --git a/jupyter_nbformat/tests/test3.ipynb b/jupyter_nbformat/tests/test3.ipynb deleted file mode 100644 index 4472ae6..0000000 --- a/jupyter_nbformat/tests/test3.ipynb +++ /dev/null @@ -1,150 +0,0 @@ -{ - "metadata": { - "name": "" - }, - "nbformat": 3, - "nbformat_minor": 0, - "worksheets": [ - { - "cells": [ - { - "cell_type": "heading", - "level": 1, - "metadata": {}, - "source": [ - "nbconvert latex test" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**Lorem ipsum** dolor sit amet, consectetur adipiscing elit. Nunc luctus bibendum felis dictum sodales. Ut suscipit, orci ut interdum imperdiet, purus ligula mollis *justo*, non malesuada nisl augue eget lorem. Donec bibendum, erat sit amet porttitor aliquam, urna lorem ornare libero, in vehicula diam diam ut ante. Nam non urna rhoncus, accumsan elit sit amet, mollis tellus. Vestibulum nec tellus metus. Vestibulum tempor, ligula et vehicula rhoncus, sapien turpis faucibus lorem, id dapibus turpis mauris ac orci. Sed volutpat vestibulum venenatis." - ] - }, - { - "cell_type": "heading", - "level": 2, - "metadata": {}, - "source": [ - "Printed Using Python" - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "print(\"hello\")" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "hello\n" - ] - } - ], - "prompt_number": 1 - }, - { - "cell_type": "heading", - "level": 2, - "metadata": {}, - "source": [ - "Pyout" - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "from IPython.display import HTML\n", - "HTML(\"\"\"\n", - "\n", - "HTML\n", - "\"\"\")" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "html": [ - "\n", - "\n", - "HTML\n" - ], - "metadata": {}, - "output_type": "pyout", - "prompt_number": 3, - "text": [ - "" - ] - } - ], - "prompt_number": 3 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "%%javascript\n", - "console.log(\"hi\");" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "javascript": [ - "console.log(\"hi\");" - ], - "metadata": {}, - "output_type": "display_data", - "text": [ - "" - ] - } - ], - "prompt_number": 7 - }, - { - "cell_type": "heading", - "level": 3, - "metadata": {}, - "source": [ - "Image" - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "from IPython.display import Image\n", - "Image(\"http://ipython.org/_static/IPy_header.png\")" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "png": "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\n", - "prompt_number": 6, - "text": [ - "" - ] - } - ], - "prompt_number": 6 - } - ], - "metadata": {} - } - ] -} \ No newline at end of file diff --git a/jupyter_nbformat/tests/test4.ipynb b/jupyter_nbformat/tests/test4.ipynb deleted file mode 100644 index fa14dd2..0000000 --- a/jupyter_nbformat/tests/test4.ipynb +++ /dev/null @@ -1,308 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# nbconvert latex test" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**Lorem ipsum** dolor sit amet, consectetur adipiscing elit. Nunc luctus bibendum felis dictum sodales. Ut suscipit, orci ut interdum imperdiet, purus ligula mollis *justo*, non malesuada nisl augue eget lorem. Donec bibendum, erat sit amet porttitor aliquam, urna lorem ornare libero, in vehicula diam diam ut ante. Nam non urna rhoncus, accumsan elit sit amet, mollis tellus. Vestibulum nec tellus metus. Vestibulum tempor, ligula et vehicula rhoncus, sapien turpis faucibus lorem, id dapibus turpis mauris ac orci. Sed volutpat vestibulum venenatis." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Printed Using Python" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "hello\n" - ] - } - ], - "source": [ - "print(\"hello\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Pyout" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "text/html": [ - "\n", - "\n", - "HTML\n" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from IPython.display import HTML\n", - "HTML(\"\"\"\n", - "\n", - "HTML\n", - "\"\"\")" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "application/javascript": [ - "console.log(\"hi\");" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "%%javascript\n", - "console.log(\"hi\");" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Image" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "image/png": [ - "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\n" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from IPython.display import Image\n", - "Image(\"http://ipython.org/_static/IPy_header.png\")" - ] - } - ], - "metadata": {}, - "nbformat": 4, - "nbformat_minor": 0 -} \ No newline at end of file diff --git a/jupyter_nbformat/tests/test4plus.ipynb b/jupyter_nbformat/tests/test4plus.ipynb deleted file mode 100644 index 38859b5..0000000 --- a/jupyter_nbformat/tests/test4plus.ipynb +++ /dev/null @@ -1,349 +0,0 @@ -{ - "extra": "future", - "cells": [ - { - "cell_type": "markdown", - "extra": 5, - "metadata": {}, - "source": [ - "# nbconvert latex test" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**Lorem ipsum** dolor sit amet, consectetur adipiscing elit. Nunc luctus bibendum felis dictum sodales. Ut suscipit, orci ut interdum imperdiet, purus ligula mollis *justo*, non malesuada nisl augue eget lorem. Donec bibendum, erat sit amet porttitor aliquam, urna lorem ornare libero, in vehicula diam diam ut ante. Nam non urna rhoncus, accumsan elit sit amet, mollis tellus. Vestibulum nec tellus metus. Vestibulum tempor, ligula et vehicula rhoncus, sapien turpis faucibus lorem, id dapibus turpis mauris ac orci. Sed volutpat vestibulum venenatis." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Printed Using Python" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "future": "yes", - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "name": "stdout", - "extra": "future", - "output_type": "stream", - "text": [ - "hello\n" - ] - } - ], - "source": [ - "print(\"hello\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Pyout" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "text/html": [ - "\n", - "\n", - "HTML\n" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from IPython.display import HTML\n", - "HTML(\"\"\"\n", - "\n", - "HTML\n", - "\"\"\")" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "application/javascript": [ - "console.log(\"hi\");" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "%%javascript\n", - "console.log(\"hi\");" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Image" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "image/png": [ - "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\n" - ], - "extra": "yes", - "text/plain": [ - "" - ] - }, - "execution_count": 6, - "metadata": {}, - "extra": "yes", - "output_type": "execute_result" - } - ], - "source": [ - "from IPython.display import Image\n", - "Image(\"http://ipython.org/_static/IPy_header.png\")" - ] - }, - { - "cell_type": "future cell", - "metadata": {}, - "key": "value" - }, - { - "cell_type": "code", - "execution_count": 99, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "hello\n" - ] - }, - { - "output_type": "future output", - "some key": [ - "some data" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "hello again\n" - ] - } - ], - "source": [ - "future_output()" - ] - } - ], - "metadata": {}, - "nbformat": 4, - "nbformat_minor": 99 -} \ No newline at end of file diff --git a/jupyter_nbformat/tests/test_api.py b/jupyter_nbformat/tests/test_api.py deleted file mode 100644 index f16f612..0000000 --- a/jupyter_nbformat/tests/test_api.py +++ /dev/null @@ -1,49 +0,0 @@ -"""Test the APIs at the top-level of nbformat""" - -# Copyright (c) IPython Development Team. -# Distributed under the terms of the Modified BSD License. - -import json -import os - -from .base import TestsBase - -from IPython.utils.tempdir import TemporaryDirectory -from ..reader import get_version -from IPython.nbformat import read, current_nbformat, writes, write - - -class TestAPI(TestsBase): - - def test_read(self): - """Can older notebooks be opened and automatically converted to the current - nbformat?""" - - # Open a version 2 notebook. - with self.fopen(u'test2.ipynb', 'r') as f: - nb = read(f, as_version=current_nbformat) - - # Check that the notebook was upgraded to the latest version automatically. - (major, minor) = get_version(nb) - self.assertEqual(major, current_nbformat) - - def test_write_downgrade_2(self): - """dowgrade a v3 notebook to v2""" - # Open a version 3 notebook. - with self.fopen(u'test3.ipynb', 'r') as f: - nb = read(f, as_version=3) - - jsons = writes(nb, version=2) - nb2 = json.loads(jsons) - (major, minor) = get_version(nb2) - self.assertEqual(major, 2) - - def test_read_write_path(self): - """read() and write() take filesystem paths""" - path = os.path.join(self._get_files_path(), u'test4.ipynb') - nb = read(path, as_version=4) - - with TemporaryDirectory() as td: - dest = os.path.join(td, 'echidna.ipynb') - write(nb, dest) - assert os.path.isfile(dest) diff --git a/jupyter_nbformat/tests/test_convert.py b/jupyter_nbformat/tests/test_convert.py deleted file mode 100644 index 06ca145..0000000 --- a/jupyter_nbformat/tests/test_convert.py +++ /dev/null @@ -1,57 +0,0 @@ -"""Tests for nbformat.convert""" - -# Copyright (c) IPython Development Team. -# Distributed under the terms of the Modified BSD License. - -from .base import TestsBase - -from ..converter import convert -from ..reader import read, get_version -from .. import current_nbformat - - -class TestConvert(TestsBase): - - def test_downgrade_3_2(self): - """Do notebook downgrades work?""" - - # Open a version 3 notebook and attempt to downgrade it to version 2. - with self.fopen(u'test3.ipynb', u'r') as f: - nb = read(f) - nb = convert(nb, 2) - - # Check if downgrade was successful. - (major, minor) = get_version(nb) - self.assertEqual(major, 2) - - - def test_upgrade_2_3(self): - """Do notebook upgrades work?""" - - # Open a version 2 notebook and attempt to upgrade it to version 3. - with self.fopen(u'test2.ipynb', u'r') as f: - nb = read(f) - nb = convert(nb, 3) - - # Check if upgrade was successful. - (major, minor) = get_version(nb) - self.assertEqual(major, 3) - - - def test_open_current(self): - """Can an old notebook be opened and converted to the current version - while remembering the original version of the notebook?""" - - # Open a version 2 notebook and attempt to upgrade it to the current version - # while remembering it's version information. - with self.fopen(u'test2.ipynb', u'r') as f: - nb = read(f) - (original_major, original_minor) = get_version(nb) - nb = convert(nb, current_nbformat) - - # Check if upgrade was successful. - (major, minor) = get_version(nb) - self.assertEqual(major, current_nbformat) - - # Check if the original major revision was remembered. - self.assertEqual(original_major, 2) diff --git a/jupyter_nbformat/tests/test_reader.py b/jupyter_nbformat/tests/test_reader.py deleted file mode 100644 index 9b5f9b8..0000000 --- a/jupyter_nbformat/tests/test_reader.py +++ /dev/null @@ -1,38 +0,0 @@ -""" -Contains tests class for reader.py -""" -#----------------------------------------------------------------------------- -# Copyright (C) 2013 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 .base import TestsBase - -from ..reader import read, get_version - -#----------------------------------------------------------------------------- -# Classes and functions -#----------------------------------------------------------------------------- - -class TestReader(TestsBase): - - def test_read(self): - """Can older notebooks be opened without modification?""" - - # Open a version 3 notebook. Make sure it is still version 3. - with self.fopen(u'test3.ipynb', u'r') as f: - nb = read(f) - (major, minor) = get_version(nb) - self.assertEqual(major, 3) - - # Open a version 2 notebook. Make sure it is still version 2. - with self.fopen(u'test2.ipynb', u'r') as f: - nb = read(f) - (major, minor) = get_version(nb) - self.assertEqual(major, 2) diff --git a/jupyter_nbformat/tests/test_sign.py b/jupyter_nbformat/tests/test_sign.py deleted file mode 100644 index b0009f9..0000000 --- a/jupyter_nbformat/tests/test_sign.py +++ /dev/null @@ -1,191 +0,0 @@ -"""Test Notebook signing""" - -# Copyright (c) IPython Development Team. -# Distributed under the terms of the Modified BSD License. - -import copy -import time - -from .base import TestsBase - -from IPython.nbformat import read, sign -from IPython.core.getipython import get_ipython - - -class TestNotary(TestsBase): - - def setUp(self): - self.notary = sign.NotebookNotary( - db_file=':memory:', - secret=b'secret', - profile_dir=get_ipython().profile_dir, - ) - with self.fopen(u'test3.ipynb', u'r') as f: - self.nb = read(f, as_version=4) - with self.fopen(u'test3.ipynb', u'r') as f: - self.nb3 = read(f, as_version=3) - - def test_algorithms(self): - last_sig = '' - for algo in sign.algorithms: - self.notary.algorithm = algo - sig = self.notary.compute_signature(self.nb) - self.assertNotEqual(last_sig, sig) - last_sig = sig - - def test_sign_same(self): - """Multiple signatures of the same notebook are the same""" - sig1 = self.notary.compute_signature(self.nb) - sig2 = self.notary.compute_signature(self.nb) - self.assertEqual(sig1, sig2) - - def test_change_secret(self): - """Changing the secret changes the signature""" - sig1 = self.notary.compute_signature(self.nb) - self.notary.secret = b'different' - sig2 = self.notary.compute_signature(self.nb) - self.assertNotEqual(sig1, sig2) - - def test_sign(self): - self.assertFalse(self.notary.check_signature(self.nb)) - self.notary.sign(self.nb) - self.assertTrue(self.notary.check_signature(self.nb)) - - def test_unsign(self): - self.notary.sign(self.nb) - self.assertTrue(self.notary.check_signature(self.nb)) - self.notary.unsign(self.nb) - self.assertFalse(self.notary.check_signature(self.nb)) - self.notary.unsign(self.nb) - self.assertFalse(self.notary.check_signature(self.nb)) - - def test_cull_db(self): - # this test has various sleeps of 2ms - # to ensure low resolution timestamps compare as expected - dt = 2e-3 - nbs = [ - copy.deepcopy(self.nb) for i in range(10) - ] - for row in self.notary.db.execute("SELECT * FROM nbsignatures"): - print(row) - self.notary.cache_size = 8 - for i, nb in enumerate(nbs[:8]): - nb.metadata.dirty = i - self.notary.sign(nb) - - for i, nb in enumerate(nbs[:8]): - time.sleep(dt) - self.assertTrue(self.notary.check_signature(nb), 'nb %i is trusted' % i) - - # signing the 9th triggers culling of first 3 - # (75% of 8 = 6, 9 - 6 = 3 culled) - self.notary.sign(nbs[8]) - self.assertFalse(self.notary.check_signature(nbs[0])) - self.assertFalse(self.notary.check_signature(nbs[1])) - self.assertFalse(self.notary.check_signature(nbs[2])) - self.assertTrue(self.notary.check_signature(nbs[3])) - # checking nb3 should keep it from being culled: - self.notary.sign(nbs[0]) - self.notary.sign(nbs[1]) - self.notary.sign(nbs[2]) - self.assertTrue(self.notary.check_signature(nbs[3])) - self.assertFalse(self.notary.check_signature(nbs[4])) - - def test_check_signature(self): - nb = self.nb - md = nb.metadata - notary = self.notary - check_signature = notary.check_signature - # no signature: - md.pop('signature', None) - self.assertFalse(check_signature(nb)) - # hash only, no algo - md.signature = notary.compute_signature(nb) - self.assertFalse(check_signature(nb)) - # proper signature, algo mismatch - notary.algorithm = 'sha224' - notary.sign(nb) - notary.algorithm = 'sha256' - self.assertFalse(check_signature(nb)) - # check correctly signed notebook - notary.sign(nb) - self.assertTrue(check_signature(nb)) - - def test_mark_cells_untrusted(self): - cells = self.nb.cells - self.notary.mark_cells(self.nb, False) - for cell in cells: - self.assertNotIn('trusted', cell) - if cell.cell_type == 'code': - self.assertIn('trusted', cell.metadata) - self.assertFalse(cell.metadata.trusted) - else: - self.assertNotIn('trusted', cell.metadata) - - def test_mark_cells_trusted(self): - cells = self.nb.cells - self.notary.mark_cells(self.nb, True) - for cell in cells: - self.assertNotIn('trusted', cell) - if cell.cell_type == 'code': - self.assertIn('trusted', cell.metadata) - self.assertTrue(cell.metadata.trusted) - else: - self.assertNotIn('trusted', cell.metadata) - - def test_check_cells(self): - nb = self.nb - self.notary.mark_cells(nb, True) - self.assertTrue(self.notary.check_cells(nb)) - for cell in nb.cells: - self.assertNotIn('trusted', cell) - self.notary.mark_cells(nb, False) - self.assertFalse(self.notary.check_cells(nb)) - for cell in nb.cells: - self.assertNotIn('trusted', cell) - - def test_trust_no_output(self): - nb = self.nb - self.notary.mark_cells(nb, False) - for cell in nb.cells: - if cell.cell_type == 'code': - cell.outputs = [] - self.assertTrue(self.notary.check_cells(nb)) - - def test_mark_cells_untrusted_v3(self): - nb = self.nb3 - cells = nb.worksheets[0].cells - self.notary.mark_cells(nb, False) - for cell in cells: - self.assertNotIn('trusted', cell) - if cell.cell_type == 'code': - self.assertIn('trusted', cell.metadata) - self.assertFalse(cell.metadata.trusted) - else: - self.assertNotIn('trusted', cell.metadata) - - def test_mark_cells_trusted_v3(self): - nb = self.nb3 - cells = nb.worksheets[0].cells - self.notary.mark_cells(nb, True) - for cell in cells: - self.assertNotIn('trusted', cell) - if cell.cell_type == 'code': - self.assertIn('trusted', cell.metadata) - self.assertTrue(cell.metadata.trusted) - else: - self.assertNotIn('trusted', cell.metadata) - - def test_check_cells_v3(self): - nb = self.nb3 - cells = nb.worksheets[0].cells - self.notary.mark_cells(nb, True) - self.assertTrue(self.notary.check_cells(nb)) - for cell in cells: - self.assertNotIn('trusted', cell) - self.notary.mark_cells(nb, False) - self.assertFalse(self.notary.check_cells(nb)) - for cell in cells: - self.assertNotIn('trusted', cell) - - diff --git a/jupyter_nbformat/tests/test_validator.py b/jupyter_nbformat/tests/test_validator.py deleted file mode 100644 index a084282..0000000 --- a/jupyter_nbformat/tests/test_validator.py +++ /dev/null @@ -1,58 +0,0 @@ -"""Test nbformat.validator""" - -# Copyright (c) IPython Development Team. -# Distributed under the terms of the Modified BSD License. - -import os - -from .base import TestsBase -from jsonschema import ValidationError -from IPython.nbformat import read -from ..validator import isvalid, validate - - -class TestValidator(TestsBase): - - def test_nb2(self): - """Test that a v2 notebook converted to current passes validation""" - with self.fopen(u'test2.ipynb', u'r') as f: - nb = read(f, as_version=4) - validate(nb) - self.assertEqual(isvalid(nb), True) - - def test_nb3(self): - """Test that a v3 notebook passes validation""" - with self.fopen(u'test3.ipynb', u'r') as f: - nb = read(f, as_version=4) - validate(nb) - self.assertEqual(isvalid(nb), True) - - def test_nb4(self): - """Test that a v4 notebook passes validation""" - with self.fopen(u'test4.ipynb', u'r') as f: - nb = read(f, as_version=4) - validate(nb) - self.assertEqual(isvalid(nb), True) - - def test_invalid(self): - """Test than an invalid notebook does not pass validation""" - # this notebook has a few different errors: - # - one cell is missing its source - # - invalid cell type - # - invalid output_type - with self.fopen(u'invalid.ipynb', u'r') as f: - nb = read(f, as_version=4) - with self.assertRaises(ValidationError): - validate(nb) - self.assertEqual(isvalid(nb), False) - - def test_future(self): - """Test than a notebook from the future with extra keys passes validation""" - with self.fopen(u'test4plus.ipynb', u'r') as f: - nb = read(f, as_version=4) - with self.assertRaises(ValidationError): - validate(nb, version=4) - - self.assertEqual(isvalid(nb, version=4), False) - self.assertEqual(isvalid(nb), True) - diff --git a/jupyter_nbformat/v1/__init__.py b/jupyter_nbformat/v1/__init__.py deleted file mode 100644 index b3a51a6..0000000 --- a/jupyter_nbformat/v1/__init__.py +++ /dev/null @@ -1,23 +0,0 @@ -"""The main module for the v1 notebook format.""" - -#----------------------------------------------------------------------------- -# 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 ( - NotebookNode, - new_code_cell, new_text_cell, new_notebook -) - -from .nbjson import reads as reads_json, writes as writes_json -from .nbjson import reads as read_json, writes as write_json -from .nbjson import to_notebook as to_notebook_json - -from .convert import upgrade diff --git a/jupyter_nbformat/v1/convert.py b/jupyter_nbformat/v1/convert.py deleted file mode 100644 index 303b604..0000000 --- a/jupyter_nbformat/v1/convert.py +++ /dev/null @@ -1,16 +0,0 @@ -"""Convert notebook to the v1 format.""" - -#----------------------------------------------------------------------------- -# 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. -#----------------------------------------------------------------------------- - -#----------------------------------------------------------------------------- -# Code -#----------------------------------------------------------------------------- - -def upgrade(nb, orig_version=None): - raise ValueError('Cannot convert to v1 notebook format') - diff --git a/jupyter_nbformat/v1/nbbase.py b/jupyter_nbformat/v1/nbbase.py deleted file mode 100644 index 20da6a6..0000000 --- a/jupyter_nbformat/v1/nbbase.py +++ /dev/null @@ -1,73 +0,0 @@ -"""The basic dict based 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 pprint -import uuid - -from IPython.utils.ipstruct import Struct -from IPython.utils.py3compat import unicode_type - -#----------------------------------------------------------------------------- -# 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_code_cell(code=None, prompt_number=None): - """Create a new code cell with input and output""" - cell = NotebookNode() - cell.cell_type = u'code' - if code is not None: - cell.code = unicode_type(code) - if prompt_number is not None: - cell.prompt_number = int(prompt_number) - return cell - - -def new_text_cell(text=None): - """Create a new text cell.""" - cell = NotebookNode() - if text is not None: - cell.text = unicode_type(text) - cell.cell_type = u'text' - return cell - - -def new_notebook(cells=None): - """Create a notebook by name, id and a list of worksheets.""" - nb = NotebookNode() - if cells is not None: - nb.cells = cells - else: - nb.cells = [] - return nb - diff --git a/jupyter_nbformat/v1/nbjson.py b/jupyter_nbformat/v1/nbjson.py deleted file mode 100644 index 6af14c6..0000000 --- a/jupyter_nbformat/v1/nbjson.py +++ /dev/null @@ -1,54 +0,0 @@ -"""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 -#----------------------------------------------------------------------------- - -from base64 import encodestring -from .rwbase import NotebookReader, NotebookWriter -from .nbbase import from_dict -import json - -#----------------------------------------------------------------------------- -# Code -#----------------------------------------------------------------------------- - -class JSONReader(NotebookReader): - - def reads(self, s, **kwargs): - nb = json.loads(s, **kwargs) - return self.to_notebook(nb, **kwargs) - - def to_notebook(self, d, **kwargs): - """Convert from a raw JSON dict to a nested NotebookNode structure.""" - return from_dict(d) - - -class JSONWriter(NotebookWriter): - - def writes(self, nb, **kwargs): - kwargs['indent'] = 4 - 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 - diff --git a/jupyter_nbformat/v1/rwbase.py b/jupyter_nbformat/v1/rwbase.py deleted file mode 100644 index 3938604..0000000 --- a/jupyter_nbformat/v1/rwbase.py +++ /dev/null @@ -1,47 +0,0 @@ -"""Base classes and function 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 encodestring, decodestring - -#----------------------------------------------------------------------------- -# Code -#----------------------------------------------------------------------------- - -class NotebookReader(object): - - 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.reads(fp.read(), **kwargs) - - -class NotebookWriter(object): - - 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)) - - - diff --git a/jupyter_nbformat/v1/tests/__init__.py b/jupyter_nbformat/v1/tests/__init__.py deleted file mode 100644 index e69de29..0000000 --- a/jupyter_nbformat/v1/tests/__init__.py +++ /dev/null diff --git a/jupyter_nbformat/v1/tests/nbexamples.py b/jupyter_nbformat/v1/tests/nbexamples.py deleted file mode 100644 index e07ac48..0000000 --- a/jupyter_nbformat/v1/tests/nbexamples.py +++ /dev/null @@ -1,29 +0,0 @@ -from ..nbbase import ( - NotebookNode, - new_code_cell, new_text_cell, new_notebook -) - - - -nb0 = new_notebook() - -nb0.cells.append(new_text_cell( - text='Some NumPy Examples' -)) - - -nb0.cells.append(new_code_cell( - code='import numpy', - prompt_number=1 -)) - -nb0.cells.append(new_code_cell( - code='a = numpy.random.rand(100)', - prompt_number=2 -)) - -nb0.cells.append(new_code_cell( - code='print a', - prompt_number=3 -)) - diff --git a/jupyter_nbformat/v1/tests/test_json.py b/jupyter_nbformat/v1/tests/test_json.py deleted file mode 100644 index ec7c3f9..0000000 --- a/jupyter_nbformat/v1/tests/test_json.py +++ /dev/null @@ -1,14 +0,0 @@ -from unittest import TestCase - -from ..nbjson import reads, writes -from .nbexamples import nb0 - - -class TestJSON(TestCase): - - def test_roundtrip(self): - s = writes(nb0) - self.assertEqual(reads(s),nb0) - - - diff --git a/jupyter_nbformat/v1/tests/test_nbbase.py b/jupyter_nbformat/v1/tests/test_nbbase.py deleted file mode 100644 index 6331060..0000000 --- a/jupyter_nbformat/v1/tests/test_nbbase.py +++ /dev/null @@ -1,41 +0,0 @@ -from unittest import TestCase - -from ..nbbase import ( - NotebookNode, - new_code_cell, new_text_cell, new_notebook -) - -class TestCell(TestCase): - - def test_empty_code_cell(self): - cc = new_code_cell() - self.assertEqual(cc.cell_type,'code') - self.assertEqual('code' not in cc, True) - self.assertEqual('prompt_number' not in cc, True) - - def test_code_cell(self): - cc = new_code_cell(code='a=10', prompt_number=0) - self.assertEqual(cc.code, u'a=10') - self.assertEqual(cc.prompt_number, 0) - - def test_empty_text_cell(self): - tc = new_text_cell() - self.assertEqual(tc.cell_type, 'text') - self.assertEqual('text' not in tc, True) - - def test_text_cell(self): - tc = new_text_cell('hi') - self.assertEqual(tc.text, u'hi') - - -class TestNotebook(TestCase): - - def test_empty_notebook(self): - nb = new_notebook() - self.assertEqual(nb.cells, []) - - def test_notebooke(self): - cells = [new_code_cell(),new_text_cell()] - nb = new_notebook(cells=cells) - self.assertEqual(nb.cells,cells) - diff --git a/jupyter_nbformat/v2/__init__.py b/jupyter_nbformat/v2/__init__.py deleted file mode 100644 index 35fd430..0000000 --- a/jupyter_nbformat/v2/__init__.py +++ /dev/null @@ -1,83 +0,0 @@ -"""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 .nbbase import ( - NotebookNode, - new_code_cell, new_text_cell, new_notebook, new_output, new_worksheet, - new_metadata, new_author -) - -from .nbjson import reads as reads_json, writes as writes_json -from .nbjson import reads as read_json, writes as write_json -from .nbjson import to_notebook as to_notebook_json - -from .nbxml import reads as reads_xml -from .nbxml import reads as read_xml -from .nbxml import to_notebook as to_notebook_xml - -from .nbpy import reads as reads_py, writes as writes_py -from .nbpy import reads as read_py, writes as write_py -from .nbpy import to_notebook as to_notebook_py - -from .convert import downgrade, upgrade - -#----------------------------------------------------------------------------- -# 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 == u'.ipynb': - format = u'json' - elif ext == u'.json': - format = u'json' - elif ext == u'.py': - format = u'py' - else: - basename = fname - fname = fname + u'.ipynb' - format = u'json' - return fname, basename, format diff --git a/jupyter_nbformat/v2/convert.py b/jupyter_nbformat/v2/convert.py deleted file mode 100644 index d084ae6..0000000 --- a/jupyter_nbformat/v2/convert.py +++ /dev/null @@ -1,61 +0,0 @@ -"""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_text_cell, new_worksheet, new_notebook, new_output -) - -#----------------------------------------------------------------------------- -# 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 == u'code': - newcell = new_code_cell(input=cell.get('code'),prompt_number=cell.get('prompt_number')) - elif cell.cell_type == u'text': - newcell = new_text_cell(u'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.") diff --git a/jupyter_nbformat/v2/nbbase.py b/jupyter_nbformat/v2/nbbase.py deleted file mode 100644 index 793aea1..0000000 --- a/jupyter_nbformat/v2/nbbase.py +++ /dev/null @@ -1,180 +0,0 @@ -"""The basic dict based notebook format. - -The Python representation of a notebook is a nested structure of -dictionary subclasses that support attribute access -(IPython.utils.ipstruct.Struct). 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 -#----------------------------------------------------------------------------- - -import pprint -import uuid - -from IPython.utils.ipstruct import Struct -from IPython.utils.py3compat import unicode_type - -#----------------------------------------------------------------------------- -# 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 = unicode_type(output_type) - - if output_type != 'pyerr': - if output_text is not None: - output.text = unicode_type(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 = unicode_type(output_html) - if output_svg is not None: - output.svg = unicode_type(output_svg) - if output_latex is not None: - output.latex = unicode_type(output_latex) - if output_json is not None: - output.json = unicode_type(output_json) - if output_javascript is not None: - output.javascript = unicode_type(output_javascript) - - if output_type == u'pyout': - if prompt_number is not None: - output.prompt_number = int(prompt_number) - - if output_type == u'pyerr': - if etype is not None: - output.etype = unicode_type(etype) - if evalue is not None: - output.evalue = unicode_type(evalue) - if traceback is not None: - output.traceback = [unicode_type(frame) for frame in list(traceback)] - - return output - - -def new_code_cell(input=None, prompt_number=None, outputs=None, - language=u'python', collapsed=False): - """Create a new code cell with input and output""" - cell = NotebookNode() - cell.cell_type = u'code' - if language is not None: - cell.language = unicode_type(language) - if input is not None: - cell.input = unicode_type(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 = unicode_type(source) - if rendered is not None: - cell.rendered = unicode_type(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 = unicode_type(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 = unicode_type(name) - if authors is not None: - metadata.authors = list(authors) - if created is not None: - metadata.created = unicode_type(created) - if modified is not None: - metadata.modified = unicode_type(modified) - if license is not None: - metadata.license = unicode_type(license) - if gistid is not None: - metadata.gistid = unicode_type(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 = unicode_type(name) - if email is not None: - author.email = unicode_type(email) - if affiliation is not None: - author.affiliation = unicode_type(affiliation) - if url is not None: - author.url = unicode_type(url) - return author - diff --git a/jupyter_nbformat/v2/nbjson.py b/jupyter_nbformat/v2/nbjson.py deleted file mode 100644 index d60e95f..0000000 --- a/jupyter_nbformat/v2/nbjson.py +++ /dev/null @@ -1,69 +0,0 @@ -"""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, restore_bytes, rejoin_lines, 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 - diff --git a/jupyter_nbformat/v2/nbpy.py b/jupyter_nbformat/v2/nbpy.py deleted file mode 100644 index 3e34b47..0000000 --- a/jupyter_nbformat/v2/nbpy.py +++ /dev/null @@ -1,151 +0,0 @@ -"""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 IPython.utils.py3compat import unicode_type -from .rwbase import NotebookReader, NotebookWriter -from .nbbase import new_code_cell, new_text_cell, new_worksheet, new_notebook - -#----------------------------------------------------------------------------- -# 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 = [] - state = u'codecell' - for line in lines: - if line.startswith(u'# ') or _encoding_declaration_re.match(line): - pass - elif line.startswith(u'# '): - cell = self.new_cell(state, cell_lines) - if cell is not None: - cells.append(cell) - state = u'codecell' - cell_lines = [] - elif line.startswith(u'# '): - cell = self.new_cell(state, cell_lines) - if cell is not None: - cells.append(cell) - state = u'htmlcell' - cell_lines = [] - elif line.startswith(u'# '): - cell = self.new_cell(state, cell_lines) - if cell is not None: - cells.append(cell) - state = u'markdowncell' - cell_lines = [] - else: - cell_lines.append(line) - if cell_lines and state == u'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 == u'codecell': - input = u'\n'.join(lines) - input = input.strip(u'\n') - if input: - return new_code_cell(input=input) - elif state == u'htmlcell': - text = self._remove_comments(lines) - if text: - return new_text_cell(u'html',source=text) - elif state == u'markdowncell': - text = self._remove_comments(lines) - if text: - return new_text_cell(u'markdown',source=text) - - def _remove_comments(self, lines): - new_lines = [] - for line in lines: - if line.startswith(u'#'): - new_lines.append(line[2:]) - else: - new_lines.append(line) - text = u'\n'.join(new_lines) - text = text.strip(u'\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 = [u'# -*- coding: utf-8 -*-'] - lines.extend([u'# 2','']) - for ws in nb.worksheets: - for cell in ws.cells: - if cell.cell_type == u'code': - input = cell.get(u'input') - if input is not None: - lines.extend([u'# ',u'']) - lines.extend(input.splitlines()) - lines.append(u'') - elif cell.cell_type == u'html': - input = cell.get(u'source') - if input is not None: - lines.extend([u'# ',u'']) - lines.extend([u'# ' + line for line in input.splitlines()]) - lines.append(u'') - elif cell.cell_type == u'markdown': - input = cell.get(u'source') - if input is not None: - lines.extend([u'# ',u'']) - lines.extend([u'# ' + line for line in input.splitlines()]) - lines.append(u'') - lines.append('') - return unicode_type('\n'.join(lines)) - - -_reader = PyReader() -_writer = PyWriter() - -reads = _reader.reads -read = _reader.read -to_notebook = _reader.to_notebook -write = _writer.write -writes = _writer.writes - diff --git a/jupyter_nbformat/v2/nbxml.py b/jupyter_nbformat/v2/nbxml.py deleted file mode 100644 index f9ca124..0000000 --- a/jupyter_nbformat/v2/nbxml.py +++ /dev/null @@ -1,189 +0,0 @@ -"""Read and write notebook files as XML. - -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 encodestring, decodestring -import warnings -from xml.etree import ElementTree as ET - -from IPython.utils.py3compat import unicode_type -from .rwbase import NotebookReader, NotebookWriter -from .nbbase import ( - new_code_cell, new_text_cell, new_worksheet, new_notebook, new_output, - new_metadata -) - -#----------------------------------------------------------------------------- -# Code -#----------------------------------------------------------------------------- - -def indent(elem, level=0): - i = "\n" + level*" " - if len(elem): - if not elem.text or not elem.text.strip(): - elem.text = i + " " - if not elem.tail or not elem.tail.strip(): - elem.tail = i - for elem in elem: - indent(elem, level+1) - if not elem.tail or not elem.tail.strip(): - elem.tail = i - else: - if level and (not elem.tail or not elem.tail.strip()): - elem.tail = i - - -def _get_text(e, tag): - sub_e = e.find(tag) - if sub_e is None: - return None - else: - return sub_e.text - - -def _set_text(nbnode, attr, parent, tag): - if attr in nbnode: - e = ET.SubElement(parent, tag) - e.text = nbnode[attr] - - -def _get_int(e, tag): - sub_e = e.find(tag) - if sub_e is None: - return None - else: - return int(sub_e.text) - - -def _set_int(nbnode, attr, parent, tag): - if attr in nbnode: - e = ET.SubElement(parent, tag) - e.text = unicode_type(nbnode[attr]) - - -def _get_bool(e, tag): - sub_e = e.find(tag) - if sub_e is None: - return None - else: - return bool(int(sub_e.text)) - - -def _set_bool(nbnode, attr, parent, tag): - if attr in nbnode: - e = ET.SubElement(parent, tag) - if nbnode[attr]: - e.text = u'1' - else: - e.text = u'0' - - -def _get_binary(e, tag): - sub_e = e.find(tag) - if sub_e is None: - return None - else: - return decodestring(sub_e.text) - - -def _set_binary(nbnode, attr, parent, tag): - if attr in nbnode: - e = ET.SubElement(parent, tag) - e.text = encodestring(nbnode[attr]) - - -class XMLReader(NotebookReader): - - def reads(self, s, **kwargs): - root = ET.fromstring(s) - return self.to_notebook(root, **kwargs) - - def to_notebook(self, root, **kwargs): - warnings.warn('The XML notebook format is no longer supported, ' - 'please convert your notebooks to JSON.', DeprecationWarning) - nbname = _get_text(root,u'name') - nbauthor = _get_text(root,u'author') - nbemail = _get_text(root,u'email') - nblicense = _get_text(root,u'license') - nbcreated = _get_text(root,u'created') - nbsaved = _get_text(root,u'saved') - - worksheets = [] - for ws_e in root.find(u'worksheets').getiterator(u'worksheet'): - wsname = _get_text(ws_e,u'name') - cells = [] - for cell_e in ws_e.find(u'cells').getiterator(): - if cell_e.tag == u'codecell': - input = _get_text(cell_e,u'input') - prompt_number = _get_int(cell_e,u'prompt_number') - collapsed = _get_bool(cell_e,u'collapsed') - language = _get_text(cell_e,u'language') - outputs = [] - for output_e in cell_e.find(u'outputs').getiterator(u'output'): - output_type = _get_text(output_e,u'output_type') - output_text = _get_text(output_e,u'text') - output_png = _get_binary(output_e,u'png') - output_jpeg = _get_binary(output_e,u'jpeg') - output_svg = _get_text(output_e,u'svg') - output_html = _get_text(output_e,u'html') - output_latex = _get_text(output_e,u'latex') - output_json = _get_text(output_e,u'json') - output_javascript = _get_text(output_e,u'javascript') - - out_prompt_number = _get_int(output_e,u'prompt_number') - etype = _get_text(output_e,u'etype') - evalue = _get_text(output_e,u'evalue') - traceback = [] - traceback_e = output_e.find(u'traceback') - if traceback_e is not None: - for frame_e in traceback_e.getiterator(u'frame'): - traceback.append(frame_e.text) - if len(traceback) == 0: - traceback = None - output = new_output(output_type=output_type,output_png=output_png, - output_text=output_text, output_svg=output_svg, - output_html=output_html, output_latex=output_latex, - output_json=output_json, output_javascript=output_javascript, - output_jpeg=output_jpeg, prompt_number=out_prompt_number, - etype=etype, evalue=evalue, traceback=traceback - ) - outputs.append(output) - cc = new_code_cell(input=input,prompt_number=prompt_number, - language=language,outputs=outputs,collapsed=collapsed) - cells.append(cc) - if cell_e.tag == u'htmlcell': - source = _get_text(cell_e,u'source') - rendered = _get_text(cell_e,u'rendered') - cells.append(new_text_cell(u'html', source=source, rendered=rendered)) - if cell_e.tag == u'markdowncell': - source = _get_text(cell_e,u'source') - rendered = _get_text(cell_e,u'rendered') - cells.append(new_text_cell(u'markdown', source=source, rendered=rendered)) - ws = new_worksheet(name=wsname,cells=cells) - worksheets.append(ws) - - md = new_metadata(name=nbname) - nb = new_notebook(metadata=md,worksheets=worksheets) - return nb - - -_reader = XMLReader() - -reads = _reader.reads -read = _reader.read -to_notebook = _reader.to_notebook - diff --git a/jupyter_nbformat/v2/rwbase.py b/jupyter_nbformat/v2/rwbase.py deleted file mode 100644 index 8f80768..0000000 --- a/jupyter_nbformat/v2/rwbase.py +++ /dev/null @@ -1,165 +0,0 @@ -"""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 encodestring, decodestring -import pprint - -from IPython.utils.py3compat import str_to_bytes, unicode_type, string_types - -#----------------------------------------------------------------------------- -# 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 = str_to_bytes(output.png, 'ascii') - if 'jpeg' in output: - output.jpeg = str_to_bytes(output.jpeg, '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 = u'\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] = u'\n'.join(item) - else: # text cell - for key in ['source', 'rendered']: - item = cell.get(key, None) - if isinstance(item, list): - cell[key] = u'\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, string_types): - cell.input = cell.input.splitlines() - for output in cell.outputs: - for key in _multiline_outputs: - item = output.get(key, None) - if isinstance(item, string_types): - output[key] = item.splitlines() - else: # text cell - for key in ['source', 'rendered']: - item = cell.get(key, None) - if isinstance(item, string_types): - 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, unicode_type): - output.png = output.png.encode('ascii') - output.png = decodestring(output.png) - if 'jpeg' in output: - if isinstance(output.jpeg, unicode_type): - output.jpeg = output.jpeg.encode('ascii') - output.jpeg = decodestring(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 = encodestring(output.png).decode('ascii') - if 'jpeg' in output: - output.jpeg = encodestring(output.jpeg).decode('ascii') - return nb - - -class NotebookReader(object): - """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(object): - """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)) - - - diff --git a/jupyter_nbformat/v2/tests/__init__.py b/jupyter_nbformat/v2/tests/__init__.py deleted file mode 100644 index e69de29..0000000 --- a/jupyter_nbformat/v2/tests/__init__.py +++ /dev/null diff --git a/jupyter_nbformat/v2/tests/nbexamples.py b/jupyter_nbformat/v2/tests/nbexamples.py deleted file mode 100644 index 3e83e8e..0000000 --- a/jupyter_nbformat/v2/tests/nbexamples.py +++ /dev/null @@ -1,109 +0,0 @@ -import os -from base64 import encodestring - -from ..nbbase import ( - NotebookNode, - new_code_cell, new_text_cell, new_worksheet, new_notebook, new_output, - new_metadata, new_author -) - -# some random base64-encoded *bytes* -png = encodestring(os.urandom(5)) -jpeg = encodestring(os.urandom(6)) - -ws = new_worksheet(name='worksheet1') - -ws.cells.append(new_text_cell( - u'html', - source='Some NumPy Examples', - rendered='Some NumPy Examples' -)) - - -ws.cells.append(new_code_cell( - input='import numpy', - prompt_number=1, - collapsed=False -)) - -ws.cells.append(new_text_cell( - u'markdown', - source='A random array', - rendered='A random array' -)) - -ws.cells.append(new_code_cell( - input='a = numpy.random.rand(100)', - prompt_number=2, - collapsed=True -)) - -ws.cells.append(new_code_cell( - input='print a', - prompt_number=3, - collapsed=False, - outputs=[new_output( - output_type=u'pyout', - output_text=u'', - output_html=u'The HTML rep', - output_latex=u'$a$', - output_png=png, - output_jpeg=jpeg, - output_svg=u'', - output_json=u'json data', - output_javascript=u'var i=0;', - prompt_number=3 - ),new_output( - output_type=u'display_data', - output_text=u'', - output_html=u'The HTML rep', - output_latex=u'$a$', - output_png=png, - output_jpeg=jpeg, - output_svg=u'', - output_json=u'json data', - output_javascript=u'var i=0;' - ),new_output( - output_type=u'pyerr', - etype=u'NameError', - evalue=u'NameError was here', - traceback=[u'frame 0', u'frame 1', u'frame 2'] - )] -)) - -authors = [new_author(name='Bart Simpson',email='bsimpson@fox.com', - affiliation=u'Fox',url=u'http://www.fox.com')] -md = new_metadata(name=u'My Notebook',license=u'BSD',created=u'8601_goes_here', - modified=u'8601_goes_here',gistid=u'21341231',authors=authors) - -nb0 = new_notebook( - worksheets=[ws, new_worksheet(name='worksheet2')], - metadata=md -) - -nb0_py = """# -*- coding: utf-8 -*- -# 2 - -# - -# Some NumPy Examples - -# - -import numpy - -# - -# A random array - -# - -a = numpy.random.rand(100) - -# - -print a - -""" - - diff --git a/jupyter_nbformat/v2/tests/test_json.py b/jupyter_nbformat/v2/tests/test_json.py deleted file mode 100644 index 453d6c4..0000000 --- a/jupyter_nbformat/v2/tests/test_json.py +++ /dev/null @@ -1,34 +0,0 @@ -import pprint -from unittest import TestCase - -from ..nbjson import reads, writes -from .nbexamples import nb0 - - -class TestJSON(TestCase): - - def test_roundtrip(self): - s = writes(nb0) -# print -# print pprint.pformat(nb0,indent=2) -# print -# print pprint.pformat(reads(s),indent=2) -# print -# print s - self.assertEqual(reads(s),nb0) - - def test_roundtrip_nosplit(self): - """Ensure that multiline blobs are still readable""" - # ensures that notebooks written prior to splitlines change - # are still readable. - s = writes(nb0, split_lines=False) - self.assertEqual(reads(s),nb0) - - def test_roundtrip_split(self): - """Ensure that splitting multiline blocks is safe""" - # This won't differ from test_roundtrip unless the default changes - s = writes(nb0, split_lines=True) - self.assertEqual(reads(s),nb0) - - - diff --git a/jupyter_nbformat/v2/tests/test_nbbase.py b/jupyter_nbformat/v2/tests/test_nbbase.py deleted file mode 100644 index 62d49bf..0000000 --- a/jupyter_nbformat/v2/tests/test_nbbase.py +++ /dev/null @@ -1,113 +0,0 @@ -from unittest import TestCase - -from ..nbbase import ( - NotebookNode, - new_code_cell, new_text_cell, new_worksheet, new_notebook, new_output, - new_author, new_metadata -) - -class TestCell(TestCase): - - def test_empty_code_cell(self): - cc = new_code_cell() - self.assertEqual(cc.cell_type,u'code') - self.assertEqual(u'input' not in cc, True) - self.assertEqual(u'prompt_number' not in cc, True) - self.assertEqual(cc.outputs, []) - self.assertEqual(cc.collapsed, False) - - def test_code_cell(self): - cc = new_code_cell(input='a=10', prompt_number=0, collapsed=True) - cc.outputs = [new_output(output_type=u'pyout', - output_svg=u'foo',output_text=u'10',prompt_number=0)] - self.assertEqual(cc.input, u'a=10') - self.assertEqual(cc.prompt_number, 0) - self.assertEqual(cc.language, u'python') - self.assertEqual(cc.outputs[0].svg, u'foo') - self.assertEqual(cc.outputs[0].text, u'10') - self.assertEqual(cc.outputs[0].prompt_number, 0) - self.assertEqual(cc.collapsed, True) - - def test_pyerr(self): - o = new_output(output_type=u'pyerr', etype=u'NameError', - evalue=u'Name not found', traceback=[u'frame 0', u'frame 1', u'frame 2'] - ) - self.assertEqual(o.output_type, u'pyerr') - self.assertEqual(o.etype, u'NameError') - self.assertEqual(o.evalue, u'Name not found') - self.assertEqual(o.traceback, [u'frame 0', u'frame 1', u'frame 2']) - - def test_empty_html_cell(self): - tc = new_text_cell(u'html') - self.assertEqual(tc.cell_type, u'html') - self.assertEqual(u'source' not in tc, True) - self.assertEqual(u'rendered' not in tc, True) - - def test_html_cell(self): - tc = new_text_cell(u'html', 'hi', 'hi') - self.assertEqual(tc.source, u'hi') - self.assertEqual(tc.rendered, u'hi') - - def test_empty_markdown_cell(self): - tc = new_text_cell(u'markdown') - self.assertEqual(tc.cell_type, u'markdown') - self.assertEqual(u'source' not in tc, True) - self.assertEqual(u'rendered' not in tc, True) - - def test_markdown_cell(self): - tc = new_text_cell(u'markdown', 'hi', 'hi') - self.assertEqual(tc.source, u'hi') - self.assertEqual(tc.rendered, u'hi') - - -class TestWorksheet(TestCase): - - def test_empty_worksheet(self): - ws = new_worksheet() - self.assertEqual(ws.cells,[]) - self.assertEqual(u'name' not in ws, True) - - def test_worksheet(self): - cells = [new_code_cell(), new_text_cell(u'html')] - ws = new_worksheet(cells=cells,name=u'foo') - self.assertEqual(ws.cells,cells) - self.assertEqual(ws.name,u'foo') - -class TestNotebook(TestCase): - - def test_empty_notebook(self): - nb = new_notebook() - self.assertEqual(nb.worksheets, []) - self.assertEqual(nb.metadata, NotebookNode()) - self.assertEqual(nb.nbformat,2) - - def test_notebook(self): - worksheets = [new_worksheet(),new_worksheet()] - metadata = new_metadata(name=u'foo') - nb = new_notebook(metadata=metadata,worksheets=worksheets) - self.assertEqual(nb.metadata.name,u'foo') - self.assertEqual(nb.worksheets,worksheets) - self.assertEqual(nb.nbformat,2) - -class TestMetadata(TestCase): - - def test_empty_metadata(self): - md = new_metadata() - self.assertEqual(u'name' not in md, True) - self.assertEqual(u'authors' not in md, True) - self.assertEqual(u'license' not in md, True) - self.assertEqual(u'saved' not in md, True) - self.assertEqual(u'modified' not in md, True) - self.assertEqual(u'gistid' not in md, True) - - def test_metadata(self): - authors = [new_author(name='Bart Simpson',email='bsimpson@fox.com')] - md = new_metadata(name=u'foo',license=u'BSD',created=u'today', - modified=u'now',gistid=u'21341231',authors=authors) - self.assertEqual(md.name, u'foo') - self.assertEqual(md.license, u'BSD') - self.assertEqual(md.created, u'today') - self.assertEqual(md.modified, u'now') - self.assertEqual(md.gistid, u'21341231') - self.assertEqual(md.authors, authors) - diff --git a/jupyter_nbformat/v2/tests/test_nbpy.py b/jupyter_nbformat/v2/tests/test_nbpy.py deleted file mode 100644 index 956c5a6..0000000 --- a/jupyter_nbformat/v2/tests/test_nbpy.py +++ /dev/null @@ -1,17 +0,0 @@ -from unittest import TestCase - -from ..nbbase import ( - NotebookNode, - new_code_cell, new_text_cell, new_worksheet, new_notebook -) - -from ..nbpy import reads, writes -from .nbexamples import nb0, nb0_py - - -class TestPy(TestCase): - - def test_write(self): - s = writes(nb0) - self.assertEqual(s,nb0_py) - diff --git a/jupyter_nbformat/v3/__init__.py b/jupyter_nbformat/v3/__init__.py deleted file mode 100644 index c93834b..0000000 --- a/jupyter_nbformat/v3/__init__.py +++ /dev/null @@ -1,70 +0,0 @@ -"""The main API for the v3 notebook format. -""" - -# Copyright (c) IPython Development Team. -# Distributed under the terms of the Modified BSD License. - -__all__ = ['NotebookNode', 'new_code_cell', 'new_text_cell', 'new_notebook', - 'new_output', 'new_worksheet', 'new_metadata', 'new_author', - 'new_heading_cell', 'nbformat', 'nbformat_minor', 'nbformat_schema', - 'reads_json', 'writes_json', 'read_json', 'write_json', - 'to_notebook_json', 'reads_py', 'writes_py', 'read_py', 'write_py', - 'to_notebook_py', 'downgrade', 'upgrade', 'parse_filename' - ] - -import os - -from .nbbase import ( - NotebookNode, - new_code_cell, new_text_cell, new_notebook, new_output, new_worksheet, - new_metadata, new_author, new_heading_cell, nbformat, nbformat_minor, - nbformat_schema -) - -from .nbjson import reads as reads_json, writes as writes_json -from .nbjson import reads as read_json, writes as write_json -from .nbjson import to_notebook as to_notebook_json - -from .nbpy import reads as reads_py, writes as writes_py -from .nbpy import reads as read_py, writes as write_py -from .nbpy import to_notebook as to_notebook_py - -from .convert import downgrade, upgrade - - -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 == u'.ipynb': - format = u'json' - elif ext == u'.json': - format = u'json' - elif ext == u'.py': - format = u'py' - else: - basename = fname - fname = fname + u'.ipynb' - format = u'json' - return fname, basename, format diff --git a/jupyter_nbformat/v3/convert.py b/jupyter_nbformat/v3/convert.py deleted file mode 100644 index 04b44b7..0000000 --- a/jupyter_nbformat/v3/convert.py +++ /dev/null @@ -1,91 +0,0 @@ -"""Code for converting notebooks to and from the v2 format.""" - -# Copyright (c) IPython Development Team. -# Distributed under the terms of the Modified BSD License. - -from .nbbase import ( - new_code_cell, new_text_cell, new_worksheet, new_notebook, new_output, - nbformat, nbformat_minor -) - -from jupyter_nbformat import v2 - -def _unbytes(obj): - """There should be no bytes objects in a notebook - - v2 stores png/jpeg as b64 ascii bytes - """ - if isinstance(obj, dict): - for k,v in obj.items(): - obj[k] = _unbytes(v) - elif isinstance(obj, list): - for i,v in enumerate(obj): - obj[i] = _unbytes(v) - elif isinstance(obj, bytes): - # only valid bytes are b64-encoded ascii - obj = obj.decode('ascii') - return obj - -def upgrade(nb, from_version=2, from_minor=0): - """Convert a notebook to v3. - - Parameters - ---------- - nb : NotebookNode - The Python representation of the notebook to convert. - from_version : int - The original version of the notebook to convert. - from_minor : int - The original minor version of the notebook to convert (only relevant for v >= 3). - """ - if from_version == 2: - # Mark the original nbformat so consumers know it has been converted. - nb.nbformat = nbformat - nb.nbformat_minor = nbformat_minor - - nb.orig_nbformat = 2 - nb = _unbytes(nb) - for ws in nb['worksheets']: - for cell in ws['cells']: - cell.setdefault('metadata', {}) - return nb - elif from_version == 3: - if from_minor != nbformat_minor: - nb.orig_nbformat_minor = from_minor - nb.nbformat_minor = nbformat_minor - return nb - else: - raise ValueError('Cannot convert a notebook directly from v%s to v3. ' \ - 'Try using the IPython.nbformat.convert module.' % from_version) - - -def heading_to_md(cell): - """turn heading cell into corresponding markdown""" - cell.cell_type = "markdown" - level = cell.pop('level', 1) - cell.source = '#'*level + ' ' + cell.source - - -def raw_to_md(cell): - """let raw passthrough as markdown""" - cell.cell_type = "markdown" - - -def downgrade(nb): - """Convert a v3 notebook to v2. - - Parameters - ---------- - nb : NotebookNode - The Python representation of the notebook to convert. - """ - if nb.nbformat != 3: - return nb - nb.nbformat = 2 - for ws in nb.worksheets: - for cell in ws.cells: - if cell.cell_type == 'heading': - heading_to_md(cell) - elif cell.cell_type == 'raw': - raw_to_md(cell) - return nb \ No newline at end of file diff --git a/jupyter_nbformat/v3/nbbase.py b/jupyter_nbformat/v3/nbbase.py deleted file mode 100644 index 3a48ab8..0000000 --- a/jupyter_nbformat/v3/nbbase.py +++ /dev/null @@ -1,202 +0,0 @@ -"""The basic dict based notebook format. - -The Python representation of a notebook is a nested structure of -dictionary subclasses that support attribute access -(IPython.utils.ipstruct.Struct). The functions in this module are merely -helpers to build the structs in the right form. -""" - -# Copyright (c) IPython Development Team. -# Distributed under the terms of the Modified BSD License. - -import pprint -import uuid - -from IPython.utils.ipstruct import Struct -from IPython.utils.py3compat import cast_unicode, unicode_type - -#----------------------------------------------------------------------------- -# Code -#----------------------------------------------------------------------------- - -# Change this when incrementing the nbformat version -nbformat = 3 -nbformat_minor = 0 -nbformat_schema = 'nbformat.v3.schema.json' - -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, 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, - ename=None, evalue=None, traceback=None, stream=None, metadata=None): - """Create a new output, to go in the ``cell.outputs`` list of a code cell. - """ - output = NotebookNode() - output.output_type = unicode_type(output_type) - - if metadata is None: - metadata = {} - if not isinstance(metadata, dict): - raise TypeError("metadata must be dict") - - - if output_type in {u'pyout', 'display_data'}: - output.metadata = metadata - - if output_type != 'pyerr': - if output_text is not None: - output.text = cast_unicode(output_text) - if output_png is not None: - output.png = cast_unicode(output_png) - if output_jpeg is not None: - output.jpeg = cast_unicode(output_jpeg) - if output_html is not None: - output.html = cast_unicode(output_html) - if output_svg is not None: - output.svg = cast_unicode(output_svg) - if output_latex is not None: - output.latex = cast_unicode(output_latex) - if output_json is not None: - output.json = cast_unicode(output_json) - if output_javascript is not None: - output.javascript = cast_unicode(output_javascript) - - if output_type == u'pyout': - if prompt_number is not None: - output.prompt_number = int(prompt_number) - - if output_type == u'pyerr': - if ename is not None: - output.ename = cast_unicode(ename) - if evalue is not None: - output.evalue = cast_unicode(evalue) - if traceback is not None: - output.traceback = [cast_unicode(frame) for frame in list(traceback)] - - if output_type == u'stream': - output.stream = 'stdout' if stream is None else cast_unicode(stream) - - return output - - -def new_code_cell(input=None, prompt_number=None, outputs=None, - language=u'python', collapsed=False, metadata=None): - """Create a new code cell with input and output""" - cell = NotebookNode() - cell.cell_type = u'code' - if language is not None: - cell.language = cast_unicode(language) - if input is not None: - cell.input = cast_unicode(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) - cell.metadata = NotebookNode(metadata or {}) - - return cell - -def new_text_cell(cell_type, source=None, rendered=None, metadata=None): - """Create a new text cell.""" - cell = NotebookNode() - # VERSIONHACK: plaintext -> raw - # handle never-released plaintext name for raw cells - if cell_type == 'plaintext': - cell_type = 'raw' - if source is not None: - cell.source = cast_unicode(source) - cell.metadata = NotebookNode(metadata or {}) - cell.cell_type = cell_type - return cell - - -def new_heading_cell(source=None, level=1, rendered=None, metadata=None): - """Create a new section cell with a given integer level.""" - cell = NotebookNode() - cell.cell_type = u'heading' - if source is not None: - cell.source = cast_unicode(source) - cell.level = int(level) - cell.metadata = NotebookNode(metadata or {}) - return cell - - -def new_worksheet(name=None, cells=None, metadata=None): - """Create a worksheet by name with with a list of cells.""" - ws = NotebookNode() - if cells is None: - ws.cells = [] - else: - ws.cells = list(cells) - ws.metadata = NotebookNode(metadata or {}) - return ws - - -def new_notebook(name=None, metadata=None, worksheets=None): - """Create a notebook by name, id and a list of worksheets.""" - nb = NotebookNode() - nb.nbformat = nbformat - nb.nbformat_minor = nbformat_minor - if worksheets is None: - nb.worksheets = [] - else: - nb.worksheets = list(worksheets) - if metadata is None: - nb.metadata = new_metadata() - else: - nb.metadata = NotebookNode(metadata) - if name is not None: - nb.metadata.name = cast_unicode(name) - 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 = cast_unicode(name) - if authors is not None: - metadata.authors = list(authors) - if created is not None: - metadata.created = cast_unicode(created) - if modified is not None: - metadata.modified = cast_unicode(modified) - if license is not None: - metadata.license = cast_unicode(license) - if gistid is not None: - metadata.gistid = cast_unicode(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 = cast_unicode(name) - if email is not None: - author.email = cast_unicode(email) - if affiliation is not None: - author.affiliation = cast_unicode(affiliation) - if url is not None: - author.url = cast_unicode(url) - return author - diff --git a/jupyter_nbformat/v3/nbformat.v3.schema.json b/jupyter_nbformat/v3/nbformat.v3.schema.json deleted file mode 100644 index 8175853..0000000 --- a/jupyter_nbformat/v3/nbformat.v3.schema.json +++ /dev/null @@ -1,367 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "IPython Notebook v3.0 JSON schema.", - "type": "object", - "additionalProperties": false, - "required": ["metadata", "nbformat_minor", "nbformat", "worksheets"], - "properties": { - "metadata": { - "description": "Notebook root-level metadata.", - "type": "object", - "additionalProperties": true, - "properties": { - "kernel_info": { - "description": "Kernel information.", - "type": "object", - "required": ["name", "language"], - "properties": { - "name": { - "description": "Name of the kernel specification.", - "type": "string" - }, - "language": { - "description": "The programming language which this kernel runs.", - "type": "string" - }, - "codemirror_mode": { - "description": "The codemirror mode to use for code in this language.", - "type": "string" - } - } - }, - "signature": { - "description": "Hash of the notebook.", - "type": "string" - } - } - }, - "nbformat_minor": { - "description": "Notebook format (minor number). Incremented for backward compatible changes to the notebook format.", - "type": "integer", - "minimum": 0 - }, - "nbformat": { - "description": "Notebook format (major number). Incremented between backwards incompatible changes to the notebook format.", - "type": "integer", - "minimum": 3, - "maximum": 3 - }, - "orig_nbformat": { - "description": "Original notebook format (major number) before converting the notebook between versions.", - "type": "integer", - "minimum": 1 - }, - "orig_nbformat_minor": { - "description": "Original notebook format (minor number) before converting the notebook between versions.", - "type": "integer", - "minimum": 0 - }, - "worksheets" : { - "description": "Array of worksheets", - "type": "array", - "items": {"$ref": "#/definitions/worksheet"} - } - }, - - "definitions": { - "worksheet": { - "additionalProperties": false, - "required" : ["cells"], - "properties":{ - "cells": { - "description": "Array of cells of the current notebook.", - "type": "array", - "items": { - "type": "object", - "oneOf": [ - {"$ref": "#/definitions/raw_cell"}, - {"$ref": "#/definitions/markdown_cell"}, - {"$ref": "#/definitions/heading_cell"}, - {"$ref": "#/definitions/code_cell"} - ] - } - }, - "metadata": { - "type": "object", - "description": "metadata of the current worksheet" - } - } - }, - "raw_cell": { - "description": "Notebook raw nbconvert cell.", - "type": "object", - "additionalProperties": false, - "required": ["cell_type", "source"], - "properties": { - "cell_type": { - "description": "String identifying the type of cell.", - "enum": ["raw"] - }, - "metadata": { - "description": "Cell-level metadata.", - "type": "object", - "additionalProperties": true, - "properties": { - "format": { - "description": "Raw cell metadata format for nbconvert.", - "type": "string" - }, - "name": {"$ref": "#/definitions/misc/metadata_name"}, - "tags": {"$ref": "#/definitions/misc/metadata_tags"} - } - }, - "source": {"$ref": "#/definitions/misc/source"} - } - }, - - "markdown_cell": { - "description": "Notebook markdown cell.", - "type": "object", - "additionalProperties": false, - "required": ["cell_type", "source"], - "properties": { - "cell_type": { - "description": "String identifying the type of cell.", - "enum": ["markdown", "html"] - }, - "metadata": { - "description": "Cell-level metadata.", - "type": "object", - "properties": { - "name": {"$ref": "#/definitions/misc/metadata_name"}, - "tags": {"$ref": "#/definitions/misc/metadata_tags"} - }, - "additionalProperties": true - }, - "source": {"$ref": "#/definitions/misc/source"} - } - }, - - "heading_cell": { - "description": "Notebook heading cell.", - "type": "object", - "additionalProperties": false, - "required": ["cell_type", "source", "level"], - "properties": { - "cell_type": { - "description": "String identifying the type of cell.", - "enum": ["heading"] - }, - "metadata": { - "description": "Cell-level metadata.", - "type": "object", - "additionalProperties": true - }, - "source": {"$ref": "#/definitions/misc/source"}, - "level": { - "description": "Level of heading cells.", - "type": "integer", - "minimum": 1 - } - } - }, - - "code_cell": { - "description": "Notebook code cell.", - "type": "object", - "additionalProperties": false, - "required": ["cell_type", "input", "outputs", "language"], - "properties": { - "cell_type": { - "description": "String identifying the type of cell.", - "enum": ["code"] - }, - "language": { - "description": "The cell's language (always Python)", - "type": "string" - }, - "collapsed": { - "description": "Whether the cell is collapsed/expanded.", - "type": "boolean" - }, - "metadata": { - "description": "Cell-level metadata.", - "type": "object", - "additionalProperties": true - }, - "input": {"$ref": "#/definitions/misc/source"}, - "outputs": { - "description": "Execution, display, or stream outputs.", - "type": "array", - "items": {"$ref": "#/definitions/output"} - }, - "prompt_number": { - "description": "The code cell's prompt number. Will be null if the cell has not been run.", - "type": ["integer", "null"], - "minimum": 0 - } - } - }, - "output": { - "type": "object", - "oneOf": [ - {"$ref": "#/definitions/pyout"}, - {"$ref": "#/definitions/display_data"}, - {"$ref": "#/definitions/stream"}, - {"$ref": "#/definitions/pyerr"} - ] - }, - "pyout": { - "description": "Result of executing a code cell.", - "type": "object", - "additionalProperties": false, - "required": ["output_type", "prompt_number"], - "properties": { - "output_type": { - "description": "Type of cell output.", - "enum": ["pyout"] - }, - "prompt_number": { - "description": "A result's prompt number.", - "type": ["integer"], - "minimum": 0 - }, - "text": {"$ref": "#/definitions/misc/multiline_string"}, - "latex": {"$ref": "#/definitions/misc/multiline_string"}, - "png": {"$ref": "#/definitions/misc/multiline_string"}, - "jpeg": {"$ref": "#/definitions/misc/multiline_string"}, - "svg": {"$ref": "#/definitions/misc/multiline_string"}, - "html": {"$ref": "#/definitions/misc/multiline_string"}, - "javascript": {"$ref": "#/definitions/misc/multiline_string"}, - "json": {"$ref": "#/definitions/misc/multiline_string"}, - "pdf": {"$ref": "#/definitions/misc/multiline_string"}, - "metadata": {"$ref": "#/definitions/misc/output_metadata"} - }, - "patternProperties": { - "^[a-zA-Z0-9]+/[a-zA-Z0-9\\-\\+\\.]+$": { - "description": "mimetype output (e.g. text/plain), represented as either an array of strings or a string.", - "$ref": "#/definitions/misc/multiline_string" - } - } - }, - - "display_data": { - "description": "Data displayed as a result of code cell execution.", - "type": "object", - "additionalProperties": false, - "required": ["output_type"], - "properties": { - "output_type": { - "description": "Type of cell output.", - "enum": ["display_data"] - }, - "text": {"$ref": "#/definitions/misc/multiline_string"}, - "latex": {"$ref": "#/definitions/misc/multiline_string"}, - "png": {"$ref": "#/definitions/misc/multiline_string"}, - "jpeg": {"$ref": "#/definitions/misc/multiline_string"}, - "svg": {"$ref": "#/definitions/misc/multiline_string"}, - "html": {"$ref": "#/definitions/misc/multiline_string"}, - "javascript": {"$ref": "#/definitions/misc/multiline_string"}, - "json": {"$ref": "#/definitions/misc/multiline_string"}, - "pdf": {"$ref": "#/definitions/misc/multiline_string"}, - "metadata": {"$ref": "#/definitions/misc/output_metadata"} - }, - "patternProperties": { - "[a-zA-Z0-9]+/[a-zA-Z0-9\\-\\+\\.]+$": { - "description": "mimetype output (e.g. text/plain), represented as either an array of strings or a string.", - "$ref": "#/definitions/misc/multiline_string" - } - } - }, - - "stream": { - "description": "Stream output from a code cell.", - "type": "object", - "additionalProperties": false, - "required": ["output_type", "stream", "text"], - "properties": { - "output_type": { - "description": "Type of cell output.", - "enum": ["stream"] - }, - "stream": { - "description": "The stream type/destination.", - "type": "string" - }, - "text": { - "description": "The stream's text output, represented as an array of strings.", - "$ref": "#/definitions/misc/multiline_string" - } - } - }, - - "pyerr": { - "description": "Output of an error that occurred during code cell execution.", - "type": "object", - "additionalProperties": false, - "required": ["output_type", "ename", "evalue", "traceback"], - "properties": { - "output_type": { - "description": "Type of cell output.", - "enum": ["pyerr"] - }, - "ename": { - "description": "The name of the error.", - "type": "string" - }, - "evalue": { - "description": "The value, or message, of the error.", - "type": "string" - }, - "traceback": { - "description": "The error's traceback, represented as an array of strings.", - "type": "array", - "items": {"type": "string"} - } - } - }, - - "misc": { - "metadata_name": { - "description": "The cell's name. If present, must be a non-empty string.", - "type": "string", - "pattern": "^.+$" - }, - "metadata_tags": { - "description": "The cell's tags. Tags must be unique, and must not contain commas.", - "type": "array", - "uniqueItems": true, - "items": { - "type": "string", - "pattern": "^[^,]+$" - } - }, - "source": { - "description": "Contents of the cell, represented as an array of lines.", - "$ref": "#/definitions/misc/multiline_string" - }, - "prompt_number": { - "description": "The code cell's prompt number. Will be null if the cell has not been run.", - "type": ["integer", "null"], - "minimum": 0 - }, - "mimetype": { - "patternProperties": { - "^[a-zA-Z0-9\\-\\+]+/[a-zA-Z0-9\\-\\+]+": { - "description": "The cell's mimetype output (e.g. text/plain), represented as either an array of strings or a string.", - "$ref": "#/definitions/misc/multiline_string" - } - } - }, - "output_metadata": { - "description": "Cell output metadata.", - "type": "object", - "additionalProperties": true - }, - "multiline_string": { - "oneOf" : [ - {"type": "string"}, - { - "type": "array", - "items": {"type": "string"} - } - ] - } - } - } -} diff --git a/jupyter_nbformat/v3/nbjson.py b/jupyter_nbformat/v3/nbjson.py deleted file mode 100644 index d63cbba..0000000 --- a/jupyter_nbformat/v3/nbjson.py +++ /dev/null @@ -1,60 +0,0 @@ -"""Read and write notebooks in JSON format.""" - -# Copyright (c) IPython Development Team. -# Distributed under the terms of the Modified BSD License. - -import copy -import json - -from .nbbase import from_dict -from .rwbase import ( - NotebookReader, NotebookWriter, restore_bytes, rejoin_lines, split_lines, - strip_transient, -) - -from IPython.utils import py3compat - - -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) - nb = strip_transient(nb) - return nb - - def to_notebook(self, d, **kwargs): - return rejoin_lines(from_dict(d)) - - -class JSONWriter(NotebookWriter): - - def writes(self, nb, **kwargs): - kwargs['cls'] = BytesEncoder - kwargs['indent'] = 1 - kwargs['sort_keys'] = True - kwargs['separators'] = (',',': ') - nb = copy.deepcopy(nb) - nb = strip_transient(nb) - if kwargs.pop('split_lines', True): - nb = split_lines(nb) - return py3compat.str_to_unicode(json.dumps(nb, **kwargs), 'utf-8') - - -_reader = JSONReader() -_writer = JSONWriter() - -reads = _reader.reads -read = _reader.read -to_notebook = _reader.to_notebook -write = _writer.write -writes = _writer.writes - diff --git a/jupyter_nbformat/v3/nbpy.py b/jupyter_nbformat/v3/nbpy.py deleted file mode 100644 index bd4a9ad..0000000 --- a/jupyter_nbformat/v3/nbpy.py +++ /dev/null @@ -1,204 +0,0 @@ -"""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 .rwbase import NotebookReader, NotebookWriter -from .nbbase import ( - new_code_cell, new_text_cell, new_worksheet, - new_notebook, new_heading_cell, nbformat, nbformat_minor, -) - -#----------------------------------------------------------------------------- -# 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 = [] - kwargs = {} - state = u'codecell' - for line in lines: - if line.startswith(u'# ') or _encoding_declaration_re.match(line): - pass - elif line.startswith(u'# '): - cell = self.new_cell(state, cell_lines, **kwargs) - if cell is not None: - cells.append(cell) - state = u'codecell' - cell_lines = [] - kwargs = {} - elif line.startswith(u'# '): - cell = self.new_cell(state, cell_lines, **kwargs) - if cell is not None: - cells.append(cell) - state = u'htmlcell' - cell_lines = [] - kwargs = {} - elif line.startswith(u'# '): - cell = self.new_cell(state, cell_lines, **kwargs) - if cell is not None: - cells.append(cell) - state = u'markdowncell' - cell_lines = [] - kwargs = {} - # VERSIONHACK: plaintext -> raw - elif line.startswith(u'# ') or line.startswith(u'# '): - cell = self.new_cell(state, cell_lines, **kwargs) - if cell is not None: - cells.append(cell) - state = u'rawcell' - cell_lines = [] - kwargs = {} - elif line.startswith(u'# \d)>',line) - if m is not None: - state = u'headingcell' - kwargs = {} - kwargs['level'] = int(m.group('level')) - else: - state = u'codecell' - kwargs = {} - cell_lines = [] - else: - cell_lines.append(line) - if cell_lines and state == u'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, **kwargs): - if state == u'codecell': - input = u'\n'.join(lines) - input = input.strip(u'\n') - if input: - return new_code_cell(input=input) - elif state == u'htmlcell': - text = self._remove_comments(lines) - if text: - return new_text_cell(u'html',source=text) - elif state == u'markdowncell': - text = self._remove_comments(lines) - if text: - return new_text_cell(u'markdown',source=text) - elif state == u'rawcell': - text = self._remove_comments(lines) - if text: - return new_text_cell(u'raw',source=text) - elif state == u'headingcell': - text = self._remove_comments(lines) - level = kwargs.get('level',1) - if text: - return new_heading_cell(source=text,level=level) - - def _remove_comments(self, lines): - new_lines = [] - for line in lines: - if line.startswith(u'#'): - new_lines.append(line[2:]) - else: - new_lines.append(line) - text = u'\n'.join(new_lines) - text = text.strip(u'\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 = [u'# -*- coding: utf-8 -*-'] - lines.extend([ - u'# %i.%i' % (nbformat, nbformat_minor), - u'', - ]) - for ws in nb.worksheets: - for cell in ws.cells: - if cell.cell_type == u'code': - input = cell.get(u'input') - if input is not None: - lines.extend([u'# ',u'']) - lines.extend(input.splitlines()) - lines.append(u'') - elif cell.cell_type == u'html': - input = cell.get(u'source') - if input is not None: - lines.extend([u'# ',u'']) - lines.extend([u'# ' + line for line in input.splitlines()]) - lines.append(u'') - elif cell.cell_type == u'markdown': - input = cell.get(u'source') - if input is not None: - lines.extend([u'# ',u'']) - lines.extend([u'# ' + line for line in input.splitlines()]) - lines.append(u'') - elif cell.cell_type == u'raw': - input = cell.get(u'source') - if input is not None: - lines.extend([u'# ',u'']) - lines.extend([u'# ' + line for line in input.splitlines()]) - lines.append(u'') - elif cell.cell_type == u'heading': - input = cell.get(u'source') - level = cell.get(u'level',1) - if input is not None: - lines.extend([u'# ' % level,u'']) - lines.extend([u'# ' + line for line in input.splitlines()]) - lines.append(u'') - lines.append('') - return u'\n'.join(lines) - - -_reader = PyReader() -_writer = PyWriter() - -reads = _reader.reads -read = _reader.read -to_notebook = _reader.to_notebook -write = _writer.write -writes = _writer.writes - diff --git a/jupyter_nbformat/v3/rwbase.py b/jupyter_nbformat/v3/rwbase.py deleted file mode 100644 index 8b0635b..0000000 --- a/jupyter_nbformat/v3/rwbase.py +++ /dev/null @@ -1,190 +0,0 @@ -"""Base classes and utilities for readers and writers.""" - -# Copyright (c) IPython Development Team. -# Distributed under the terms of the Modified BSD License. - -from base64 import encodestring, decodestring - -from IPython.utils import py3compat -from IPython.utils.py3compat import str_to_bytes, unicode_type, string_types - - -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. - - 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 = str_to_bytes(output.png, 'ascii') - if 'jpeg' in output: - output.jpeg = str_to_bytes(output.jpeg, 'ascii') - return nb - -# output keys that are likely to have multiline values -_multiline_outputs = ['text', 'html', 'svg', 'latex', 'javascript', 'json'] - - -# FIXME: workaround for old splitlines() -def _join_lines(lines): - """join lines that have been written by splitlines() - - Has logic to protect against `splitlines()`, which - should have been `splitlines(True)` - """ - if lines and lines[0].endswith(('\n', '\r')): - # created by splitlines(True) - return u''.join(lines) - else: - # created by splitlines() - return u'\n'.join(lines) - - -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 = _join_lines(cell.input) - for output in cell.outputs: - for key in _multiline_outputs: - item = output.get(key, None) - if isinstance(item, list): - output[key] = _join_lines(item) - else: # text, heading cell - for key in ['source', 'rendered']: - item = cell.get(key, None) - if isinstance(item, list): - cell[key] = _join_lines(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, string_types): - cell.input = cell.input.splitlines(True) - for output in cell.outputs: - for key in _multiline_outputs: - item = output.get(key, None) - if isinstance(item, string_types): - output[key] = item.splitlines(True) - else: # text, heading cell - for key in ['source', 'rendered']: - item = cell.get(key, None) - if isinstance(item, string_types): - cell[key] = item.splitlines(True) - 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, unicode_type): - output.png = output.png.encode('ascii') - output.png = decodestring(output.png) - if 'jpeg' in output: - if isinstance(output.jpeg, unicode_type): - output.jpeg = output.jpeg.encode('ascii') - output.jpeg = decodestring(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 = encodestring(output.png).decode('ascii') - if 'jpeg' in output: - output.jpeg = encodestring(output.jpeg).decode('ascii') - return nb - - -def strip_transient(nb): - """Strip transient values that shouldn't be stored in files. - - This should be called in *both* read and write. - """ - nb.pop('orig_nbformat', None) - nb.pop('orig_nbformat_minor', None) - for ws in nb['worksheets']: - for cell in ws['cells']: - cell.get('metadata', {}).pop('trusted', None) - # strip cell.trusted even though it shouldn't be used, - # since it's where the transient value used to be stored. - cell.pop('trusted', None) - return nb - - -class NotebookReader(object): - """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""" - nbs = fp.read() - if not py3compat.PY3 and not isinstance(nbs, unicode_type): - nbs = py3compat.str_to_unicode(nbs) - return self.reads(nbs, **kwargs) - - -class NotebookWriter(object): - """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""" - nbs = self.writes(nb,**kwargs) - if not py3compat.PY3 and not isinstance(nbs, unicode_type): - # this branch is likely only taken for JSON on Python 2 - nbs = py3compat.str_to_unicode(nbs) - return fp.write(nbs) - - - diff --git a/jupyter_nbformat/v3/tests/__init__.py b/jupyter_nbformat/v3/tests/__init__.py deleted file mode 100644 index e69de29..0000000 --- a/jupyter_nbformat/v3/tests/__init__.py +++ /dev/null diff --git a/jupyter_nbformat/v3/tests/formattest.py b/jupyter_nbformat/v3/tests/formattest.py deleted file mode 100644 index e866758..0000000 --- a/jupyter_nbformat/v3/tests/formattest.py +++ /dev/null @@ -1,63 +0,0 @@ -# -*- coding: utf8 -*- -import io -import os -import shutil -import tempfile - -pjoin = os.path.join - -from ..nbbase import ( - NotebookNode, - new_code_cell, new_text_cell, new_worksheet, new_notebook -) - -from ..nbpy import reads, writes, read, write -from .nbexamples import nb0, nb0_py - - -def open_utf8(fname, mode): - return io.open(fname, mode=mode, encoding='utf-8') - -class NBFormatTest: - """Mixin for writing notebook format tests""" - - # override with appropriate values in subclasses - nb0_ref = None - ext = None - mod = None - - def setUp(self): - self.wd = tempfile.mkdtemp() - - def tearDown(self): - shutil.rmtree(self.wd) - - def assertNBEquals(self, nba, nbb): - self.assertEqual(nba, nbb) - - def test_writes(self): - s = self.mod.writes(nb0) - if self.nb0_ref: - self.assertEqual(s, self.nb0_ref) - - def test_reads(self): - s = self.mod.writes(nb0) - nb = self.mod.reads(s) - - def test_roundtrip(self): - s = self.mod.writes(nb0) - self.assertNBEquals(self.mod.reads(s),nb0) - - def test_write_file(self): - with open_utf8(pjoin(self.wd, "nb0.%s" % self.ext), 'w') as f: - self.mod.write(nb0, f) - - def test_read_file(self): - with open_utf8(pjoin(self.wd, "nb0.%s" % self.ext), 'w') as f: - self.mod.write(nb0, f) - - with open_utf8(pjoin(self.wd, "nb0.%s" % self.ext), 'r') as f: - nb = self.mod.read(f) - - - diff --git a/jupyter_nbformat/v3/tests/nbexamples.py b/jupyter_nbformat/v3/tests/nbexamples.py deleted file mode 100644 index 898a032..0000000 --- a/jupyter_nbformat/v3/tests/nbexamples.py +++ /dev/null @@ -1,152 +0,0 @@ -# -*- coding: utf-8 -*- - -import os -from base64 import encodestring - -from ..nbbase import ( - NotebookNode, - new_code_cell, new_text_cell, new_worksheet, new_notebook, new_output, - new_metadata, new_author, new_heading_cell, nbformat, nbformat_minor -) - -# some random base64-encoded *text* -png = encodestring(os.urandom(5)).decode('ascii') -jpeg = encodestring(os.urandom(6)).decode('ascii') - -ws = new_worksheet() - -ws.cells.append(new_text_cell( - u'html', - source='Some NumPy Examples', -)) - - -ws.cells.append(new_code_cell( - input='import numpy', - prompt_number=1, - collapsed=False -)) - -ws.cells.append(new_text_cell( - u'markdown', - source='A random array', -)) - -ws.cells.append(new_text_cell( - u'raw', - source='A random array', -)) - -ws.cells.append(new_heading_cell( - u'My Heading', - level=2 -)) - -ws.cells.append(new_code_cell( - input='a = numpy.random.rand(100)', - prompt_number=2, - collapsed=True -)) -ws.cells.append(new_code_cell( - input='a = 10\nb = 5\n', - prompt_number=3, -)) -ws.cells.append(new_code_cell( - input='a = 10\nb = 5', - prompt_number=4, -)) - -ws.cells.append(new_code_cell( - input=u'print "ünîcødé"', - prompt_number=3, - collapsed=False, - outputs=[new_output( - output_type=u'pyout', - output_text=u'', - output_html=u'The HTML rep', - output_latex=u'$a$', - output_png=png, - output_jpeg=jpeg, - output_svg=u'', - output_json=u'{"json": "data"}', - output_javascript=u'var i=0;', - prompt_number=3 - ),new_output( - output_type=u'display_data', - output_text=u'', - output_html=u'The HTML rep', - output_latex=u'$a$', - output_png=png, - output_jpeg=jpeg, - output_svg=u'', - output_json=u'{"json": "data"}', - output_javascript=u'var i=0;' - ),new_output( - output_type=u'pyerr', - ename=u'NameError', - evalue=u'NameError was here', - traceback=[u'frame 0', u'frame 1', u'frame 2'] - ),new_output( - output_type=u'stream', - output_text='foo\rbar\r\n' - ),new_output( - output_type=u'stream', - stream='stderr', - output_text='\rfoo\rbar\n' - )] -)) - -authors = [new_author(name='Bart Simpson',email='bsimpson@fox.com', - affiliation=u'Fox',url=u'http://www.fox.com')] -md = new_metadata(name=u'My Notebook',license=u'BSD',created=u'8601_goes_here', - modified=u'8601_goes_here',gistid=u'21341231',authors=authors) - -nb0 = new_notebook( - worksheets=[ws, new_worksheet()], - metadata=md -) - -nb0_py = u"""# -*- coding: utf-8 -*- -# %i.%i - -# - -# Some NumPy Examples - -# - -import numpy - -# - -# A random array - -# - -# A random array - -# - -# My Heading - -# - -a = numpy.random.rand(100) - -# - -a = 10 -b = 5 - -# - -a = 10 -b = 5 - -# - -print "ünîcødé" - -""" % (nbformat, nbformat_minor) - - diff --git a/jupyter_nbformat/v3/tests/test_json.py b/jupyter_nbformat/v3/tests/test_json.py deleted file mode 100644 index cd8c76e..0000000 --- a/jupyter_nbformat/v3/tests/test_json.py +++ /dev/null @@ -1,103 +0,0 @@ -import copy -import json -from base64 import decodestring -from unittest import TestCase - -from IPython.utils.py3compat import unicode_type -from ..nbjson import reads, writes -from ..nbbase import from_dict -from .. import nbjson -from .nbexamples import nb0 - -from . import formattest - -from .nbexamples import nb0 - - -class TestJSON(formattest.NBFormatTest, TestCase): - - nb0_ref = None - ext = 'ipynb' - mod = nbjson - - def test_roundtrip_nosplit(self): - """Ensure that multiline blobs are still readable""" - # ensures that notebooks written prior to splitlines change - # are still readable. - s = writes(nb0, split_lines=False) - self.assertEqual(nbjson.reads(s),nb0) - - def test_roundtrip_split(self): - """Ensure that splitting multiline blocks is safe""" - # This won't differ from test_roundtrip unless the default changes - s = writes(nb0, split_lines=True) - self.assertEqual(nbjson.reads(s),nb0) - - def test_strip_transient(self): - """transient values aren't written to files""" - nb = copy.deepcopy(nb0) - nb.orig_nbformat = 2 - nb.orig_nbformat_minor = 3 - nb.worksheets[0].cells[0].metadata.trusted = False - nbs = nbjson.writes(nb) - - nb2 = from_dict(json.loads(nbs)) - self.assertNotIn('orig_nbformat', nb2) - self.assertNotIn('orig_nbformat_minor', nb2) - for cell in nb2.worksheets[0].cells: - self.assertNotIn('trusted', cell.metadata) - - def test_to_json(self): - """to_notebook_json doesn't strip transient""" - nb = copy.deepcopy(nb0) - nb.orig_nbformat = 2 - nb.orig_nbformat_minor = 3 - nb.worksheets[0].cells[0].metadata.trusted = False - nbs = json.dumps(nb) - nb2 = nbjson.to_notebook(json.loads(nbs)) - - nb2 = from_dict(json.loads(nbs)) - self.assertIn('orig_nbformat', nb2) - self.assertIn('orig_nbformat_minor', nb2) - cell = nb2.worksheets[0].cells[0] - self.assertIn('trusted', cell.metadata) - - def test_read_png(self): - """PNG output data is b64 unicode""" - s = writes(nb0) - nb1 = nbjson.reads(s) - found_png = False - for cell in nb1.worksheets[0].cells: - if not 'outputs' in cell: - continue - for output in cell.outputs: - if 'png' in output: - found_png = True - pngdata = output['png'] - self.assertEqual(type(pngdata), unicode_type) - # test that it is valid b64 data - b64bytes = pngdata.encode('ascii') - raw_bytes = decodestring(b64bytes) - assert found_png, "never found png output" - - def test_read_jpeg(self): - """JPEG output data is b64 unicode""" - s = writes(nb0) - nb1 = nbjson.reads(s) - found_jpeg = False - for cell in nb1.worksheets[0].cells: - if not 'outputs' in cell: - continue - for output in cell.outputs: - if 'jpeg' in output: - found_jpeg = True - jpegdata = output['jpeg'] - self.assertEqual(type(jpegdata), unicode_type) - # test that it is valid b64 data - b64bytes = jpegdata.encode('ascii') - raw_bytes = decodestring(b64bytes) - assert found_jpeg, "never found jpeg output" - - - - diff --git a/jupyter_nbformat/v3/tests/test_misc.py b/jupyter_nbformat/v3/tests/test_misc.py deleted file mode 100644 index 3eaf5ac..0000000 --- a/jupyter_nbformat/v3/tests/test_misc.py +++ /dev/null @@ -1,33 +0,0 @@ -import os -from unittest import TestCase - -from IPython.utils.py3compat import unicode_type -from .. import parse_filename - - -class MiscTests(TestCase): - - def check_filename(self, path, exp_fname, exp_bname, exp_format): - fname, bname, format = parse_filename(path) - self.assertEqual(fname, exp_fname) - self.assertEqual(bname, exp_bname) - self.assertEqual(format, exp_format) - - def test_parse_filename(self): - - # check format detection - self.check_filename("test.ipynb", "test.ipynb", "test", "json") - self.check_filename("test.json", "test.json", "test", "json") - self.check_filename("test.py", "test.py", "test", "py") - - # check parsing an unknown format - self.check_filename("test.nb", "test.nb.ipynb", "test.nb", "json") - - # check parsing a full file path - abs_path = os.path.abspath("test.ipynb") - basename, ext = os.path.splitext(abs_path) - self.check_filename(abs_path, abs_path, basename, "json") - - # check parsing a file name containing dots - self.check_filename("test.nb.ipynb", "test.nb.ipynb", "test.nb", - "json") diff --git a/jupyter_nbformat/v3/tests/test_nbbase.py b/jupyter_nbformat/v3/tests/test_nbbase.py deleted file mode 100644 index 0526657..0000000 --- a/jupyter_nbformat/v3/tests/test_nbbase.py +++ /dev/null @@ -1,148 +0,0 @@ -from unittest import TestCase - -from ..nbbase import ( - NotebookNode, - new_code_cell, new_text_cell, new_worksheet, new_notebook, new_output, - new_author, new_metadata, new_heading_cell, nbformat -) - -class TestCell(TestCase): - - def test_empty_code_cell(self): - cc = new_code_cell() - self.assertEqual(cc.cell_type,u'code') - self.assertEqual(u'input' not in cc, True) - self.assertEqual(u'prompt_number' not in cc, True) - self.assertEqual(cc.outputs, []) - self.assertEqual(cc.collapsed, False) - - def test_code_cell(self): - cc = new_code_cell(input='a=10', prompt_number=0, collapsed=True) - cc.outputs = [new_output(output_type=u'pyout', - output_svg=u'foo',output_text=u'10',prompt_number=0)] - self.assertEqual(cc.input, u'a=10') - self.assertEqual(cc.prompt_number, 0) - self.assertEqual(cc.language, u'python') - self.assertEqual(cc.outputs[0].svg, u'foo') - self.assertEqual(cc.outputs[0].text, u'10') - self.assertEqual(cc.outputs[0].prompt_number, 0) - self.assertEqual(cc.collapsed, True) - - def test_pyerr(self): - o = new_output(output_type=u'pyerr', ename=u'NameError', - evalue=u'Name not found', traceback=[u'frame 0', u'frame 1', u'frame 2'] - ) - self.assertEqual(o.output_type, u'pyerr') - self.assertEqual(o.ename, u'NameError') - self.assertEqual(o.evalue, u'Name not found') - self.assertEqual(o.traceback, [u'frame 0', u'frame 1', u'frame 2']) - - def test_empty_html_cell(self): - tc = new_text_cell(u'html') - self.assertEqual(tc.cell_type, u'html') - self.assertEqual(u'source' not in tc, True) - - def test_html_cell(self): - tc = new_text_cell(u'html', 'hi') - self.assertEqual(tc.source, u'hi') - - def test_empty_markdown_cell(self): - tc = new_text_cell(u'markdown') - self.assertEqual(tc.cell_type, u'markdown') - self.assertEqual(u'source' not in tc, True) - - def test_markdown_cell(self): - tc = new_text_cell(u'markdown', 'hi') - self.assertEqual(tc.source, u'hi') - - def test_empty_raw_cell(self): - tc = new_text_cell(u'raw') - self.assertEqual(tc.cell_type, u'raw') - self.assertEqual(u'source' not in tc, True) - - def test_raw_cell(self): - tc = new_text_cell(u'raw', 'hi') - self.assertEqual(tc.source, u'hi') - - def test_empty_heading_cell(self): - tc = new_heading_cell() - self.assertEqual(tc.cell_type, u'heading') - self.assertEqual(u'source' not in tc, True) - - def test_heading_cell(self): - tc = new_heading_cell(u'hi', level=2) - self.assertEqual(tc.source, u'hi') - self.assertEqual(tc.level, 2) - - -class TestWorksheet(TestCase): - - def test_empty_worksheet(self): - ws = new_worksheet() - self.assertEqual(ws.cells,[]) - self.assertEqual(u'name' not in ws, True) - - def test_worksheet(self): - cells = [new_code_cell(), new_text_cell(u'html')] - ws = new_worksheet(cells=cells) - self.assertEqual(ws.cells,cells) - -class TestNotebook(TestCase): - - def test_empty_notebook(self): - nb = new_notebook() - self.assertEqual(nb.worksheets, []) - self.assertEqual(nb.metadata, NotebookNode()) - self.assertEqual(nb.nbformat,nbformat) - - def test_notebook(self): - worksheets = [new_worksheet(),new_worksheet()] - metadata = new_metadata(name=u'foo') - nb = new_notebook(metadata=metadata,worksheets=worksheets) - self.assertEqual(nb.metadata.name,u'foo') - self.assertEqual(nb.worksheets,worksheets) - self.assertEqual(nb.nbformat,nbformat) - - def test_notebook_name(self): - worksheets = [new_worksheet(),new_worksheet()] - nb = new_notebook(name='foo',worksheets=worksheets) - self.assertEqual(nb.metadata.name,u'foo') - self.assertEqual(nb.worksheets,worksheets) - self.assertEqual(nb.nbformat,nbformat) - -class TestMetadata(TestCase): - - def test_empty_metadata(self): - md = new_metadata() - self.assertEqual(u'name' not in md, True) - self.assertEqual(u'authors' not in md, True) - self.assertEqual(u'license' not in md, True) - self.assertEqual(u'saved' not in md, True) - self.assertEqual(u'modified' not in md, True) - self.assertEqual(u'gistid' not in md, True) - - def test_metadata(self): - authors = [new_author(name='Bart Simpson',email='bsimpson@fox.com')] - md = new_metadata(name=u'foo',license=u'BSD',created=u'today', - modified=u'now',gistid=u'21341231',authors=authors) - self.assertEqual(md.name, u'foo') - self.assertEqual(md.license, u'BSD') - self.assertEqual(md.created, u'today') - self.assertEqual(md.modified, u'now') - self.assertEqual(md.gistid, u'21341231') - self.assertEqual(md.authors, authors) - -class TestOutputs(TestCase): - def test_binary_png(self): - out = new_output(output_png=b'\x89PNG\r\n\x1a\n', output_type='display_data') - - def test_b64b6tes_png(self): - out = new_output(output_png=b'iVBORw0KG', output_type='display_data') - - def test_binary_jpeg(self): - out = new_output(output_jpeg=b'\xff\xd8', output_type='display_data') - - def test_b64b6tes_jpeg(self): - out = new_output(output_jpeg=b'/9', output_type='display_data') - - diff --git a/jupyter_nbformat/v3/tests/test_nbpy.py b/jupyter_nbformat/v3/tests/test_nbpy.py deleted file mode 100644 index fbe6e2f..0000000 --- a/jupyter_nbformat/v3/tests/test_nbpy.py +++ /dev/null @@ -1,48 +0,0 @@ -# -*- coding: utf8 -*- - -from unittest import TestCase - -from IPython.utils.py3compat import string_types, iteritems - -from . import formattest - -from .. import nbpy -from .nbexamples import nb0, nb0_py - - -class TestPy(formattest.NBFormatTest, TestCase): - - nb0_ref = nb0_py - ext = 'py' - mod = nbpy - ignored_keys = ['collapsed', 'outputs', 'prompt_number', 'metadata'] - - def assertSubset(self, da, db): - """assert that da is a subset of db, ignoring self.ignored_keys. - - Called recursively on containers, ultimately comparing individual - elements. - """ - if isinstance(da, dict): - for k,v in iteritems(da): - if k in self.ignored_keys: - continue - self.assertTrue(k in db) - self.assertSubset(v, db[k]) - elif isinstance(da, list): - for a,b in zip(da, db): - self.assertSubset(a,b) - else: - if isinstance(da, string_types) and isinstance(db, string_types): - # pyfile is not sensitive to preserving leading/trailing - # newlines in blocks through roundtrip - da = da.strip('\n') - db = db.strip('\n') - self.assertEqual(da, db) - return True - - def assertNBEquals(self, nba, nbb): - # since roundtrip is lossy, only compare keys that are preserved - # assumes nba is read from my file format - return self.assertSubset(nba, nbb) - diff --git a/jupyter_nbformat/v4/__init__.py b/jupyter_nbformat/v4/__init__.py deleted file mode 100644 index 03a517e..0000000 --- a/jupyter_nbformat/v4/__init__.py +++ /dev/null @@ -1,23 +0,0 @@ -"""The main API for the v4 notebook format.""" - -# Copyright (c) IPython Development Team. -# Distributed under the terms of the Modified BSD License. - -__all__ = ['nbformat', 'nbformat_minor', 'nbformat_schema', 'new_code_cell', - 'new_markdown_cell', 'new_notebook', 'new_output', 'output_from_msg', - 'reads', 'writes', 'to_notebook', 'downgrade', 'upgrade'] - -from .nbbase import ( - nbformat, nbformat_minor, nbformat_schema, - new_code_cell, new_markdown_cell, new_notebook, - new_output, output_from_msg, -) - -from .nbjson import reads, writes, to_notebook -reads_json = reads -writes_json = writes -to_notebook_json = to_notebook - -from .convert import downgrade, upgrade - - diff --git a/jupyter_nbformat/v4/convert.py b/jupyter_nbformat/v4/convert.py deleted file mode 100644 index b25efd9..0000000 --- a/jupyter_nbformat/v4/convert.py +++ /dev/null @@ -1,253 +0,0 @@ -"""Code for converting notebooks to and from v3.""" - -# Copyright (c) IPython Development Team. -# Distributed under the terms of the Modified BSD License. - -import json -import re - -from .nbbase import ( - nbformat, nbformat_minor, - NotebookNode, -) - -from jupyter_nbformat import v3 -from IPython.utils.log import get_logger - -def _warn_if_invalid(nb, version): - """Log validation errors, if there are any.""" - from IPython.nbformat import validate, ValidationError - try: - validate(nb, version=version) - except ValidationError as e: - get_logger().error("Notebook JSON is not valid v%i: %s", version, e) - -def upgrade(nb, from_version=3, from_minor=0): - """Convert a notebook to v4. - - Parameters - ---------- - nb : NotebookNode - The Python representation of the notebook to convert. - from_version : int - The original version of the notebook to convert. - from_minor : int - The original minor version of the notebook to convert (only relevant for v >= 3). - """ - if from_version == 3: - # Validate the notebook before conversion - _warn_if_invalid(nb, from_version) - - # Mark the original nbformat so consumers know it has been converted - orig_nbformat = nb.pop('orig_nbformat', None) - nb.metadata.orig_nbformat = orig_nbformat or 3 - - # Mark the new format - nb.nbformat = nbformat - nb.nbformat_minor = nbformat_minor - - # remove worksheet(s) - nb['cells'] = cells = [] - # In the unlikely event of multiple worksheets, - # they will be flattened - for ws in nb.pop('worksheets', []): - # upgrade each cell - for cell in ws['cells']: - cells.append(upgrade_cell(cell)) - # upgrade metadata - nb.metadata.pop('name', '') - nb.metadata.pop('signature', '') - # Validate the converted notebook before returning it - _warn_if_invalid(nb, nbformat) - return nb - elif from_version == 4: - # nothing to do - if from_minor != nbformat_minor: - nb.metadata.orig_nbformat_minor = from_minor - nb.nbformat_minor = nbformat_minor - - return nb - else: - raise ValueError('Cannot convert a notebook directly from v%s to v4. ' \ - 'Try using the IPython.nbformat.convert module.' % from_version) - -def upgrade_cell(cell): - """upgrade a cell from v3 to v4 - - heading cell: - - -> markdown heading - code cell: - - remove language metadata - - cell.input -> cell.source - - cell.prompt_number -> cell.execution_count - - update outputs - """ - cell.setdefault('metadata', NotebookNode()) - if cell.cell_type == 'code': - cell.pop('language', '') - if 'collapsed' in cell: - cell.metadata['collapsed'] = cell.pop('collapsed') - cell.source = cell.pop('input', '') - cell.execution_count = cell.pop('prompt_number', None) - cell.outputs = upgrade_outputs(cell.outputs) - elif cell.cell_type == 'heading': - cell.cell_type = 'markdown' - level = cell.pop('level', 1) - cell.source = u'{hashes} {single_line}'.format( - hashes='#' * level, - single_line = ' '.join(cell.get('source', '').splitlines()), - ) - elif cell.cell_type == 'html': - # Technically, this exists. It will never happen in practice. - cell.cell_type = 'markdown' - return cell - -def downgrade_cell(cell): - """downgrade a cell from v4 to v3 - - code cell: - - set cell.language - - cell.input <- cell.source - - cell.prompt_number <- cell.execution_count - - update outputs - markdown cell: - - single-line heading -> heading cell - """ - if cell.cell_type == 'code': - cell.language = 'python' - cell.input = cell.pop('source', '') - cell.prompt_number = cell.pop('execution_count', None) - cell.collapsed = cell.metadata.pop('collapsed', False) - cell.outputs = downgrade_outputs(cell.outputs) - elif cell.cell_type == 'markdown': - source = cell.get('source', '') - if '\n' not in source and source.startswith('#'): - prefix, text = re.match(r'(#+)\s*(.*)', source).groups() - cell.cell_type = 'heading' - cell.source = text - cell.level = len(prefix) - return cell - -_mime_map = { - "text" : "text/plain", - "html" : "text/html", - "svg" : "image/svg+xml", - "png" : "image/png", - "jpeg" : "image/jpeg", - "latex" : "text/latex", - "json" : "application/json", - "javascript" : "application/javascript", -}; - -def to_mime_key(d): - """convert dict with v3 aliases to plain mime-type keys""" - for alias, mime in _mime_map.items(): - if alias in d: - d[mime] = d.pop(alias) - return d - -def from_mime_key(d): - """convert dict with mime-type keys to v3 aliases""" - for alias, mime in _mime_map.items(): - if mime in d: - d[alias] = d.pop(mime) - return d - -def upgrade_output(output): - """upgrade a single code cell output from v3 to v4 - - - pyout -> execute_result - - pyerr -> error - - output.type -> output.data.mime/type - - mime-type keys - - stream.stream -> stream.name - """ - if output['output_type'] in {'pyout', 'display_data'}: - output.setdefault('metadata', NotebookNode()) - if output['output_type'] == 'pyout': - output['output_type'] = 'execute_result' - output['execution_count'] = output.pop('prompt_number', None) - - # move output data into data sub-dict - data = {} - for key in list(output): - if key in {'output_type', 'execution_count', 'metadata'}: - continue - data[key] = output.pop(key) - to_mime_key(data) - output['data'] = data - to_mime_key(output.metadata) - if 'application/json' in data: - data['application/json'] = json.loads(data['application/json']) - # promote ascii bytes (from v2) to unicode - for key in ('image/png', 'image/jpeg'): - if key in data and isinstance(data[key], bytes): - data[key] = data[key].decode('ascii') - elif output['output_type'] == 'pyerr': - output['output_type'] = 'error' - elif output['output_type'] == 'stream': - output['name'] = output.pop('stream', 'stdout') - return output - -def downgrade_output(output): - """downgrade a single code cell output to v3 from v4 - - - pyout <- execute_result - - pyerr <- error - - output.data.mime/type -> output.type - - un-mime-type keys - - stream.stream <- stream.name - """ - if output['output_type'] in {'execute_result', 'display_data'}: - if output['output_type'] == 'execute_result': - output['output_type'] = 'pyout' - output['prompt_number'] = output.pop('execution_count', None) - - # promote data dict to top-level output namespace - data = output.pop('data', {}) - if 'application/json' in data: - data['application/json'] = json.dumps(data['application/json']) - from_mime_key(data) - output.update(data) - from_mime_key(output.get('metadata', {})) - elif output['output_type'] == 'error': - output['output_type'] = 'pyerr' - elif output['output_type'] == 'stream': - output['stream'] = output.pop('name') - return output - -def upgrade_outputs(outputs): - """upgrade outputs of a code cell from v3 to v4""" - return [upgrade_output(op) for op in outputs] - -def downgrade_outputs(outputs): - """downgrade outputs of a code cell to v3 from v4""" - return [downgrade_output(op) for op in outputs] - -def downgrade(nb): - """Convert a v4 notebook to v3. - - Parameters - ---------- - nb : NotebookNode - The Python representation of the notebook to convert. - """ - if nb.nbformat != nbformat: - return nb - - # Validate the notebook before conversion - _warn_if_invalid(nb, nbformat) - - nb.nbformat = v3.nbformat - nb.nbformat_minor = v3.nbformat_minor - cells = [ downgrade_cell(cell) for cell in nb.pop('cells') ] - nb.worksheets = [v3.new_worksheet(cells=cells)] - nb.metadata.setdefault('name', '') - - # Validate the converted notebook before returning it - _warn_if_invalid(nb, v3.nbformat) - - nb.orig_nbformat = nb.metadata.pop('orig_nbformat', nbformat) - nb.orig_nbformat_minor = nb.metadata.pop('orig_nbformat_minor', nbformat_minor) - - return nb diff --git a/jupyter_nbformat/v4/nbbase.py b/jupyter_nbformat/v4/nbbase.py deleted file mode 100644 index 1827bf7..0000000 --- a/jupyter_nbformat/v4/nbbase.py +++ /dev/null @@ -1,137 +0,0 @@ -"""Python API for composing notebook elements - -The Python representation of a notebook is a nested structure of -dictionary subclasses that support attribute access -(IPython.utils.ipstruct.Struct). The functions in this module are merely -helpers to build the structs in the right form. -""" - -# Copyright (c) IPython Development Team. -# Distributed under the terms of the Modified BSD License. - -from ..notebooknode import from_dict, NotebookNode - -# Change this when incrementing the nbformat version -nbformat = 4 -nbformat_minor = 0 -nbformat_schema = 'nbformat.v4.schema.json' - - -def validate(node, ref=None): - """validate a v4 node""" - from .. import validate - return validate(node, ref=ref, version=nbformat) - - -def new_output(output_type, data=None, **kwargs): - """Create a new output, to go in the ``cell.outputs`` list of a code cell.""" - output = NotebookNode(output_type=output_type) - - # populate defaults: - if output_type == 'stream': - output.name = u'stdout' - output.text = u'' - elif output_type in {'execute_result', 'display_data'}: - output.metadata = NotebookNode() - output.data = NotebookNode() - # load from args: - output.update(from_dict(kwargs)) - if data is not None: - output.data = from_dict(data) - # validate - validate(output, output_type) - return output - - -def output_from_msg(msg): - """Create a NotebookNode for an output from a kernel's IOPub message. - - Returns - ------- - - NotebookNode: the output as a notebook node. - - Raises - ------ - - ValueError: if the message is not an output message. - - """ - msg_type = msg['header']['msg_type'] - content = msg['content'] - - if msg_type == 'execute_result': - return new_output(output_type=msg_type, - metadata=content['metadata'], - data=content['data'], - execution_count=content['execution_count'], - ) - elif msg_type == 'stream': - return new_output(output_type=msg_type, - name=content['name'], - text=content['text'], - ) - elif msg_type == 'display_data': - return new_output(output_type=msg_type, - metadata=content['metadata'], - data=content['data'], - ) - elif msg_type == 'error': - return new_output(output_type=msg_type, - ename=content['ename'], - evalue=content['evalue'], - traceback=content['traceback'], - ) - else: - raise ValueError("Unrecognized output msg type: %r" % msg_type) - - -def new_code_cell(source='', **kwargs): - """Create a new code cell""" - cell = NotebookNode( - cell_type='code', - metadata=NotebookNode(), - execution_count=None, - source=source, - outputs=[], - ) - cell.update(from_dict(kwargs)) - - validate(cell, 'code_cell') - return cell - -def new_markdown_cell(source='', **kwargs): - """Create a new markdown cell""" - cell = NotebookNode( - cell_type='markdown', - source=source, - metadata=NotebookNode(), - ) - cell.update(from_dict(kwargs)) - - validate(cell, 'markdown_cell') - return cell - -def new_raw_cell(source='', **kwargs): - """Create a new raw cell""" - cell = NotebookNode( - cell_type='raw', - source=source, - metadata=NotebookNode(), - ) - cell.update(from_dict(kwargs)) - - validate(cell, 'raw_cell') - return cell - -def new_notebook(**kwargs): - """Create a new notebook""" - nb = NotebookNode( - nbformat=nbformat, - nbformat_minor=nbformat_minor, - metadata=NotebookNode(), - cells=[], - ) - nb.update(from_dict(kwargs)) - validate(nb) - return nb diff --git a/jupyter_nbformat/v4/nbformat.v4.schema.json b/jupyter_nbformat/v4/nbformat.v4.schema.json deleted file mode 100644 index 5a150bf..0000000 --- a/jupyter_nbformat/v4/nbformat.v4.schema.json +++ /dev/null @@ -1,371 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "IPython Notebook v4.0 JSON schema.", - "type": "object", - "additionalProperties": false, - "required": ["metadata", "nbformat_minor", "nbformat", "cells"], - "properties": { - "metadata": { - "description": "Notebook root-level metadata.", - "type": "object", - "additionalProperties": true, - "properties": { - "kernelspec": { - "description": "Kernel information.", - "type": "object", - "required": ["name", "display_name"], - "properties": { - "name": { - "description": "Name of the kernel specification.", - "type": "string" - }, - "display_name": { - "description": "Name to display in UI.", - "type": "string" - } - } - }, - "language_info": { - "description": "Kernel information.", - "type": "object", - "required": ["name"], - "properties": { - "name": { - "description": "The programming language which this kernel runs.", - "type": "string" - }, - "codemirror_mode": { - "description": "The codemirror mode to use for code in this language.", - "oneOf": [ - {"type": "string"}, - {"type": "object"} - ] - }, - "file_extension": { - "description": "The file extension for files in this language.", - "type": "string" - }, - "mimetype": { - "description": "The mimetype corresponding to files in this language.", - "type": "string" - }, - "pygments_lexer": { - "description": "The pygments lexer to use for code in this language.", - "type": "string" - } - } - }, - "orig_nbformat": { - "description": "Original notebook format (major number) before converting the notebook between versions. This should never be written to a file.", - "type": "integer", - "minimum": 1 - } - } - }, - "nbformat_minor": { - "description": "Notebook format (minor number). Incremented for backward compatible changes to the notebook format.", - "type": "integer", - "minimum": 0 - }, - "nbformat": { - "description": "Notebook format (major number). Incremented between backwards incompatible changes to the notebook format.", - "type": "integer", - "minimum": 4, - "maximum": 4 - }, - "cells": { - "description": "Array of cells of the current notebook.", - "type": "array", - "items": {"$ref": "#/definitions/cell"} - } - }, - - "definitions": { - "cell": { - "type": "object", - "oneOf": [ - {"$ref": "#/definitions/raw_cell"}, - {"$ref": "#/definitions/markdown_cell"}, - {"$ref": "#/definitions/code_cell"} - ] - }, - - "raw_cell": { - "description": "Notebook raw nbconvert cell.", - "type": "object", - "additionalProperties": false, - "required": ["cell_type", "metadata", "source"], - "properties": { - "cell_type": { - "description": "String identifying the type of cell.", - "enum": ["raw"] - }, - "metadata": { - "description": "Cell-level metadata.", - "type": "object", - "additionalProperties": true, - "properties": { - "format": { - "description": "Raw cell metadata format for nbconvert.", - "type": "string" - }, - "name": {"$ref": "#/definitions/misc/metadata_name"}, - "tags": {"$ref": "#/definitions/misc/metadata_tags"} - } - }, - "source": {"$ref": "#/definitions/misc/source"} - } - }, - - "markdown_cell": { - "description": "Notebook markdown cell.", - "type": "object", - "additionalProperties": false, - "required": ["cell_type", "metadata", "source"], - "properties": { - "cell_type": { - "description": "String identifying the type of cell.", - "enum": ["markdown"] - }, - "metadata": { - "description": "Cell-level metadata.", - "type": "object", - "properties": { - "name": {"$ref": "#/definitions/misc/metadata_name"}, - "tags": {"$ref": "#/definitions/misc/metadata_tags"} - }, - "additionalProperties": true - }, - "source": {"$ref": "#/definitions/misc/source"} - } - }, - - "code_cell": { - "description": "Notebook code cell.", - "type": "object", - "additionalProperties": false, - "required": ["cell_type", "metadata", "source", "outputs", "execution_count"], - "properties": { - "cell_type": { - "description": "String identifying the type of cell.", - "enum": ["code"] - }, - "metadata": { - "description": "Cell-level metadata.", - "type": "object", - "additionalProperties": true, - "properties": { - "collapsed": { - "description": "Whether the cell is collapsed/expanded.", - "type": "boolean" - }, - "scrolled": { - "description": "Whether the cell's output is scrolled, unscrolled, or autoscrolled.", - "enum": [true, false, "auto"] - }, - "name": {"$ref": "#/definitions/misc/metadata_name"}, - "tags": {"$ref": "#/definitions/misc/metadata_tags"} - } - }, - "source": {"$ref": "#/definitions/misc/source"}, - "outputs": { - "description": "Execution, display, or stream outputs.", - "type": "array", - "items": {"$ref": "#/definitions/output"} - }, - "execution_count": { - "description": "The code cell's prompt number. Will be null if the cell has not been run.", - "type": ["integer", "null"], - "minimum": 0 - } - } - }, - - "unrecognized_cell": { - "description": "Unrecognized cell from a future minor-revision to the notebook format.", - "type": "object", - "additionalProperties": true, - "required": ["cell_type", "metadata"], - "properties": { - "cell_type": { - "description": "String identifying the type of cell.", - "not" : { - "enum": ["markdown", "code", "raw"] - } - }, - "metadata": { - "description": "Cell-level metadata.", - "type": "object", - "properties": { - "name": {"$ref": "#/definitions/misc/metadata_name"}, - "tags": {"$ref": "#/definitions/misc/metadata_tags"} - }, - "additionalProperties": true - } - } - }, - - "output": { - "type": "object", - "oneOf": [ - {"$ref": "#/definitions/execute_result"}, - {"$ref": "#/definitions/display_data"}, - {"$ref": "#/definitions/stream"}, - {"$ref": "#/definitions/error"} - ] - }, - - "execute_result": { - "description": "Result of executing a code cell.", - "type": "object", - "additionalProperties": false, - "required": ["output_type", "data", "metadata", "execution_count"], - "properties": { - "output_type": { - "description": "Type of cell output.", - "enum": ["execute_result"] - }, - "execution_count": { - "description": "A result's prompt number.", - "type": ["integer", "null"], - "minimum": 0 - }, - "data": {"$ref": "#/definitions/misc/mimebundle"}, - "metadata": {"$ref": "#/definitions/misc/output_metadata"} - } - }, - - "display_data": { - "description": "Data displayed as a result of code cell execution.", - "type": "object", - "additionalProperties": false, - "required": ["output_type", "data", "metadata"], - "properties": { - "output_type": { - "description": "Type of cell output.", - "enum": ["display_data"] - }, - "data": {"$ref": "#/definitions/misc/mimebundle"}, - "metadata": {"$ref": "#/definitions/misc/output_metadata"} - } - }, - - "stream": { - "description": "Stream output from a code cell.", - "type": "object", - "additionalProperties": false, - "required": ["output_type", "name", "text"], - "properties": { - "output_type": { - "description": "Type of cell output.", - "enum": ["stream"] - }, - "name": { - "description": "The name of the stream (stdout, stderr).", - "type": "string" - }, - "text": { - "description": "The stream's text output, represented as an array of strings.", - "$ref": "#/definitions/misc/multiline_string" - } - } - }, - - "error": { - "description": "Output of an error that occurred during code cell execution.", - "type": "object", - "additionalProperties": false, - "required": ["output_type", "ename", "evalue", "traceback"], - "properties": { - "output_type": { - "description": "Type of cell output.", - "enum": ["error"] - }, - "ename": { - "description": "The name of the error.", - "type": "string" - }, - "evalue": { - "description": "The value, or message, of the error.", - "type": "string" - }, - "traceback": { - "description": "The error's traceback, represented as an array of strings.", - "type": "array", - "items": {"type": "string"} - } - } - }, - - "unrecognized_output": { - "description": "Unrecognized output from a future minor-revision to the notebook format.", - "type": "object", - "additionalProperties": true, - "required": ["output_type"], - "properties": { - "output_type": { - "description": "Type of cell output.", - "not": { - "enum": ["execute_result", "display_data", "stream", "error"] - } - } - } - }, - - "misc": { - "metadata_name": { - "description": "The cell's name. If present, must be a non-empty string.", - "type": "string", - "pattern": "^.+$" - }, - "metadata_tags": { - "description": "The cell's tags. Tags must be unique, and must not contain commas.", - "type": "array", - "uniqueItems": true, - "items": { - "type": "string", - "pattern": "^[^,]+$" - } - }, - "source": { - "description": "Contents of the cell, represented as an array of lines.", - "$ref": "#/definitions/misc/multiline_string" - }, - "execution_count": { - "description": "The code cell's prompt number. Will be null if the cell has not been run.", - "type": ["integer", "null"], - "minimum": 0 - }, - "mimebundle": { - "description": "A mime-type keyed dictionary of data", - "type": "object", - "additionalProperties": false, - "properties": { - "application/json": { - "type": "object" - } - }, - "patternProperties": { - "^(?!application/json$)[a-zA-Z0-9]+/[a-zA-Z0-9\\-\\+\\.]+$": { - "description": "mimetype output (e.g. text/plain), represented as either an array of strings or a string.", - "$ref": "#/definitions/misc/multiline_string" - } - } - }, - "output_metadata": { - "description": "Cell output metadata.", - "type": "object", - "additionalProperties": true - }, - "multiline_string": { - "oneOf" : [ - {"type": "string"}, - { - "type": "array", - "items": {"type": "string"} - } - ] - } - } - } -} diff --git a/jupyter_nbformat/v4/nbjson.py b/jupyter_nbformat/v4/nbjson.py deleted file mode 100644 index cc05b05..0000000 --- a/jupyter_nbformat/v4/nbjson.py +++ /dev/null @@ -1,68 +0,0 @@ -"""Read and write notebooks in JSON format.""" - -# Copyright (c) IPython Development Team. -# Distributed under the terms of the Modified BSD License. - -import copy -import json - -from IPython.utils import py3compat - -from .nbbase import from_dict -from .rwbase import ( - NotebookReader, NotebookWriter, rejoin_lines, split_lines, strip_transient -) - - -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): - """Read a JSON string into a Notebook object""" - nb = json.loads(s, **kwargs) - nb = self.to_notebook(nb, **kwargs) - return nb - - def to_notebook(self, d, **kwargs): - """Convert a disk-format notebook dict to in-memory NotebookNode - - handles multi-line values as strings, scrubbing of transient values, etc. - """ - nb = from_dict(d) - nb = rejoin_lines(nb) - nb = strip_transient(nb) - return nb - - -class JSONWriter(NotebookWriter): - - def writes(self, nb, **kwargs): - """Serialize a NotebookNode object as a JSON string""" - kwargs['cls'] = BytesEncoder - kwargs['indent'] = 1 - kwargs['sort_keys'] = True - kwargs['separators'] = (',',': ') - kwargs.setdefault('ensure_ascii', False) - # don't modify in-memory dict - nb = copy.deepcopy(nb) - if kwargs.pop('split_lines', True): - nb = split_lines(nb) - nb = strip_transient(nb) - return py3compat.cast_unicode_py2(json.dumps(nb, **kwargs), 'utf-8') - - -_reader = JSONReader() -_writer = JSONWriter() - -reads = _reader.reads -read = _reader.read -to_notebook = _reader.to_notebook -write = _writer.write -writes = _writer.writes diff --git a/jupyter_nbformat/v4/rwbase.py b/jupyter_nbformat/v4/rwbase.py deleted file mode 100644 index 84c4a2e..0000000 --- a/jupyter_nbformat/v4/rwbase.py +++ /dev/null @@ -1,102 +0,0 @@ -"""Base classes and utilities for readers and writers.""" - -# Copyright (c) IPython Development Team. -# Distributed under the terms of the Modified BSD License. - -from IPython.utils.py3compat import string_types, cast_unicode_py2 - - -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 cell in nb.cells: - if 'source' in cell and isinstance(cell.source, list): - cell.source = ''.join(cell.source) - if cell.get('cell_type', None) == 'code': - for output in cell.get('outputs', []): - output_type = output.get('output_type', '') - if output_type in {'execute_result', 'display_data'}: - for key, value in output.get('data', {}).items(): - if key != 'application/json' and isinstance(value, list): - output.data[key] = ''.join(value) - elif output_type: - if isinstance(output.get('text', ''), list): - output.text = ''.join(output.text) - return nb - -_non_text_split_mimes = { - 'application/javascript', - 'image/svg+xml', -} - -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 cell in nb.cells: - source = cell.get('source', None) - if isinstance(source, string_types): - cell['source'] = source.splitlines(True) - - if cell.cell_type == 'code': - for output in cell.outputs: - if output.output_type in {'execute_result', 'display_data'}: - for key, value in output.data.items(): - if isinstance(value, string_types) and ( - key.startswith('text/') or key in _non_text_split_mimes - ): - output.data[key] = value.splitlines(True) - elif output.output_type == 'stream': - if isinstance(output.text, string_types): - output.text = output.text.splitlines(True) - return nb - - -def strip_transient(nb): - """Strip transient values that shouldn't be stored in files. - - This should be called in *both* read and write. - """ - nb.metadata.pop('orig_nbformat', None) - nb.metadata.pop('orig_nbformat_minor', None) - nb.metadata.pop('signature', None) - for cell in nb.cells: - cell.metadata.pop('trusted', None) - return nb - - -class NotebookReader(object): - """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""" - nbs = cast_unicode_py2(fp.read()) - return self.reads(nbs, **kwargs) - - -class NotebookWriter(object): - """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""" - nbs = cast_unicode_py2(self.writes(nb, **kwargs)) - return fp.write(nbs) diff --git a/jupyter_nbformat/v4/tests/__init__.py b/jupyter_nbformat/v4/tests/__init__.py deleted file mode 100644 index e69de29..0000000 --- a/jupyter_nbformat/v4/tests/__init__.py +++ /dev/null diff --git a/jupyter_nbformat/v4/tests/formattest.py b/jupyter_nbformat/v4/tests/formattest.py deleted file mode 100644 index 853083e..0000000 --- a/jupyter_nbformat/v4/tests/formattest.py +++ /dev/null @@ -1,54 +0,0 @@ -# -*- coding: utf8 -*- -import io -import os -import shutil -import tempfile - -pjoin = os.path.join - -from .nbexamples import nb0 - - -def open_utf8(fname, mode): - return io.open(fname, mode=mode, encoding='utf-8') - -class NBFormatTest: - """Mixin for writing notebook format tests""" - - # override with appropriate values in subclasses - nb0_ref = None - ext = None - mod = None - - def setUp(self): - self.wd = tempfile.mkdtemp() - - def tearDown(self): - shutil.rmtree(self.wd) - - def assertNBEquals(self, nba, nbb): - self.assertEqual(nba, nbb) - - def test_writes(self): - s = self.mod.writes(nb0) - if self.nb0_ref: - self.assertEqual(s, self.nb0_ref) - - def test_reads(self): - s = self.mod.writes(nb0) - nb = self.mod.reads(s) - - def test_roundtrip(self): - s = self.mod.writes(nb0) - self.assertNBEquals(self.mod.reads(s),nb0) - - def test_write_file(self): - with open_utf8(pjoin(self.wd, "nb0.%s" % self.ext), 'w') as f: - self.mod.write(nb0, f) - - def test_read_file(self): - with open_utf8(pjoin(self.wd, "nb0.%s" % self.ext), 'w') as f: - self.mod.write(nb0, f) - - with open_utf8(pjoin(self.wd, "nb0.%s" % self.ext), 'r') as f: - nb = self.mod.read(f) diff --git a/jupyter_nbformat/v4/tests/nbexamples.py b/jupyter_nbformat/v4/tests/nbexamples.py deleted file mode 100644 index b55a0c4..0000000 --- a/jupyter_nbformat/v4/tests/nbexamples.py +++ /dev/null @@ -1,104 +0,0 @@ -# -*- coding: utf-8 -*- - -import os -from base64 import encodestring - -from ..nbbase import ( - new_code_cell, new_markdown_cell, new_notebook, - new_output, new_raw_cell -) - -# some random base64-encoded *text* -png = encodestring(os.urandom(5)).decode('ascii') -jpeg = encodestring(os.urandom(6)).decode('ascii') - -cells = [] -cells.append(new_markdown_cell( - source='Some NumPy Examples', -)) - - -cells.append(new_code_cell( - source='import numpy', - execution_count=1, -)) - -cells.append(new_markdown_cell( - source='A random array', -)) - -cells.append(new_raw_cell( - source='A random array', -)) - -cells.append(new_markdown_cell( - source=u'## My Heading', -)) - -cells.append(new_code_cell( - source='a = numpy.random.rand(100)', - execution_count=2, -)) -cells.append(new_code_cell( - source='a = 10\nb = 5\n', - execution_count=3, -)) -cells.append(new_code_cell( - source='a = 10\nb = 5', - execution_count=4, -)) - -cells.append(new_code_cell( - source=u'print "ünîcødé"', - execution_count=3, - outputs=[new_output( - output_type=u'execute_result', - data={ - 'text/plain': u'', - 'text/html': u'The HTML rep', - 'text/latex': u'$a$', - 'image/png': png, - 'image/jpeg': jpeg, - 'image/svg+xml': u'', - 'application/json': { - 'key': 'value' - }, - 'application/javascript': u'var i=0;' - }, - execution_count=3 - ),new_output( - output_type=u'display_data', - data={ - 'text/plain': u'', - 'text/html': u'The HTML rep', - 'text/latex': u'$a$', - 'image/png': png, - 'image/jpeg': jpeg, - 'image/svg+xml': u'', - 'application/json': { - 'key': 'value' - }, - 'application/javascript': u'var i=0;' - }, - ),new_output( - output_type=u'error', - ename=u'NameError', - evalue=u'NameError was here', - traceback=[u'frame 0', u'frame 1', u'frame 2'] - ),new_output( - output_type=u'stream', - text='foo\rbar\r\n' - ),new_output( - output_type=u'stream', - name='stderr', - text='\rfoo\rbar\n' - )] -)) - -nb0 = new_notebook(cells=cells, - metadata={ - 'language': 'python', - } -) - - diff --git a/jupyter_nbformat/v4/tests/test_convert.py b/jupyter_nbformat/v4/tests/test_convert.py deleted file mode 100644 index 04f871b..0000000 --- a/jupyter_nbformat/v4/tests/test_convert.py +++ /dev/null @@ -1,72 +0,0 @@ -# -*- coding: utf-8 -*- -import copy - -import nose.tools as nt - -from IPython.nbformat import validate -from .. import convert - -from . import nbexamples -from IPython.nbformat.v3.tests import nbexamples as v3examples -from IPython.nbformat import v3, v4 - -def test_upgrade_notebook(): - nb03 = copy.deepcopy(v3examples.nb0) - validate(nb03) - nb04 = convert.upgrade(nb03) - validate(nb04) - -def test_downgrade_notebook(): - nb04 = copy.deepcopy(nbexamples.nb0) - validate(nb04) - nb03 = convert.downgrade(nb04) - validate(nb03) - -def test_upgrade_heading(): - v3h = v3.new_heading_cell - v4m = v4.new_markdown_cell - for v3cell, expected in [ - ( - v3h(source='foo', level=1), - v4m(source='# foo'), - ), - ( - v3h(source='foo\nbar\nmulti-line\n', level=4), - v4m(source='#### foo bar multi-line'), - ), - ( - v3h(source=u'ünìcö∂e–cønvërsioñ', level=4), - v4m(source=u'#### ünìcö∂e–cønvërsioñ'), - ), - ]: - upgraded = convert.upgrade_cell(v3cell) - nt.assert_equal(upgraded, expected) - -def test_downgrade_heading(): - v3h = v3.new_heading_cell - v4m = v4.new_markdown_cell - v3m = lambda source: v3.new_text_cell('markdown', source) - for v4cell, expected in [ - ( - v4m(source='# foo'), - v3h(source='foo', level=1), - ), - ( - v4m(source='#foo'), - v3h(source='foo', level=1), - ), - ( - v4m(source='#\tfoo'), - v3h(source='foo', level=1), - ), - ( - v4m(source='# \t foo'), - v3h(source='foo', level=1), - ), - ( - v4m(source='# foo\nbar'), - v3m(source='# foo\nbar'), - ), - ]: - downgraded = convert.downgrade_cell(v4cell) - nt.assert_equal(downgraded, expected) diff --git a/jupyter_nbformat/v4/tests/test_json.py b/jupyter_nbformat/v4/tests/test_json.py deleted file mode 100644 index 5b89c5f..0000000 --- a/jupyter_nbformat/v4/tests/test_json.py +++ /dev/null @@ -1,69 +0,0 @@ -from base64 import decodestring -from unittest import TestCase - -from IPython.utils.py3compat import unicode_type -from ..nbjson import reads, writes -from .. import nbjson -from .nbexamples import nb0 - -from . import formattest - - -class TestJSON(formattest.NBFormatTest, TestCase): - - nb0_ref = None - ext = 'ipynb' - mod = nbjson - - def test_roundtrip_nosplit(self): - """Ensure that multiline blobs are still readable""" - # ensures that notebooks written prior to splitlines change - # are still readable. - s = writes(nb0, split_lines=False) - self.assertEqual(nbjson.reads(s),nb0) - - def test_roundtrip_split(self): - """Ensure that splitting multiline blocks is safe""" - # This won't differ from test_roundtrip unless the default changes - s = writes(nb0, split_lines=True) - self.assertEqual(nbjson.reads(s),nb0) - - def test_read_png(self): - """PNG output data is b64 unicode""" - s = writes(nb0) - nb1 = nbjson.reads(s) - found_png = False - for cell in nb1.cells: - if not 'outputs' in cell: - continue - for output in cell.outputs: - if not 'data' in output: - continue - if 'image/png' in output.data: - found_png = True - pngdata = output.data['image/png'] - self.assertEqual(type(pngdata), unicode_type) - # test that it is valid b64 data - b64bytes = pngdata.encode('ascii') - raw_bytes = decodestring(b64bytes) - assert found_png, "never found png output" - - def test_read_jpeg(self): - """JPEG output data is b64 unicode""" - s = writes(nb0) - nb1 = nbjson.reads(s) - found_jpeg = False - for cell in nb1.cells: - if not 'outputs' in cell: - continue - for output in cell.outputs: - if not 'data' in output: - continue - if 'image/jpeg' in output.data: - found_jpeg = True - jpegdata = output.data['image/jpeg'] - self.assertEqual(type(jpegdata), unicode_type) - # test that it is valid b64 data - b64bytes = jpegdata.encode('ascii') - raw_bytes = decodestring(b64bytes) - assert found_jpeg, "never found jpeg output" diff --git a/jupyter_nbformat/v4/tests/test_nbbase.py b/jupyter_nbformat/v4/tests/test_nbbase.py deleted file mode 100644 index 6172657..0000000 --- a/jupyter_nbformat/v4/tests/test_nbbase.py +++ /dev/null @@ -1,101 +0,0 @@ -# coding: utf-8 -"""Tests for the Python API for composing notebook elements""" - -import nose.tools as nt - -from IPython.nbformat.validator import isvalid, validate, ValidationError -from ..nbbase import ( - NotebookNode, nbformat, - new_code_cell, new_markdown_cell, new_notebook, - new_output, new_raw_cell, -) - -def test_empty_notebook(): - nb = new_notebook() - nt.assert_equal(nb.cells, []) - nt.assert_equal(nb.metadata, NotebookNode()) - nt.assert_equal(nb.nbformat, nbformat) - -def test_empty_markdown_cell(): - cell = new_markdown_cell() - nt.assert_equal(cell.cell_type, 'markdown') - nt.assert_equal(cell.source, '') - -def test_markdown_cell(): - cell = new_markdown_cell(u'* Søme markdown') - nt.assert_equal(cell.source, u'* Søme markdown') - -def test_empty_raw_cell(): - cell = new_raw_cell() - nt.assert_equal(cell.cell_type, u'raw') - nt.assert_equal(cell.source, '') - -def test_raw_cell(): - cell = new_raw_cell('hi') - nt.assert_equal(cell.source, u'hi') - -def test_empty_code_cell(): - cell = new_code_cell('hi') - nt.assert_equal(cell.cell_type, 'code') - nt.assert_equal(cell.source, u'hi') - -def test_empty_display_data(): - output = new_output('display_data') - nt.assert_equal(output.output_type, 'display_data') - -def test_empty_stream(): - output = new_output('stream') - nt.assert_equal(output.output_type, 'stream') - nt.assert_equal(output.name, 'stdout') - nt.assert_equal(output.text, '') - -def test_empty_execute_result(): - output = new_output('execute_result', execution_count=1) - nt.assert_equal(output.output_type, 'execute_result') - -mimebundle = { - 'text/plain': "some text", - "application/json": { - "key": "value" - }, - "image/svg+xml": 'ABCDEF', - "application/octet-stream": 'ABC-123', - "application/vnd.foo+bar": "Some other stuff", -} - -def test_display_data(): - output = new_output('display_data', mimebundle) - for key, expected in mimebundle.items(): - nt.assert_equal(output.data[key], expected) - -def test_execute_result(): - output = new_output('execute_result', mimebundle, execution_count=10) - nt.assert_equal(output.execution_count, 10) - for key, expected in mimebundle.items(): - nt.assert_equal(output.data[key], expected) - -def test_error(): - o = new_output(output_type=u'error', ename=u'NameError', - evalue=u'Name not found', traceback=[u'frame 0', u'frame 1', u'frame 2'] - ) - nt.assert_equal(o.output_type, u'error') - nt.assert_equal(o.ename, u'NameError') - nt.assert_equal(o.evalue, u'Name not found') - nt.assert_equal(o.traceback, [u'frame 0', u'frame 1', u'frame 2']) - -def test_code_cell_with_outputs(): - cell = new_code_cell(execution_count=10, outputs=[ - new_output('display_data', mimebundle), - new_output('stream', text='hello'), - new_output('execute_result', mimebundle, execution_count=10), - ]) - nt.assert_equal(cell.execution_count, 10) - nt.assert_equal(len(cell.outputs), 3) - er = cell.outputs[-1] - nt.assert_equal(er.execution_count, 10) - nt.assert_equal(er['output_type'], 'execute_result') - -def test_stream(): - output = new_output('stream', name='stderr', text='hello there') - nt.assert_equal(output.name, 'stderr') - nt.assert_equal(output.text, 'hello there') diff --git a/jupyter_nbformat/v4/tests/test_validate.py b/jupyter_nbformat/v4/tests/test_validate.py deleted file mode 100644 index dbef2cb..0000000 --- a/jupyter_nbformat/v4/tests/test_validate.py +++ /dev/null @@ -1,105 +0,0 @@ -"""Tests for nbformat validation""" - -# Copyright (c) IPython Development Team. -# Distributed under the terms of the Modified BSD License. - -import io -import os - -import nose.tools as nt - -from IPython.nbformat.validator import validate, ValidationError -from ..nbjson import reads -from ..nbbase import ( - nbformat, - new_code_cell, new_markdown_cell, new_notebook, - new_output, new_raw_cell, -) - -def validate4(obj, ref=None): - return validate(obj, ref, version=nbformat) - -def test_valid_code_cell(): - cell = new_code_cell() - validate4(cell, 'code_cell') - -def test_invalid_code_cell(): - cell = new_code_cell() - - cell['source'] = 5 - with nt.assert_raises(ValidationError): - validate4(cell, 'code_cell') - - cell = new_code_cell() - del cell['metadata'] - - with nt.assert_raises(ValidationError): - validate4(cell, 'code_cell') - - cell = new_code_cell() - del cell['source'] - - with nt.assert_raises(ValidationError): - validate4(cell, 'code_cell') - - cell = new_code_cell() - del cell['cell_type'] - - with nt.assert_raises(ValidationError): - validate4(cell, 'code_cell') - -def test_invalid_markdown_cell(): - cell = new_markdown_cell() - - cell['source'] = 5 - with nt.assert_raises(ValidationError): - validate4(cell, 'markdown_cell') - - cell = new_markdown_cell() - del cell['metadata'] - - with nt.assert_raises(ValidationError): - validate4(cell, 'markdown_cell') - - cell = new_markdown_cell() - del cell['source'] - - with nt.assert_raises(ValidationError): - validate4(cell, 'markdown_cell') - - cell = new_markdown_cell() - del cell['cell_type'] - - with nt.assert_raises(ValidationError): - validate4(cell, 'markdown_cell') - -def test_invalid_raw_cell(): - cell = new_raw_cell() - - cell['source'] = 5 - with nt.assert_raises(ValidationError): - validate4(cell, 'raw_cell') - - cell = new_raw_cell() - del cell['metadata'] - - with nt.assert_raises(ValidationError): - validate4(cell, 'raw_cell') - - cell = new_raw_cell() - del cell['source'] - - with nt.assert_raises(ValidationError): - validate4(cell, 'raw_cell') - - cell = new_raw_cell() - del cell['cell_type'] - - with nt.assert_raises(ValidationError): - validate4(cell, 'raw_cell') - -def test_sample_notebook(): - here = os.path.dirname(__file__) - with io.open(os.path.join(here, os.pardir, os.pardir, 'tests', "test4.ipynb"), encoding='utf-8') as f: - nb = reads(f.read()) - validate4(nb) diff --git a/jupyter_nbformat/validator.py b/jupyter_nbformat/validator.py deleted file mode 100644 index 3e74e55..0000000 --- a/jupyter_nbformat/validator.py +++ /dev/null @@ -1,157 +0,0 @@ -# Copyright (c) IPython Development Team. -# Distributed under the terms of the Modified BSD License. - -from __future__ import print_function -import json -import os -import warnings - -try: - from jsonschema import ValidationError - from jsonschema import Draft4Validator as Validator -except ImportError as e: - verbose_msg = """ - - IPython notebook format depends on the jsonschema package: - - https://pypi.python.org/pypi/jsonschema - - Please install it first. - """ - raise ImportError(str(e) + verbose_msg) - -from IPython.utils.importstring import import_item - - -validators = {} - -def _relax_additional_properties(obj): - """relax any `additionalProperties`""" - if isinstance(obj, dict): - for key, value in obj.items(): - if key == 'additionalProperties': - value = True - else: - value = _relax_additional_properties(value) - obj[key] = value - elif isinstance(obj, list): - for i, value in enumerate(obj): - obj[i] = _relax_additional_properties(value) - return obj - -def _allow_undefined(schema): - schema['definitions']['cell']['oneOf'].append( - {"$ref": "#/definitions/unrecognized_cell"} - ) - schema['definitions']['output']['oneOf'].append( - {"$ref": "#/definitions/unrecognized_output"} - ) - return schema - -def get_validator(version=None, version_minor=None): - """Load the JSON schema into a Validator""" - if version is None: - from .. import current_nbformat - version = current_nbformat - - v = import_item("jupyter_nbformat.v%s" % version) - current_minor = v.nbformat_minor - if version_minor is None: - version_minor = current_minor - - version_tuple = (version, version_minor) - - if version_tuple not in validators: - try: - v.nbformat_schema - except AttributeError: - # no validator - return None - schema_path = os.path.join(os.path.dirname(v.__file__), v.nbformat_schema) - with open(schema_path) as f: - schema_json = json.load(f) - - if current_minor < version_minor: - # notebook from the future, relax all `additionalProperties: False` requirements - schema_json = _relax_additional_properties(schema_json) - # and allow undefined cell types and outputs - schema_json = _allow_undefined(schema_json) - - validators[version_tuple] = Validator(schema_json) - return validators[version_tuple] - -def isvalid(nbjson, ref=None, version=None, version_minor=None): - """Checks whether the given notebook JSON conforms to the current - notebook format schema. Returns True if the JSON is valid, and - False otherwise. - - To see the individual errors that were encountered, please use the - `validate` function instead. - """ - try: - validate(nbjson, ref, version, version_minor) - except ValidationError: - return False - else: - return True - - -def better_validation_error(error, version, version_minor): - """Get better ValidationError on oneOf failures - - oneOf errors aren't informative. - if it's a cell type or output_type error, - try validating directly based on the type for a better error message - """ - key = error.schema_path[-1] - if key.endswith('Of'): - - ref = None - if isinstance(error.instance, dict): - if 'cell_type' in error.instance: - ref = error.instance['cell_type'] + "_cell" - elif 'output_type' in error.instance: - ref = error.instance['output_type'] - - if ref: - try: - validate(error.instance, - ref, - version=version, - version_minor=version_minor, - ) - except ValidationError as e: - return better_validation_error(e, version, version_minor) - except: - # if it fails for some reason, - # let the original error through - pass - - return error - - -def validate(nbjson, ref=None, version=None, version_minor=None): - """Checks whether the given notebook JSON conforms to the current - notebook format schema. - - Raises ValidationError if not valid. - """ - if version is None: - from .reader import get_version - (version, version_minor) = get_version(nbjson) - - validator = get_validator(version, version_minor) - - if validator is None: - # no validator - warnings.warn("No schema for validating v%s notebooks" % version, UserWarning) - return - - try: - if ref: - return validator.validate(nbjson, {'$ref' : '#/definitions/%s' % ref}) - else: - return validator.validate(nbjson) - except ValidationError as e: - raise better_validation_error(e, version, version_minor) - diff --git a/setup.py b/setup.py index fcec5b1..c47a27d 100755 --- a/setup.py +++ b/setup.py @@ -271,7 +271,7 @@ extras_require = dict( doc = ['Sphinx>=1.1', 'numpydoc'], test = ['nose>=0.10.1', 'requests'], terminal = [], - nbformat = ['jsonschema>=2.0'], + nbformat = ['jupyter_nbformat'], notebook = ['tornado>=4.0', pyzmq, 'jinja2', 'pygments', 'mistune>=0.5'], nbconvert = ['pygments', 'jinja2', 'mistune>=0.3.1'] )