Skip to content
This repository has been archived by the owner on Dec 5, 2024. It is now read-only.

Commit

Permalink
Whatever
Browse files Browse the repository at this point in the history
  • Loading branch information
Carreau committed Jun 19, 2017
1 parent 12bc453 commit dc21f64
Show file tree
Hide file tree
Showing 2 changed files with 200 additions and 52 deletions.
128 changes: 76 additions & 52 deletions disp/py3only.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,30 @@ def repr(o):


thecss = """
/* summary::-webkit-details-marker {
display: none;
}
summary {
text-decoration-line: underline;
text-decoration-style: dotted;
} */
.rendered_html pre, .rendered_html code {
background-color: transparent; /* bug in notebook css */
}
.rendered_html .jupyter-extra-info ul{
list-style: none;
}
.jupyter-extra-info {
background-color: hsla(0, 0%, 5%, 0.07);
padding: 0.5em;
border: thin solid silver;
}
dl.jupyter-inner-mapping-repr {
padding-left: 1em;
margin-bottom: 0;
Expand Down Expand Up @@ -65,7 +89,7 @@ def repr(o):
list-style-type: none;
}
summary > pre {
summary > code {
display: inline
}
Expand All @@ -74,10 +98,6 @@ def repr(o):
display: inline-block;
}
details[open] {
/*display: inline-block;*/
}
.rendered_html ul.jupyter-flat-container-repr {
padding-left: 0px;
margin-left: 0em;
Expand All @@ -96,11 +116,11 @@ def repr(o):
/*display: block;*/
}
details[open] ~ .jupyter-breaking-placeholder {
details.jupyter-details[open] ~ .jupyter-breaking-placeholder {
display: block;
}
details ~ .jupyter-breaking-placeholder {
.jupyter-details ~ .jupyter-breaking-placeholder {
display: inline;
}
.output_subarea > ul.jupyter-flat-container-repr, .output_subarea > ul.jupyter-flat-container-repr > p {
Expand All @@ -109,9 +129,9 @@ def repr(o):
"""


#################################################################################
##########################################################################
# Utilities #
#################################################################################
##########################################################################

def safe(obj):
"""
Expand All @@ -136,6 +156,31 @@ def htmlify_repr(obj)-> str:
escape(repr(obj))


def details(summary, details_):
if details:
rsum = safe(summary)._repr_html_()
rdetails = safe(details_)._repr_html_()
return HTML(f"<details class='jupyter-details'><summary>{rsum}</summary>{rdetails}</details>")
else:
rsum = htmlify_repr(summary)
return HTML(f"{rsum}")


def code(string):
assert isinstance(string, str)
return HTML(f"<code>{escape(string)}</code>")


def well(s):
s = safe(s)._repr_html_()
return HTML('<div class="jupyter-extra-info">' + s + '</div>')


##########################################################################
# Formatters #
##########################################################################


def html_flat_container(container: List, delims, empty) -> str:
"""Retrun an Html representation of a list with recursive HTML repr for all sub objects.
Expand All @@ -149,10 +194,9 @@ def html_flat_container(container: List, delims, empty) -> str:
last = (index == len(container) - 1)
rpr = htmlify_repr(elem)
pc = '<span class="post-comma">,</span>' if not last else ''
pl = '<br/>' if last else ''
x.append('<li>{}{}</li>'.format(rpr, pc))
return f"""<ul class="jupyter-flat-container-repr">
<details open>
<details class='jupyter-details' open>
<summary>{delims[0]}</summary>
{''.join(x)}
</details>
Expand All @@ -162,16 +206,16 @@ def html_flat_container(container: List, delims, empty) -> str:
"""


def html_formatter_for_list(t): return html_flat_container(
t, delims='[]', empty='[]')
def html_formatter_for_list(t):
return html_flat_container(t, delims='[]', empty='[]')


def html_formatter_for_tuple(t): return html_flat_container(
t, delims='()', empty='()')
def html_formatter_for_tuple(t):
return html_flat_container(t, delims='()', empty='()')


def html_formatter_for_set(t): return html_flat_container(
t, delims='{}', empty='set({})')
def html_formatter_for_set(t):
return html_flat_container(t, delims='{}', empty='set({})')


def _inner_html_formatter_for_mapping(mapping):
Expand All @@ -194,7 +238,7 @@ def html_formatter_for_mapping(mapping, *, open=True):
delims = '{}'
op = 'open' if open else ''
return f"""
<details {op}>
<details class='jupyter-details' {op}>
<summary>{delims[0]}</summary>
{_inner_html_formatter_for_mapping(mapping)}
</details>
Expand Down Expand Up @@ -224,9 +268,9 @@ def in_f(k, v):
<style>
{thecss}
</style>
<details><summary><pre>{escape(repr(req))}</pre></summary>
<details class='jupyter-details'><summary><code>{escape(repr(req))}</code></summary>
{attrs}
<details class="disp-requests-repr">
<details class="jupyter-details">
<summary>Content (JSON)</summary>
{_inner_html_formatter_for_mapping(json_content)}
</details>
Expand All @@ -238,44 +282,24 @@ def in_f(k, v):
<style>
{thecss}
</style>
<details><summary><pre>{escape(repr(req))}</pre></summary>
<details class='jupyter-details'><summary><code>{escape(repr(req))}</code></summary>
{attrs}
</details>
"""


def details(summary, details_):
if details:
rsum = safe(summary)._repr_html_()
rdetails = safe(details_)._repr_html_()
return HTML(f"<details><summary>{rsum}</summary>{rdetails}</details>")
else:
rsum = htmlify_repr(summary)
return HTML(f"{rsum}")


def pre(string):
assert isinstance(string, str)
return HTML(f"<pre>{escape(string)}</pre>")


def well(s):
s = safe(s)._repr_html_()
return HTML('<div class="well">' + s + '</div>')


def gen_help(obj):
doc = next(filter(None, (x.__doc__ for x in type(obj).mro())))
return f"""
<pre title='{escape(doc)}'>{escape(repr(obj))}<pre>
<code title='{escape(doc)}'>{escape(repr(obj))}<code>
"""


def general_repr(obj):
return f'<style>{thecss}</style>' +\
f'<details><summary><pre>{escape(repr(obj))}<pre></summary>' +\
f'<details class="jupyter-details"><summary><code>{escape(repr(obj))}<code></summary>' +\
_inner_html_formatter_for_mapping({k: v for (k, v) in vars(obj).items() if not k.startswith('_')}) +\
'</details>'
'</details>'


def html_formatter_for_type(obj):
Expand All @@ -285,16 +309,17 @@ def html_formatter_for_type(obj):
mro = ()
if len(mro) > 1:
mime = get_repr_mimebundle(mro[1], include='text/html').data
return f'<details><summary><pre>{escape(repr(obj))}</pre></summary>'\
return f'<style>{thecss}</style>' + \
f'<details class="jupyter-details" ><summary><code>{escape(repr(obj))}</code></summary>'\
+ well(HTML(f"""
<p><pre alpha>{obj.__doc__ or ''}</pre></p>
<p><code alpha>{obj.__doc__ or ''}</code></p>
<p> Inherit from :</p>
<ul>
<li>{mime.get('text/html')}</li>
</ul>"""))._repr_html_()\
+ '</details>'
else:
return f'<style>{thecss}</style>' + f'<pre>{escape(repr(obj))}</pre>'
return f'<style>{thecss}</style>' + f'<code>{escape(repr(obj))}</code>'


def html_formatter_for_builtin_function_or_method(obj):
Expand All @@ -305,14 +330,13 @@ def html_formatter_for_builtin_function_or_method(obj):
res.pop('string_form')
res.pop('base_class')
if res.get('definition', None):
res['definition'] = pre(obj.__name__ + res['definition'])
res['definition'] = code(obj.__name__ + res['definition'])
if docstring != '<no docstring>':
res['docstring'] = pre(docstring)
res['docstring'] = code(docstring)
else:
del res['docstring']
# return repr(details(repr(obj), htmlify_repr(res)))
return f'<style>{thecss}</style>' + htmlify_repr(details(HTML(escape(repr(obj))), HTML('<div class="well">' + _inner_html_formatter_for_mapping(res) + '<div>')))
return f'<style>{thecss}</style>' + htmlify_repr(details(code(repr(obj)), well(HTML(_inner_html_formatter_for_mapping(res)))))


def html_formatter_for_module(obj):
return f'<style>{thecss}</style>' + details(HTML(escape(repr(obj))), well(pre(obj.__doc__ or '')))._repr_html_()
return f'<style>{thecss}</style>' + details(code(repr(obj)), well(code(obj.__doc__ or '')))._repr_html_()
124 changes: 124 additions & 0 deletions disp/vendor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@

try:
from IPython.core import DataMetadata, RecursiveObject, ReprGetter, get_repr_mimebundle
except ImportError:
from collections import namedtuple

class RecursiveObject:
"""
Default recursive object that provides a recursion repr if needed.
You may register a formatter for this object that will be call when
recursion is reached.
"""

def __init__(self, already_seen):
self.seen = already_seen
pass

def __repr__(self):
return '<recursion ... {}>'.format(str(self.seen))

def _repr_html_(self):
import html
return '&lt;recursion ... {}&gt;'.format(html.escape(str(self.seen)))



DataMetadata = namedtuple('DataMetadata', ('data','metadata'))


class ReprGetter:
"""
Object to carry recursion state when computing formating information when
computing rich representation.
useful when computing representation concurrently of nested object that may
refer to common resources.
"""

__slots__ = ('_objs',)

def __init__(self):
self._objs = set()

def get_repr_mimebundle(self, obj, include=None, exclude=None, *, on_recursion=RecursiveObject):
"""
return the representations of an object and associated metadata.
An given object can have many representation available, that can be defined
in many ways: `_repr_*_` methods, `_repr_mimebundle_`, or user-registered
formatter for types.
When given an object, :any:`get_repr_mimebundle` will search for the
various formatting option with their associated priority and return the
requested representation and associated metadata.
Parameters
----------
obj : an objects
The Python objects to get the representation data.
include : list, tuple or set, optional
A list of format type strings (MIME types) to include in the
format data dict. If this is set *only* the format types included
in this list will be computed.
exclude : list, tuple or set, optional
A list of format type strings (MIME types) to exclude in the format
data dict. If this is set all format types will be computed,
except for those included in this argument.
on_recursion: callable
Return an object to compute the representation when recursion is
detected.
Returns
-------
(data, metadata) : named tuple of two dicts
- 0/.data: See :any:`DisplayFormatter.format`.
- 1/.metadata: See :any:`DisplayFormatter.format`
Note
----
When :any:`get_repr_mimebundle` detect it is recursively called, it will
attempt to return the representation of :class:`RecursiveObject`. You
may register extra formatter for :class:`RecursiveObject`.
If you are computing objects representation in a concurrent way (thread,
coroutines, ...), you should make sure to instanciate a
:class:`ReprGetter` object and use one per task to avoid race conditions.
If a specific mimetype formatter need to call `get_repr_mimebundle()`
for another mimeformat, then it must pass the mimetypes values it desire
to `include` in order to correctly avoid recursion
See Also
--------
:func:`display`, :any:`DisplayFormatter.format`
"""
from IPython.core.interactiveshell import InteractiveShell
if isinstance(include, str):
include = (include,)
if not include:
keys = {(id(obj), None)}
else:
keys = {(id(obj), f) for f in include}
fmt = InteractiveShell.instance().display_formatter.format
if id(obj) == id(object):
return DataMetadata({'text/plain':"<class 'object'>"}, {})
if self._objs.intersection(keys):
return DataMetadata(*fmt(on_recursion(obj), include=include, exclude=exclude))
else:
try:
self._objs.update(keys)
return DataMetadata(*fmt(obj, include=include, exclude=exclude))
finally:
self._objs.difference_update(keys)

# Expose this for convenience at the top level. Similar to what the random
# module in python does. If you want to avoid weird behavior from concurrency:
# Instantiate your own.
get_repr_mimebundle = ReprGetter().get_repr_mimebundle

0 comments on commit dc21f64

Please sign in to comment.