Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Catch dict-like vals in __setitem__, apply from_dict() #107

Merged
merged 8 commits into from
Aug 18, 2017
37 changes: 32 additions & 5 deletions nbformat/notebooknode.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,50 @@
"""NotebookNode - adding attribute access to dicts"""

from ipython_genutils.ipstruct import Struct
from collections import Mapping


class NotebookNode(Struct):
"""A dict-like node with attribute-access"""
pass

def __setitem__(self, key, value):
if isinstance(value, Mapping) and not isinstance(value, NotebookNode):
value = from_dict(value)
super(NotebookNode, self).__setitem__(key, value)

def update(self, *args, **kwargs):
"""
A dict-like update method based on CPython's MutableMapping `update`
method.
"""
if len(args) > 1:
raise TypeError('update expected at most 1 arguments, got %d' %
len(args))
if args:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did not know that update could be called in so many ways!

other = args[0]
if isinstance(other, Mapping):
for key in other:
self[key] = other[key]
elif hasattr(other, "keys"):
for key in other.keys():
self[key] = other[key]
else:
for key, value in other:
self[key] = value
for key, value in kwargs.items():
self[key] = value


def from_dict(d):
"""Convert dict to dict-like NotebookNode

Recursively converts any dict in the container to a NotebookNode.
This does not check that the contents of the dictionary make a valid
notebook or part of a notebook.
"""
if isinstance(d, dict):
return NotebookNode({k:from_dict(v) for k,v in d.items()})
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


14 changes: 7 additions & 7 deletions nbformat/v4/nbbase.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
# Copyright (c) IPython Development Team.
# Distributed under the terms of the Modified BSD License.

from ..notebooknode import from_dict, NotebookNode
from ..notebooknode import NotebookNode

# Change this when incrementing the nbformat version
nbformat = 4
Expand All @@ -35,9 +35,9 @@ def new_output(output_type, data=None, **kwargs):
output.metadata = NotebookNode()
output.data = NotebookNode()
# load from args:
output.update(from_dict(kwargs))
output.update(kwargs)
if data is not None:
output.data = from_dict(data)
output.data = data
# validate
validate(output, output_type)
return output
Expand Down Expand Up @@ -95,7 +95,7 @@ def new_code_cell(source='', **kwargs):
source=source,
outputs=[],
)
cell.update(from_dict(kwargs))
cell.update(kwargs)

validate(cell, 'code_cell')
return cell
Expand All @@ -107,7 +107,7 @@ def new_markdown_cell(source='', **kwargs):
source=source,
metadata=NotebookNode(),
)
cell.update(from_dict(kwargs))
cell.update(kwargs)

validate(cell, 'markdown_cell')
return cell
Expand All @@ -119,7 +119,7 @@ def new_raw_cell(source='', **kwargs):
source=source,
metadata=NotebookNode(),
)
cell.update(from_dict(kwargs))
cell.update(kwargs)

validate(cell, 'raw_cell')
return cell
Expand All @@ -132,6 +132,6 @@ def new_notebook(**kwargs):
metadata=NotebookNode(),
cells=[],
)
nb.update(from_dict(kwargs))
nb.update(kwargs)
validate(nb)
return nb
2 changes: 1 addition & 1 deletion nbformat/v4/nbjson.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

from ipython_genutils import py3compat

from .nbbase import from_dict
from ..notebooknode import from_dict
from .rwbase import (
NotebookReader, NotebookWriter, rejoin_lines, split_lines, strip_transient
)
Expand Down