Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 13 additions & 3 deletions google/colab/_inspector.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import math
import re
import types
import warnings

from IPython.core import oinspect
from IPython.utils import dir2
Expand Down Expand Up @@ -475,6 +476,17 @@ def _getdef(self, obj, oname=''):
except: # pylint: disable=bare-except
logging.exception('Exception raised in ColabInspector._getdef')
def info(self, obj, oname='', formatter=None, info=None, detail_level=0):
"""Compute a dict with detailed information about an object."""
if formatter is not None:
warnings.warn(
'The `formatter` keyword argument to `Inspector.info`'
'is deprecated as of IPython 5.0 and will have no effects.',
DeprecationWarning,
stacklevel=2,
)
return self._info(obj, oname=oname, info=info, detail_level=detail_level)

def _info(self, obj, oname='', info=None, detail_level=0):
"""Compute a dict with detailed information about an object.

This overrides the superclass method for two main purposes:
Expand All @@ -484,7 +496,6 @@ def info(self, obj, oname='', formatter=None, info=None, detail_level=0):
Args:
obj: object to inspect.
oname: (optional) string reference to this object
formatter: (optional) custom docstring formatter
info: (optional) previously computed information about obj
detail_level: (optional) 0 or 1; 1 means "include more detail"

Expand Down Expand Up @@ -572,8 +583,7 @@ def info(self, obj, oname='', formatter=None, info=None, detail_level=0):
if source is not None:
out['source'] = source
if 'source' not in out:
formatter = formatter or (lambda x: x)
docstring = formatter(getdoc(obj) or '<no docstring>')
docstring = getdoc(obj) or '<no docstring>'
if docstring:
out['docstring'] = docstring

Expand Down
20 changes: 18 additions & 2 deletions google/colab/_kernel.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@
from ipykernel import jsonutil
from IPython.utils import tokenutil

# Only include info_text if less than 2 MiB. We have seen frontend lockup
# issues when this is very large. See b/401357469 for more details.
# 2 MiB is chosen as an arbitrary starting point.
_MAX_INSPECT_TEXT_SIZE = 2**20 # 2 MiB


class Kernel(ipkernel.IPythonKernel):
"""Kernel with additional Colab-specific features."""
Expand All @@ -31,7 +36,19 @@ def do_inspect(self, code, cursor_pos, detail_level=0, *args, **kwargs):
info = self.shell.object_inspect(name)

data = {}
if info['found']:
if info.get('found'):
info_text = self.shell.object_inspect_text(
name, detail_level=detail_level
)
if len(info_text) < _MAX_INSPECT_TEXT_SIZE:
data['text/plain'] = info_text
else:
self.log.warning(
'do_inspect text/plain output omitted as it was too large:'
' size %d bytes',
len(info_text),
)

# Provide the structured inspection information to allow the frontend to
# format as desired.
argspec = info.get('argspec')
Expand All @@ -51,7 +68,6 @@ def do_inspect(self, code, cursor_pos, detail_level=0, *args, **kwargs):
'metadata': {},
'found': info['found'],
}

return reply_content

def complete_request(self, stream, ident, parent):
Expand Down
32 changes: 31 additions & 1 deletion google/colab/_shell.py
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,36 @@ def _getattr_property(obj, attrname):
# Nothing helped, fall back.
return getattr(obj, attrname)

def object_inspect_text(self, oname, detail_level=0):
"""Get object info as formatted text."""
info = self._ofind(oname)
if not info.get('found'):
return ''
try:
info = self._object_find(oname)
# We need to avoid arbitrary python objects remaining in info (and
# potentially being serialized below); `obj` itself needs to be
# removed, but retained for use below, and `parent` isn't used at all.
obj = info.pop('obj', '')
info.pop('parent', '')
# Follow the InteractiveShell base class implementation and call
# directly into the inspector's _get_info method.
# pylint: disable=protected-access
result = self.inspector._get_info(
obj,
oname,
info=info,
detail_level=detail_level,
)
return result['text/plain']
except Exception as e: # pylint: disable=broad-except
self.kernel.log.info(
'Exception caught during object text inspection: %s\nTraceback:\n%s',
repr(e),
''.join(traceback.format_tb(sys.exc_info()[2])),
)
return ''

def object_inspect(self, oname, detail_level=0):
info = self._ofind(oname)

Expand All @@ -259,7 +289,7 @@ def object_inspect(self, oname, detail_level=0):
e, ''.join(traceback.format_tb(sys.exc_info()[2]))
)
)
result = oinspect.InfoDict()
result = oinspect.object_info()
else:
result = super(Shell, self).object_inspect(
oname, detail_level=detail_level
Expand Down