├── .gitignore
├── .travis.yml
├── LICENSE
├── README.md
├── disp
├── __init__.py
├── py3only.py
├── spark.py
└── vendor.py
├── example
└── Disp-Example-builtins.ipynb
├── pretty-context.png
├── setup.cfg
└── setup.py
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | env/
12 | build/
13 | develop-eggs/
14 | dist/
15 | downloads/
16 | eggs/
17 | .eggs/
18 | lib/
19 | lib64/
20 | parts/
21 | sdist/
22 | var/
23 | wheels/
24 | *.egg-info/
25 | .installed.cfg
26 | *.egg
27 |
28 | # PyInstaller
29 | # Usually these files are written by a python script from a template
30 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
31 | *.manifest
32 | *.spec
33 |
34 | # Installer logs
35 | pip-log.txt
36 | pip-delete-this-directory.txt
37 |
38 | # Unit test / coverage reports
39 | htmlcov/
40 | .tox/
41 | .coverage
42 | .coverage.*
43 | .cache
44 | nosetests.xml
45 | coverage.xml
46 | *.cover
47 | .hypothesis/
48 |
49 | # Translations
50 | *.mo
51 | *.pot
52 |
53 | # Django stuff:
54 | *.log
55 | local_settings.py
56 |
57 | # Flask stuff:
58 | instance/
59 | .webassets-cache
60 |
61 | # Scrapy stuff:
62 | .scrapy
63 |
64 | # Sphinx documentation
65 | docs/_build/
66 |
67 | # PyBuilder
68 | target/
69 |
70 | # Jupyter Notebook
71 | .ipynb_checkpoints
72 |
73 | # pyenv
74 | .python-version
75 |
76 | # celery beat schedule file
77 | celerybeat-schedule
78 |
79 | # SageMath parsed files
80 | *.sage.py
81 |
82 | # dotenv
83 | .env
84 |
85 | # virtualenv
86 | .venv
87 | venv/
88 | ENV/
89 |
90 | # Spyder project settings
91 | .spyderproject
92 | .spyproject
93 |
94 | # Rope project settings
95 | .ropeproject
96 |
97 | # mkdocs documentation
98 | /site
99 |
100 | # mypy
101 | .mypy_cache/
102 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: python
2 | sudo: false
3 | before_install:
4 | - pip install pip --upgrade
5 | - pip install ipython
6 | script:
7 | - ipython -c 'import disp; disp.install()'
8 | - # py.test # no test for now.
9 | - ipython -c 'import disp; disp.uninstall()'
10 | python:
11 | - "nightly"
12 | - 3.6-dev
13 | - 3.6
14 | - 3.5
15 | - 2.7
16 |
17 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | BSD 3-Clause License
2 |
3 | Copyright (c) 2017, IPython
4 | All rights reserved.
5 |
6 | Redistribution and use in source and binary forms, with or without
7 | modification, are permitted provided that the following conditions are met:
8 |
9 | * Redistributions of source code must retain the above copyright notice, this
10 | list of conditions and the following disclaimer.
11 |
12 | * Redistributions in binary form must reproduce the above copyright notice,
13 | this list of conditions and the following disclaimer in the documentation
14 | and/or other materials provided with the distribution.
15 |
16 | * Neither the name of the copyright holder nor the names of its
17 | contributors may be used to endorse or promote products derived from
18 | this software without specific prior written permission.
19 |
20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Disp
2 |
3 | Providing default representations of common objects in Python land
4 |
5 | 
6 |
7 | Works in IPython when the object is the value returned by the last statement of
8 | a cell, or when calling `display()` on it.
9 |
10 | ## Install
11 |
12 | ```
13 | $ pip install disp
14 | $ ipython -c 'import disp; disp.install()'
15 | 💖 Installation succeeded: enjoy disp ! 💖
16 | ```
17 |
18 | ## Uninstall
19 |
20 | ```
21 | $ ipython -c 'import disp; disp.uninstall()'
22 | ```
23 |
24 | ## Supported objects
25 |
26 | The following objects will gain superpowers automatically:
27 |
28 | - `pyspark.context:SparkContext`
29 | - `pyspark.sql:SparkSession`
30 |
31 | The followings objects need to be explicitly register with
32 | `disp.activate_builtins()` and will work only on Python 3.6 and later:
33 |
34 | - types
35 | - functions methods (and alike)
36 | - modules
37 |
38 | The following objects need to be explicitly activated individually for each
39 | type with `disp.activate_for(instance)`:
40 |
41 | - requests.models.Response (Python 3.6+ only)
42 |
43 | A couple of other objects are secretly available on Python 3.6, but are still
44 | unstable so-far (dig through the source).
45 |
46 | ## Example
47 |
48 | See our [example notebook](http://nbviewer.jupyter.org/github/ipython/disp/blob/master/example/Disp-Example-builtins.ipynb)
49 |
50 | ## Do you support more objects?
51 |
52 | Do you want to submit a Pull Request? We'll probably accept it. 🤓
53 |
54 | # releasing
55 |
56 | Bump version number in `setup.py`.
57 | Install `twine`
58 |
59 | ```
60 | $ python setup.py sdist bdist_wheel
61 | $ twine upload dist/*
62 | ```
63 |
--------------------------------------------------------------------------------
/disp/__init__.py:
--------------------------------------------------------------------------------
1 | # coding: utf-8
2 | """
3 | Rich display for a variety of Python objects.
4 |
5 | Use the followign to enable permanently.
6 |
7 | >>> import disp; disp.install()
8 |
9 |
10 | The following activate rich repr on a couple of builtins types:
11 |
12 | - functions/methods
13 | - types
14 | - modules
15 |
16 | >>> import disp; disp.activate_builtins()
17 |
18 | As this may have side-effect the setting does not persist across sessions
19 |
20 |
21 | Some object are not enabled by default, you can activate with:
22 |
23 | >>> import disp; disp.activate_for(something)
24 |
25 | For example, a `requests`'s response.
26 |
27 | >>> import requests
28 | >>> response = requests.get(...)
29 | >>> disp.activate+for(response)
30 | >>> response
31 |
32 |
33 | """
34 |
35 | import sys
36 | import json
37 | from os import path
38 |
39 | from IPython import get_ipython, paths
40 | from .spark import repr_spark_context_html, repr_spark_session_html
41 |
42 | if sys.version_info < (3,):
43 | FileNotFoundError = IOError
44 | JSONDecodeError = ValueError
45 | else:
46 | from json.decoder import JSONDecodeError
47 |
48 |
49 | def load_ipython_extension(ipython):
50 | """
51 | Load an extension with IPython that tells it how to represent specifc
52 | objects.
53 | """
54 | html = ipython.display_formatter.formatters['text/html']
55 |
56 | html.for_type_by_name('pyspark.context','SparkContext', repr_spark_context_html)
57 | html.for_type_by_name('pyspark.sql', 'SparkSession', repr_spark_session_html)
58 |
59 |
60 | def activate_builtins():
61 | """
62 | Install html_repr for a couple of the builtin
63 | """
64 | if sys.version_info > (3, 6):
65 | ipython = get_ipython()
66 | html = ipython.display_formatter.formatters['text/html']
67 | import types
68 | from .py3only import html_formatter_for_builtin_function_or_method, html_formatter_for_type, html_formatter_for_module
69 | html.for_type(types.FunctionType, html_formatter_for_builtin_function_or_method)
70 | html.for_type(types.BuiltinFunctionType, html_formatter_for_builtin_function_or_method)
71 | html.for_type(types.BuiltinMethodType, html_formatter_for_builtin_function_or_method)
72 | html.for_type(types.MethodType, html_formatter_for_builtin_function_or_method)
73 | html.for_type(types.ModuleType, html_formatter_for_module)
74 |
75 | html.for_type(type, html_formatter_for_type)
76 |
77 |
78 | def activate_for(obj):
79 | ip = get_ipython()
80 | html = ip.display_formatter.formatters['text/html']
81 |
82 | if sys.version_info < (3,6):
83 | raise RuntimeError('Sorry need python 3.6 or greater')
84 | else:
85 | from . import py3only
86 | if type(obj) is type:
87 | target = obj
88 | else:
89 | target = type(obj)
90 |
91 | attr = getattr(py3only, 'html_formatter_for_'+target.__name__.replace('.', '_'))
92 | html.for_type(target, attr)
93 |
94 | def gen_help(obj):
95 | ip = get_ipython()
96 | from . import py3only
97 | html = ip.display_formatter.formatters['text/html']
98 | html.for_type(type(obj), py3only.gen_help)
99 |
100 |
101 |
102 |
103 | config_value = "disp"
104 | shell_key = "extensions"
105 | app_key = "InteractiveShellApp"
106 |
107 | def get_config():
108 | ip = get_ipython()
109 |
110 | if ip is None:
111 | profile_dir = paths.locate_profile()
112 | else:
113 | profile_dir = ip.profile_dir.location
114 |
115 | json_path = path.join(profile_dir, "ipython_config.json")
116 |
117 | try:
118 | with open(json_path, 'r') as f:
119 | config = json.load(f)
120 | except (FileNotFoundError, JSONDecodeError):
121 | config = {}
122 | return config, json_path
123 |
124 |
125 |
126 | def install():
127 | """Register `disp` as a default extension for IPython.
128 |
129 | When you run this inside IPython, the preference gets applied to the
130 | current IPython profile. When run using plain Python, the preference gets
131 | applied to the default profile.
132 |
133 | Run `uninstall()` if you ever change your mind and want to revert to the
134 | default IPython behavior.
135 | """
136 |
137 | cfg, json_path = get_config()
138 |
139 | installed = config_value in cfg.get(app_key, {}).get(shell_key, [])
140 |
141 | if installed:
142 | print("😕 Looks like disp is already installed.😕")
143 | return
144 |
145 | with open(json_path, 'w') as f:
146 | x = cfg.get(app_key, {}).get(shell_key, [])
147 | x.append(config_value)
148 | cfg.update({app_key: {shell_key: x}})
149 | json.dump(cfg, f)
150 |
151 | print("💖 Installation succeeded: enjoy disp ! 💖")
152 |
153 | def uninstall():
154 | cfg, json_path = get_config()
155 | if config_value not in cfg.get(app_key, {}).get(shell_key, []):
156 | print('😕 Disp is not installed. Aborting. 😕')
157 | return
158 | with open(json_path, 'w') as f:
159 | cfg.get(app_key, {}).get(shell_key).remove(config_value)
160 | json.dump(cfg, f)
161 |
162 | print(" 💖 Uninstalled disp. 😢")
163 |
--------------------------------------------------------------------------------
/disp/py3only.py:
--------------------------------------------------------------------------------
1 | """
2 | This submodule contains formatting utilities and formatters which will work only
3 | on Python 3.6+. There is no inherent reasons why it would not work on earlier
4 | version of Python, it just makes use of features that are 3.6 only – Like
5 | f-strings – to make the code more readable. Feel free to send patches that makes
6 | it compatible with earlier versions of python
7 | """
8 |
9 |
10 | from html import escape
11 | from typing import List
12 | from IPython.display import HTML
13 | from .vendor import get_repr_mimebundle
14 |
15 |
16 | text_formatter = get_ipython().display_formatter.formatters['text/plain']
17 |
18 |
19 | def repr(o):
20 | """
21 | Alternative implementation of repr, whcih goes through IPython display system from plain-text.
22 |
23 | We go directly though the formatter to avoid recursion complication with
24 | get_mime_types, ans for a tiny bit more speed.
25 |
26 | If the real repr is needed, then one need to use builtins.repr
27 | """
28 | return text_formatter(o)
29 |
30 |
31 | # This is the CSS we want to inject before each top-level object. We should
32 | # (try-to) make it to work with most frontend, as not all frontends do support
33 | # CSS injection, let's try to not rely on too much customisation
34 |
35 |
36 | thecss = """
37 |
38 | /* summary::-webkit-details-marker {
39 | display: none;
40 | }
41 |
42 | summary {
43 | text-decoration-line: underline;
44 | text-decoration-style: dotted;
45 |
46 | } */
47 |
48 | .rendered_html pre, .rendered_html code {
49 | background-color: transparent; /* bug in notebook css */
50 | }
51 |
52 | .rendered_html .jupyter-extra-info ul{
53 | list-style: none;
54 | }
55 |
56 | .jupyter-extra-info {
57 | background-color: hsla(0, 0%, 5%, 0.07);
58 | padding: 0.5em;
59 | border: thin solid silver;
60 | }
61 | dl.jupyter-inner-mapping-repr {
62 | padding-left: 1em;
63 | margin-bottom: 0;
64 | }
65 |
66 | dl.jupyter-inner-mapping-repr > dd {
67 | padding-left:2em;
68 | }
69 |
70 | ul.jupyter-flat-container-repr li > p{
71 | padding-left:2em;
72 | display: inline;
73 | padding: 0;
74 | }
75 |
76 | ul.jupyter-flat-container-repr, ul.jupyter-flat-container-repr ul , ul.jupyter-flat-container-repr ul il{
77 | list-style-type: none;
78 | display: inline;
79 | padding-left: 0;
80 | }
81 |
82 | ul.jupyter-flat-container-repr > details {
83 | display: inline-block;
84 | margin-left: -1em;
85 | }
86 |
87 | ul.jupyter-flat-container-repr li{
88 | padding-left:2em;
89 | list-style-type: none;
90 | }
91 |
92 | summary > code {
93 | display: inline
94 | }
95 |
96 | ul.jupyter-flat-container-repr summary {
97 | margin-left: 0em;
98 | display: inline-block;
99 | }
100 |
101 | .rendered_html ul.jupyter-flat-container-repr {
102 | padding-left: 0px;
103 | margin-left: 0em;
104 | }
105 |
106 | .jupyter-flat-container-repr details {
107 | display: inline;
108 | }
109 |
110 | .jupyter-flat-container-repr details ~ p {
111 | margin-top: 0;
112 | display: inline;
113 | }
114 |
115 | .jupyter-flat-container-repr details[open] ~ p {
116 | /*display: block;*/
117 | }
118 |
119 | details.jupyter-details[open] ~ .jupyter-breaking-placeholder {
120 | display: block;
121 | }
122 |
123 | .jupyter-details ~ .jupyter-breaking-placeholder {
124 | display: inline;
125 | }
126 | .output_subarea > ul.jupyter-flat-container-repr, .output_subarea > ul.jupyter-flat-container-repr > p {
127 | margin-left: 1em;
128 | }
129 | """
130 |
131 |
132 | ##########################################################################
133 | # Utilities #
134 | ##########################################################################
135 |
136 | def safe(obj):
137 | """
138 | Given an object (str, or html), return an HTML version.
139 |
140 | That is to say, if Object is already an HTML object, return it. If it's a string, escape it.
141 |
142 | """
143 | if isinstance(obj, HTML):
144 | return obj
145 | else:
146 | return HTML(htmlify_repr(obj))
147 |
148 |
149 | def htmlify_repr(obj)-> str:
150 | """
151 | Return a string which is safe to embed in html.
152 |
153 | ie, if obj define rerp_html, return this, otherwise escape its text_repr
154 | """
155 | return get_repr_mimebundle(obj).data.get('text/html', None) or\
156 | escape(repr(obj))
157 |
158 |
159 | def details(summary, details_):
160 | if details:
161 | rsum = safe(summary)._repr_html_()
162 | rdetails = safe(details_)._repr_html_()
163 | return HTML(f"{rsum}
{rdetails}{escape(string)}
")
172 |
173 |
174 | def well(s):
175 | s = safe(s)._repr_html_()
176 | return HTML('
{delims[1]}
204 |{escape(repr(req))}
{escape(repr(req))}
{escape(repr(obj))}
295 | """
296 |
297 |
298 | def general_repr(obj):
299 | return f'' +\
300 | f'{escape(repr(obj))}
' +\
301 | _inner_html_formatter_for_mapping({k: v for (k, v) in vars(obj).items() if not k.startswith('_')}) +\
302 | ''
303 |
304 |
305 | def html_formatter_for_type(obj):
306 | try:
307 | mro = obj.mro() # [o for o in if o is not object]
308 | except TypeError:
309 | mro = ()
310 | if len(mro) > 1:
311 | mime = get_repr_mimebundle(mro[1], include='text/html').data
312 | return f'' + \
313 | f'{escape(repr(obj))}
'\
314 | + well(HTML(f"""
315 | {obj.__doc__ or ''}
316 | Inherit from :
317 |
318 | - {mime.get('text/html')}
319 |
"""))._repr_html_()\
320 | + ''
321 | else:
322 | return f'' + f'{escape(repr(obj))}
'
323 |
324 |
325 | def html_formatter_for_builtin_function_or_method(obj):
326 | ip = get_ipython()
327 | res = {k: v for (k, v) in ip.inspector.info(obj).items() if v}
328 | docstring = res.get('docstring')
329 | res.pop('found')
330 | res.pop('string_form')
331 | res.pop('base_class')
332 | if res.get('definition', None):
333 | res['definition'] = code(obj.__name__ + res['definition'])
334 | if docstring != '':
335 | res['docstring'] = code(docstring)
336 | else:
337 | del res['docstring']
338 | return f'' + htmlify_repr(details(code(repr(obj)), well(HTML(_inner_html_formatter_for_mapping(res)))))
339 |
340 |
341 | def html_formatter_for_module(obj):
342 | return f'' + details(code(repr(obj)), well(code(obj.__doc__ or '')))._repr_html_()
343 |
--------------------------------------------------------------------------------
/disp/spark.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 |
4 |
5 | def fully_qualified_name(m):
6 | return (m.__module__ + "." if hasattr(m, "__module__") else "") + m.__class__.__name__
7 |
8 |
9 | def repr_spark_context_html(sc):
10 | '''
11 | Carry over from the Spark 2.2.0 _repr_html_ for spark contexts
12 |
13 | Works on objects whose fully qualified name is 'pyspark.context.SparkContext'
14 | '''
15 | return """
16 |
17 | SparkContext
18 |
19 |
20 |
21 |
22 | - Version
23 | v{sc.version}
24 | - Master
25 | {sc.master}
26 | - AppName
27 | {sc.appName}
28 |
29 |
30 | """.format(
31 | sc=sc
32 | )
33 |
34 |
35 | def repr_spark_session_html(session):
36 | '''
37 | Carry over from the Spark 2.2.0 _repr_html_ for spark sessions
38 |
39 | Works on objects whose fully qualified name is 'pyspark.sql.session.SparkSession'
40 | '''
41 | return """
42 |
43 | SparkSession - {catalogImplementation}
44 | {sc_HTML}
45 |
46 | """.format(
47 | catalogImplementation=session.conf.get("spark.sql.catalogImplementation"),
48 | sc_HTML=repr_sc(session.sparkContext)
49 | )
50 |
--------------------------------------------------------------------------------
/disp/vendor.py:
--------------------------------------------------------------------------------
1 |
2 | try:
3 | from IPython.core import DataMetadata, RecursiveObject, ReprGetter, get_repr_mimebundle
4 | except ImportError:
5 | from collections import namedtuple
6 |
7 | class RecursiveObject:
8 | """
9 | Default recursive object that provides a recursion repr if needed.
10 |
11 | You may register a formatter for this object that will be call when
12 | recursion is reached.
13 | """
14 |
15 | def __init__(self, already_seen):
16 | self.seen = already_seen
17 | pass
18 |
19 | def __repr__(self):
20 | return ''.format(str(self.seen))
21 |
22 | def _repr_html_(self):
23 | import html
24 | return '<recursion ... {}>'.format(html.escape(str(self.seen)))
25 |
26 |
27 |
28 | DataMetadata = namedtuple('DataMetadata', ('data','metadata'))
29 |
30 |
31 | class ReprGetter:
32 | """
33 | Object to carry recursion state when computing formating information when
34 | computing rich representation.
35 |
36 | useful when computing representation concurrently of nested object that may
37 | refer to common resources.
38 | """
39 |
40 | __slots__ = ('_objs',)
41 |
42 | def __init__(self):
43 | self._objs = set()
44 |
45 | def get_repr_mimebundle(self, obj, include=None, exclude=None, *, on_recursion=RecursiveObject):
46 | """
47 | return the representations of an object and associated metadata.
48 |
49 | An given object can have many representation available, that can be defined
50 | in many ways: `_repr_*_` methods, `_repr_mimebundle_`, or user-registered
51 | formatter for types.
52 |
53 | When given an object, :any:`get_repr_mimebundle` will search for the
54 | various formatting option with their associated priority and return the
55 | requested representation and associated metadata.
56 |
57 |
58 | Parameters
59 | ----------
60 | obj : an objects
61 | The Python objects to get the representation data.
62 | include : list, tuple or set, optional
63 | A list of format type strings (MIME types) to include in the
64 | format data dict. If this is set *only* the format types included
65 | in this list will be computed.
66 | exclude : list, tuple or set, optional
67 | A list of format type strings (MIME types) to exclude in the format
68 | data dict. If this is set all format types will be computed,
69 | except for those included in this argument.
70 | on_recursion: callable
71 | Return an object to compute the representation when recursion is
72 | detected.
73 |
74 |
75 | Returns
76 | -------
77 | (data, metadata) : named tuple of two dicts
78 |
79 | - 0/.data: See :any:`DisplayFormatter.format`.
80 | - 1/.metadata: See :any:`DisplayFormatter.format`
81 |
82 | Note
83 | ----
84 |
85 | When :any:`get_repr_mimebundle` detect it is recursively called, it will
86 | attempt to return the representation of :class:`RecursiveObject`. You
87 | may register extra formatter for :class:`RecursiveObject`.
88 |
89 | If you are computing objects representation in a concurrent way (thread,
90 | coroutines, ...), you should make sure to instanciate a
91 | :class:`ReprGetter` object and use one per task to avoid race conditions.
92 |
93 | If a specific mimetype formatter need to call `get_repr_mimebundle()`
94 | for another mimeformat, then it must pass the mimetypes values it desire
95 | to `include` in order to correctly avoid recursion
96 |
97 | See Also
98 | --------
99 | :func:`display`, :any:`DisplayFormatter.format`
100 |
101 | """
102 | from IPython.core.interactiveshell import InteractiveShell
103 | if isinstance(include, str):
104 | include = (include,)
105 | if not include:
106 | keys = {(id(obj), None)}
107 | else:
108 | keys = {(id(obj), f) for f in include}
109 | fmt = InteractiveShell.instance().display_formatter.format
110 | if id(obj) == id(object):
111 | return DataMetadata({'text/plain':""}, {})
112 | if self._objs.intersection(keys):
113 | return DataMetadata(*fmt(on_recursion(obj), include=include, exclude=exclude))
114 | else:
115 | try:
116 | self._objs.update(keys)
117 | return DataMetadata(*fmt(obj, include=include, exclude=exclude))
118 | finally:
119 | self._objs.difference_update(keys)
120 |
121 | # Expose this for convenience at the top level. Similar to what the random
122 | # module in python does. If you want to avoid weird behavior from concurrency:
123 | # Instantiate your own.
124 | get_repr_mimebundle = ReprGetter().get_repr_mimebundle
125 |
--------------------------------------------------------------------------------
/example/Disp-Example-builtins.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# Disp Example"
8 | ]
9 | },
10 | {
11 | "cell_type": "markdown",
12 | "metadata": {},
13 | "source": [
14 | "This is an example on how you can use disp to make the environement you use richer."
15 | ]
16 | },
17 | {
18 | "cell_type": "markdown",
19 | "metadata": {},
20 | "source": [
21 | "Let's have a quick look at a nor mal workflow, and how objects are show in the notebook: "
22 | ]
23 | },
24 | {
25 | "cell_type": "code",
26 | "execution_count": 1,
27 | "metadata": {},
28 | "outputs": [
29 | {
30 | "data": {
31 | "text/plain": [
32 | "IPython.core.interactiveshell.InteractiveShell"
33 | ]
34 | },
35 | "execution_count": 1,
36 | "metadata": {},
37 | "output_type": "execute_result"
38 | }
39 | ],
40 | "source": [
41 | "from IPython.terminal.interactiveshell import InteractiveShell\n",
42 | "import disp\n",
43 | "InteractiveShell"
44 | ]
45 | },
46 | {
47 | "cell_type": "code",
48 | "execution_count": 2,
49 | "metadata": {},
50 | "outputs": [
51 | {
52 | "data": {
53 | "text/plain": [
54 | ""
55 | ]
56 | },
57 | "execution_count": 2,
58 | "metadata": {},
59 | "output_type": "execute_result"
60 | }
61 | ],
62 | "source": [
63 | "print"
64 | ]
65 | },
66 | {
67 | "cell_type": "code",
68 | "execution_count": 3,
69 | "metadata": {},
70 | "outputs": [
71 | {
72 | "data": {
73 | "text/plain": [
74 | ""
75 | ]
76 | },
77 | "execution_count": 3,
78 | "metadata": {},
79 | "output_type": "execute_result"
80 | }
81 | ],
82 | "source": [
83 | "disp"
84 | ]
85 | },
86 | {
87 | "cell_type": "markdown",
88 | "metadata": {},
89 | "source": [
90 | "This is a bit boring, and not always informative. Let's enable disp for builtin types. We don't do it by default, as it can be heavily computation intensive and does nto work outside of IPython. It will also make your notebook files way larger. "
91 | ]
92 | },
93 | {
94 | "cell_type": "code",
95 | "execution_count": 4,
96 | "metadata": {},
97 | "outputs": [],
98 | "source": [
99 | "import disp\n",
100 | "disp.activate_builtins()"
101 | ]
102 | },
103 | {
104 | "cell_type": "markdown",
105 | "metadata": {},
106 | "source": [
107 | "Let's have a look again at previous objects:"
108 | ]
109 | },
110 | {
111 | "cell_type": "code",
112 | "execution_count": 5,
113 | "metadata": {},
114 | "outputs": [
115 | {
116 | "data": {
117 | "text/html": [
118 | "IPython.core.interactiveshell.InteractiveShell
\n",
212 | " An enhanced, interactive shell for Python.
\n",
213 | " Inherit from :
\n",
214 | " \n",
215 | " traitlets.config.configurable.SingletonConfigurable
\n",
309 | " A configurable that only allows one instance.\n",
310 | "\n",
311 | " This class is for classes that should only have one instance of itself\n",
312 | " or *any* subclass. To create and retrieve such a class use the\n",
313 | " :meth:`SingletonConfigurable.instance` method.\n",
314 | "
\n",
315 | " Inherit from :
\n",
316 | " \n",
317 | " traitlets.config.configurable.LoggingConfigurable
\n",
411 | " A parent class for Configurables that log.\n",
412 | "\n",
413 | " Subclasses have a log trait, and the default behavior\n",
414 | " is to get the logger from the currently running Application.\n",
415 | "
\n",
416 | " Inherit from :
\n",
417 | " \n",
418 | " traitlets.config.configurable.Configurable
\n",
512 | "
\n",
513 | " Inherit from :
\n",
514 | " \n",
515 | " traitlets.traitlets.HasTraits
\n",
609 | "
\n",
610 | " Inherit from :
\n",
611 | " \n",
612 | " traitlets.traitlets.HasDescriptors
\n",
706 | " The base class for all classes that have descriptors.\n",
707 | "
\n",
708 | " Inherit from :
\n",
709 | " \n",
710 | " - None
\n",
711 | "
\n",
712 | "
\n",
713 | "
\n",
714 | "
\n",
715 | "
\n",
716 | "
"
717 | ],
718 | "text/plain": [
719 | "IPython.core.interactiveshell.InteractiveShell"
720 | ]
721 | },
722 | "execution_count": 5,
723 | "metadata": {},
724 | "output_type": "execute_result"
725 | }
726 | ],
727 | "source": [
728 | "InteractiveShell"
729 | ]
730 | },
731 | {
732 | "cell_type": "markdown",
733 | "metadata": {},
734 | "source": [
735 | "You should see now (at least if you are in an interactive environement) a small triangle in front of `IPython.core.interactiveshell.InteractiveShell`, if you click on it, the output will expand to show you the documentation as well as the inheritence (Actually the MRO... but details for now)."
736 | ]
737 | },
738 | {
739 | "cell_type": "code",
740 | "execution_count": 6,
741 | "metadata": {},
742 | "outputs": [
743 | {
744 | "data": {
745 | "text/html": [
746 | "<function print>
\n",
840 | " - type_name:
\n",
841 | " - 'builtin_function_or_method'
\n",
842 | "
\n",
843 | " \n",
844 | " - docstring:
\n",
845 | " print(value, ..., sep=' ', end='\\n', file=sys.stdout, flush=False)\n",
846 | "\n",
847 | "Prints the values to a stream, or to sys.stdout by default.\n",
848 | "Optional keyword arguments:\n",
849 | "file: a file-like object (stream); defaults to the current sys.stdout.\n",
850 | "sep: string inserted between values, default a space.\n",
851 | "end: string appended after the last value, default a newline.\n",
852 | "flush: whether to forcibly flush the stream.
\n",
853 | "
\n",
854 | " "
855 | ],
856 | "text/plain": [
857 | ""
858 | ]
859 | },
860 | "execution_count": 6,
861 | "metadata": {},
862 | "output_type": "execute_result"
863 | }
864 | ],
865 | "source": [
866 | "print"
867 | ]
868 | },
869 | {
870 | "cell_type": "markdown",
871 | "metadata": {},
872 | "source": [
873 | "Print wil have the same treatment, with an overview of the documetation. You can still use `?`/`??` to get more information. "
874 | ]
875 | },
876 | {
877 | "cell_type": "code",
878 | "execution_count": 7,
879 | "metadata": {},
880 | "outputs": [
881 | {
882 | "data": {
883 | "text/html": [
884 | "<module 'disp' from '/Users/bussonniermatthias/dev/disp/disp/__init__.py'>
\n",
978 | "Rich display for a variety of Python objects.\n",
979 | "\n",
980 | "Use the followign to enable permanently.\n",
981 | "\n",
982 | ">>> import disp; disp.install()\n",
983 | "\n",
984 | "\n",
985 | "The following activate rich repr on a couple of builtins types:\n",
986 | "\n",
987 | " - functions/methods\n",
988 | " - types\n",
989 | " - modules\n",
990 | "\n",
991 | ">>> import disp; disp.activate_builtins()\n",
992 | "\n",
993 | "As this may have side-effect the setting does not persist across sessions\n",
994 | "\n",
995 | "\n",
996 | "Some object are not enabled by default, you can activate with:\n",
997 | "\n",
998 | ">>> import disp; disp.activate_for(something)\n",
999 | "\n",
1000 | "For example, a `requests`'s response. \n",
1001 | "\n",
1002 | ">>> import requests\n",
1003 | ">>> response = requests.get(...)\n",
1004 | ">>> disp.activate+for(response)\n",
1005 | ">>> response\n",
1006 | "\n",
1007 | "\n",
1008 | "
"
1009 | ],
1010 | "text/plain": [
1011 | ""
1012 | ]
1013 | },
1014 | "execution_count": 7,
1015 | "metadata": {},
1016 | "output_type": "execute_result"
1017 | }
1018 | ],
1019 | "source": [
1020 | "disp"
1021 | ]
1022 | },
1023 | {
1024 | "cell_type": "markdown",
1025 | "metadata": {},
1026 | "source": [
1027 | "If modules have docstrings, they will be shown as well. "
1028 | ]
1029 | },
1030 | {
1031 | "cell_type": "markdown",
1032 | "metadata": {},
1033 | "source": [
1034 | "## Requests"
1035 | ]
1036 | },
1037 | {
1038 | "cell_type": "markdown",
1039 | "metadata": {},
1040 | "source": [
1041 | "Above are generic objects, `disp` also have special casing for some objects, example `requests` replies. "
1042 | ]
1043 | },
1044 | {
1045 | "cell_type": "code",
1046 | "execution_count": 8,
1047 | "metadata": {},
1048 | "outputs": [],
1049 | "source": [
1050 | "import requests\n",
1051 | "import requests_cache\n",
1052 | "requests_cache.install_cache('tmpcache.db')\n",
1053 | "\n",
1054 | "res = requests.get('https://api.github.com/aoisehgd')"
1055 | ]
1056 | },
1057 | {
1058 | "cell_type": "markdown",
1059 | "metadata": {},
1060 | "source": [
1061 | "`get` is still a generic function, so will show its doc:"
1062 | ]
1063 | },
1064 | {
1065 | "cell_type": "code",
1066 | "execution_count": 9,
1067 | "metadata": {},
1068 | "outputs": [
1069 | {
1070 | "data": {
1071 | "text/html": [
1072 | "<function requests.api.get>
\n",
1166 | " - type_name:
\n",
1167 | " - 'function'
\n",
1168 | "
\n",
1169 | " \n",
1170 | " - file:
\n",
1171 | " - '~/anaconda/lib/python3.6/site-packages/requests/api.py'
\n",
1172 | "
\n",
1173 | " \n",
1174 | " - definition:
\n",
1175 | " get(url, params=None, **kwargs)
\n",
1176 | "
\n",
1177 | " \n",
1178 | " - docstring:
\n",
1179 | " Sends a GET request.\n",
1180 | "\n",
1181 | ":param url: URL for the new :class:`Request` object.\n",
1182 | ":param params: (optional) Dictionary or bytes to be sent in the query string for the :class:`Request`.\n",
1183 | ":param \\*\\*kwargs: Optional arguments that ``request`` takes.\n",
1184 | ":return: :class:`Response <Response>` object\n",
1185 | ":rtype: requests.Response
\n",
1186 | "
\n",
1187 | " \n",
1188 | " - argspec:
\n",
1189 | " - {'annotations': {},\n",
1190 | " 'args': ['url', 'params'],\n",
1191 | " 'defaults': (None,),\n",
1192 | " 'kwonlyargs': [],\n",
1193 | " 'kwonlydefaults': None,\n",
1194 | " 'varargs': None,\n",
1195 | " 'varkw': 'kwargs'}
\n",
1196 | "
\n",
1197 | " "
1198 | ],
1199 | "text/plain": [
1200 | ""
1201 | ]
1202 | },
1203 | "execution_count": 9,
1204 | "metadata": {},
1205 | "output_type": "execute_result"
1206 | }
1207 | ],
1208 | "source": [
1209 | "requests.get # this is a function, alerady covered by activate_builtins()"
1210 | ]
1211 | },
1212 | {
1213 | "cell_type": "markdown",
1214 | "metadata": {},
1215 | "source": [
1216 | "By default again the repr is not enabled:"
1217 | ]
1218 | },
1219 | {
1220 | "cell_type": "code",
1221 | "execution_count": 10,
1222 | "metadata": {},
1223 | "outputs": [
1224 | {
1225 | "data": {
1226 | "text/plain": [
1227 | ""
1228 | ]
1229 | },
1230 | "execution_count": 10,
1231 | "metadata": {},
1232 | "output_type": "execute_result"
1233 | }
1234 | ],
1235 | "source": [
1236 | "res"
1237 | ]
1238 | },
1239 | {
1240 | "cell_type": "code",
1241 | "execution_count": 11,
1242 | "metadata": {},
1243 | "outputs": [
1244 | {
1245 | "data": {
1246 | "text/html": [
1247 | "requests.models.Response
\n",
1341 | " The :class:`Response ` object, which contains a\n",
1342 | " server's response to an HTTP request.\n",
1343 | "
\n",
1344 | " Inherit from :
\n",
1345 | " \n",
1346 | " - None
\n",
1347 | "
"
1348 | ],
1349 | "text/plain": [
1350 | "requests.models.Response"
1351 | ]
1352 | },
1353 | "execution_count": 11,
1354 | "metadata": {},
1355 | "output_type": "execute_result"
1356 | }
1357 | ],
1358 | "source": [
1359 | "type(res) # this is a type, already cover by activate_builtins()"
1360 | ]
1361 | },
1362 | {
1363 | "cell_type": "markdown",
1364 | "metadata": {},
1365 | "source": [
1366 | "let's activate it:"
1367 | ]
1368 | },
1369 | {
1370 | "cell_type": "code",
1371 | "execution_count": 12,
1372 | "metadata": {},
1373 | "outputs": [],
1374 | "source": [
1375 | "disp.activate_for(res) # install for res (actually for type(res), but we infer that if what is given is an instance)"
1376 | ]
1377 | },
1378 | {
1379 | "cell_type": "code",
1380 | "execution_count": 13,
1381 | "metadata": {
1382 | "scrolled": false
1383 | },
1384 | "outputs": [
1385 | {
1386 | "data": {
1387 | "text/html": [
1388 | "\n",
1389 | " \n",
1485 | " <Response [404]>
\n",
1486 | " \n",
1487 | " - status_code:
\n",
1488 | " - 404
\n",
1489 | "
\n",
1490 | " \n",
1491 | " - headers:
\n",
1492 | " - \n",
1493 | " \n",
1494 | "
{
\n",
1495 | " \n",
1496 | " - Date:
\n",
1497 | " - 'Mon, 19 Jun 2017 18:49:54 GMT'
\n",
1498 | "
\n",
1499 | " \n",
1500 | " - Content-Type:
\n",
1501 | " - 'application/json; charset=utf-8'
\n",
1502 | "
\n",
1503 | " \n",
1504 | " - Transfer-Encoding:
\n",
1505 | " - 'chunked'
\n",
1506 | "
\n",
1507 | " \n",
1508 | " - Server:
\n",
1509 | " - 'GitHub.com'
\n",
1510 | "
\n",
1511 | " \n",
1512 | " - Status:
\n",
1513 | " - '404 Not Found'
\n",
1514 | "
\n",
1515 | " \n",
1516 | " - X-RateLimit-Limit:
\n",
1517 | " - '60'
\n",
1518 | "
\n",
1519 | " \n",
1520 | " - X-RateLimit-Remaining:
\n",
1521 | " - '51'
\n",
1522 | "
\n",
1523 | " \n",
1524 | " - X-RateLimit-Reset:
\n",
1525 | " - '1497900396'
\n",
1526 | "
\n",
1527 | " \n",
1528 | " - X-GitHub-Media-Type:
\n",
1529 | " - 'github.v3; format=json'
\n",
1530 | "
\n",
1531 | " \n",
1532 | " - Access-Control-Expose-Headers:
\n",
1533 | " - 'ETag, Link, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval'
\n",
1534 | "
\n",
1535 | " \n",
1536 | " - Access-Control-Allow-Origin:
\n",
1537 | " - '*'
\n",
1538 | "
\n",
1539 | " \n",
1540 | " - Content-Security-Policy:
\n",
1541 | " - "default-src 'none'"
\n",
1542 | "
\n",
1543 | " \n",
1544 | " - Strict-Transport-Security:
\n",
1545 | " - 'max-age=31536000; includeSubdomains; preload'
\n",
1546 | "
\n",
1547 | " \n",
1548 | " - X-Content-Type-Options:
\n",
1549 | " - 'nosniff'
\n",
1550 | "
\n",
1551 | " \n",
1552 | " - X-Frame-Options:
\n",
1553 | " - 'deny'
\n",
1554 | "
\n",
1555 | " \n",
1556 | " - X-XSS-Protection:
\n",
1557 | " - '1; mode=block'
\n",
1558 | "
\n",
1559 | " \n",
1560 | " - X-Runtime-rack:
\n",
1561 | " - '0.039253'
\n",
1562 | "
\n",
1563 | " \n",
1564 | " - Content-Encoding:
\n",
1565 | " - 'gzip'
\n",
1566 | "
\n",
1567 | " \n",
1568 | " - X-GitHub-Request-Id:
\n",
1569 | " - 'A624:B330:A1C5E3:CA86F4:59481CD1'
\n",
1570 | "
\n",
1571 | " \n",
1572 | " \n",
1573 | " }\n",
1574 | " \n",
1575 | "
\n",
1576 | " \n",
1577 | " - raw:
\n",
1578 | " - <requests.packages.urllib3.response.HTTPResponse at 0x10c4ac630>
\n",
1579 | "
\n",
1580 | " \n",
1581 | " - url:
\n",
1582 | " - 'https://api.github.com/aoisehgd'
\n",
1583 | "
\n",
1584 | " \n",
1585 | " - encoding:
\n",
1586 | " - 'utf-8'
\n",
1587 | "
\n",
1588 | " \n",
1589 | " - history:
\n",
1590 | " - []
\n",
1591 | "
\n",
1592 | " \n",
1593 | " - reason:
\n",
1594 | " - 'Not Found'
\n",
1595 | "
\n",
1596 | " \n",
1597 | " - cookies:
\n",
1598 | " - <RequestsCookieJar[]>
\n",
1599 | "
\n",
1600 | " \n",
1601 | " - elapsed:
\n",
1602 | " - datetime.timedelta(0, 0, 926297)
\n",
1603 | "
\n",
1604 | " \n",
1605 | " - request:
\n",
1606 | " - <PreparedRequest [GET]>
\n",
1607 | "
\n",
1608 | " \n",
1609 | " - connection:
\n",
1610 | " - <requests.adapters.HTTPAdapter at 0x10c478588>
\n",
1611 | "
\n",
1612 | " \n",
1613 | " - from_cache:
\n",
1614 | " - False
\n",
1615 | "
\n",
1616 | " \n",
1617 | " \n",
1618 | " Content (JSON)
\n",
1619 | " \n",
1620 | " - message:
\n",
1621 | " - 'Not Found'
\n",
1622 | "
\n",
1623 | " \n",
1624 | " - documentation_url:
\n",
1625 | " - 'https://developer.github.com/v3'
\n",
1626 | "
\n",
1627 | " \n",
1628 | " \n",
1629 | " \n",
1630 | " "
1631 | ],
1632 | "text/plain": [
1633 | ""
1634 | ]
1635 | },
1636 | "execution_count": 13,
1637 | "metadata": {},
1638 | "output_type": "execute_result"
1639 | }
1640 | ],
1641 | "source": [
1642 | "res"
1643 | ]
1644 | },
1645 | {
1646 | "cell_type": "markdown",
1647 | "metadata": {},
1648 | "source": [
1649 | "We know have 1 click access to the content (if json), neatly formatted, and collapsible. we also have special cased the header field."
1650 | ]
1651 | },
1652 | {
1653 | "cell_type": "markdown",
1654 | "metadata": {},
1655 | "source": [
1656 | "## Beta feature"
1657 | ]
1658 | },
1659 | {
1660 | "cell_type": "markdown",
1661 | "metadata": {},
1662 | "source": [
1663 | "you can actually activate rich display for arbitrary container (making them collapsible), though this can have nasty side effects, so use at your own risk:"
1664 | ]
1665 | },
1666 | {
1667 | "cell_type": "code",
1668 | "execution_count": 14,
1669 | "metadata": {},
1670 | "outputs": [],
1671 | "source": [
1672 | "from IPython.display import HTML"
1673 | ]
1674 | },
1675 | {
1676 | "cell_type": "code",
1677 | "execution_count": 15,
1678 | "metadata": {},
1679 | "outputs": [
1680 | {
1681 | "data": {
1682 | "text/plain": [
1683 | "({},\n",
1684 | " ,\n",
1685 | " IPython.display.HTML,\n",
1686 | " [{'This is a key': 'and its value', 'hello': 'world'}, 123456789],\n",
1687 | " ,\n",
1688 | " set())"
1689 | ]
1690 | },
1691 | "execution_count": 15,
1692 | "metadata": {},
1693 | "output_type": "execute_result"
1694 | }
1695 | ],
1696 | "source": [
1697 | "ex = ({}, print, HTML, [{'hello':'world','This is a key':'and its value'}, 123456789], HTML('BOLD'), set())\n",
1698 | "ex"
1699 | ]
1700 | },
1701 | {
1702 | "cell_type": "code",
1703 | "execution_count": 16,
1704 | "metadata": {},
1705 | "outputs": [],
1706 | "source": [
1707 | "disp.activate_for(list)\n",
1708 | "disp.activate_for(tuple)\n",
1709 | "disp.activate_for(set)\n",
1710 | "disp.activate_for(dict)"
1711 | ]
1712 | },
1713 | {
1714 | "cell_type": "code",
1715 | "execution_count": 17,
1716 | "metadata": {},
1717 | "outputs": [
1718 | {
1719 | "data": {
1720 | "text/html": [
1721 | "\n",
1722 | " \n",
1723 | " (
\n",
1724 | " - dict({}),
<function print>
\n",
1818 | " - type_name:
\n",
1819 | " - 'builtin_function_or_method'
\n",
1820 | "
\n",
1821 | " \n",
1822 | " - docstring:
\n",
1823 | " print(value, ..., sep=' ', end='\\n', file=sys.stdout, flush=False)\n",
1824 | "\n",
1825 | "Prints the values to a stream, or to sys.stdout by default.\n",
1826 | "Optional keyword arguments:\n",
1827 | "file: a file-like object (stream); defaults to the current sys.stdout.\n",
1828 | "sep: string inserted between values, default a space.\n",
1829 | "end: string appended after the last value, default a newline.\n",
1830 | "flush: whether to forcibly flush the stream.
\n",
1831 | "
\n",
1832 | " ,IPython.display.HTML
\n",
1926 | "
\n",
1927 | " Inherit from :
\n",
1928 | " \n",
1929 | " IPython.display.TextDisplayObject
\n",
2023 | " Validate that display data is text
\n",
2024 | " Inherit from :
\n",
2025 | " \n",
2026 | " IPython.display.DisplayObject
\n",
2120 | " An object that wraps data to be displayed.
\n",
2121 | " Inherit from :
\n",
2122 | " \n",
2123 | " - None
\n",
2124 | "
\n",
2125 | "
\n",
2126 | "
,\n",
2127 | " \n",
2128 | " [
\n",
2129 | " - \n",
2130 | " \n",
2131 | "
{
\n",
2132 | " \n",
2133 | " - hello:
\n",
2134 | " - 'world'
\n",
2135 | "
\n",
2136 | " \n",
2137 | " - This is a key:
\n",
2138 | " - 'and its value'
\n",
2139 | "
\n",
2140 | " \n",
2141 | " \n",
2142 | " }\n",
2143 | " , - 123456789
\n",
2144 | " \n",
2145 | " ]
\n",
2146 | "
\n",
2147 | "\n",
2148 | " ,- BOLD,
- set({})
\n",
2149 | " \n",
2150 | " )
\n",
2151 | "
\n",
2152 | "\n",
2153 | " "
2154 | ],
2155 | "text/plain": [
2156 | "({},\n",
2157 | " ,\n",
2158 | " IPython.display.HTML,\n",
2159 | " [{'This is a key': 'and its value', 'hello': 'world'}, 123456789],\n",
2160 | " ,\n",
2161 | " set())"
2162 | ]
2163 | },
2164 | "execution_count": 17,
2165 | "metadata": {},
2166 | "output_type": "execute_result"
2167 | }
2168 | ],
2169 | "source": [
2170 | "ex"
2171 | ]
2172 | }
2173 | ],
2174 | "metadata": {
2175 | "kernel_info": {
2176 | "name": "pythonroot"
2177 | },
2178 | "kernelspec": {
2179 | "display_name": "PythonRoot",
2180 | "language": "python",
2181 | "name": "pythonroot"
2182 | },
2183 | "language_info": {
2184 | "codemirror_mode": {
2185 | "name": "ipython",
2186 | "version": 3
2187 | },
2188 | "file_extension": ".py",
2189 | "mimetype": "text/x-python",
2190 | "name": "python",
2191 | "nbconvert_exporter": "python",
2192 | "pygments_lexer": "ipython3",
2193 | "version": "3.6.0"
2194 | }
2195 | },
2196 | "nbformat": 4,
2197 | "nbformat_minor": 2
2198 | }
2199 |
--------------------------------------------------------------------------------
/pretty-context.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ipython/disp/2b604763ccacac0c1e3fcaa1b8c43cf10fec577c/pretty-context.png
--------------------------------------------------------------------------------
/setup.cfg:
--------------------------------------------------------------------------------
1 | [bdist_wheel]
2 | universal=1
3 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | from setuptools import setup
2 |
3 | description='Providing default representations of common objects in Python land',
4 |
5 | try:
6 | import pypandoc
7 | description = pypandoc.convert(open('README.md','r').read(), format='markdown', to='rst')
8 | except:
9 | print('Issues running or importing pypandoc. If you are publishing the package the description will be missing.')
10 |
11 | setup(name='disp',
12 | version='0.0.3',
13 | description='Providing default representations of common objects in Python land',
14 | url='http://github.com/ipython/disp',
15 | author='IPython developers',
16 | author_email='ipython-dev@python.org',
17 | license='BSD',
18 | packages=['disp'],
19 | zip_safe=False)
20 |
--------------------------------------------------------------------------------