Navigation Menu

Skip to content

Commit

Permalink
Move object inspection machinery out of the magics code.
Browse files Browse the repository at this point in the history
Later we'll put this into a standalone object, but the least intrusive
change for now is to put it in the main interactive shell object.  At
least now it's not embedded in the magics code, and we can start using
this programatically via the messaging api.
  • Loading branch information
fperez committed Sep 3, 2010
1 parent 2be9133 commit 4e3685b
Show file tree
Hide file tree
Showing 2 changed files with 136 additions and 132 deletions.
138 changes: 136 additions & 2 deletions IPython/core/interactiveshell.py
Expand Up @@ -18,6 +18,7 @@
from __future__ import absolute_import

import __builtin__
import __future__
import abc
import codeop
import exceptions
Expand All @@ -40,15 +41,15 @@
from IPython.core.builtin_trap import BuiltinTrap
from IPython.core.display_trap import DisplayTrap
from IPython.core.displayhook import DisplayHook
from IPython.core.error import UsageError
from IPython.core.error import TryNext, UsageError
from IPython.core.extensions import ExtensionManager
from IPython.core.fakemodule import FakeModule, init_fakemod_dict
from IPython.core.inputlist import InputList
from IPython.core.logger import Logger
from IPython.core.magic import Magic
from IPython.core.payload import PayloadManager
from IPython.core.plugin import PluginManager
from IPython.core.prefilter import PrefilterManager
from IPython.core.prefilter import PrefilterManager, ESC_MAGIC
from IPython.external.Itpl import ItplNS
from IPython.utils import PyColorize
from IPython.utils import io
Expand Down Expand Up @@ -1025,6 +1026,139 @@ def push(self, variables, interactive=True):
for name,val in vdict.iteritems():
config_ns[name] = val

#-------------------------------------------------------------------------
# Things related to object introspection
#-------------------------------------------------------------------------
def _ofind(self, oname, namespaces=None):
"""Find an object in the available namespaces.
self._ofind(oname) -> dict with keys: found,obj,ospace,ismagic
Has special code to detect magic functions.
"""
oname = oname.strip()
alias_ns = None
if namespaces is None:
# Namespaces to search in:
# Put them in a list. The order is important so that we
# find things in the same order that Python finds them.
namespaces = [ ('Interactive', self.shell.user_ns),
('IPython internal', self.shell.internal_ns),
('Python builtin', __builtin__.__dict__),
('Alias', self.shell.alias_manager.alias_table),
]
alias_ns = self.shell.alias_manager.alias_table

# initialize results to 'null'
found = False; obj = None; ospace = None; ds = None;
ismagic = False; isalias = False; parent = None

# We need to special-case 'print', which as of python2.6 registers as a
# function but should only be treated as one if print_function was
# loaded with a future import. In this case, just bail.
if (oname == 'print' and not (self.shell.compile.compiler.flags &
__future__.CO_FUTURE_PRINT_FUNCTION)):
return {'found':found, 'obj':obj, 'namespace':ospace,
'ismagic':ismagic, 'isalias':isalias, 'parent':parent}

# Look for the given name by splitting it in parts. If the head is
# found, then we look for all the remaining parts as members, and only
# declare success if we can find them all.
oname_parts = oname.split('.')
oname_head, oname_rest = oname_parts[0],oname_parts[1:]
for nsname,ns in namespaces:
try:
obj = ns[oname_head]
except KeyError:
continue
else:
#print 'oname_rest:', oname_rest # dbg
for part in oname_rest:
try:
parent = obj
obj = getattr(obj,part)
except:
# Blanket except b/c some badly implemented objects
# allow __getattr__ to raise exceptions other than
# AttributeError, which then crashes IPython.
break
else:
# If we finish the for loop (no break), we got all members
found = True
ospace = nsname
if ns == alias_ns:
isalias = True
break # namespace loop

# Try to see if it's magic
if not found:
if oname.startswith(ESC_MAGIC):
oname = oname[1:]
obj = getattr(self,'magic_'+oname,None)
if obj is not None:
found = True
ospace = 'IPython internal'
ismagic = True

# Last try: special-case some literals like '', [], {}, etc:
if not found and oname_head in ["''",'""','[]','{}','()']:
obj = eval(oname_head)
found = True
ospace = 'Interactive'

return {'found':found, 'obj':obj, 'namespace':ospace,
'ismagic':ismagic, 'isalias':isalias, 'parent':parent}

def _inspect(self,meth,oname,namespaces=None,**kw):
"""Generic interface to the inspector system.
This function is meant to be called by pdef, pdoc & friends."""

#oname = oname.strip()
#print '1- oname: <%r>' % oname # dbg
try:
oname = oname.strip().encode('ascii')
#print '2- oname: <%r>' % oname # dbg
except UnicodeEncodeError:
print 'Python identifiers can only contain ascii characters.'
return 'not found'

info = Struct(self._ofind(oname, namespaces))

if info.found:
try:
IPython.utils.generics.inspect_object(info.obj)
return
except TryNext:
pass
# Get the docstring of the class property if it exists.
path = oname.split('.')
root = '.'.join(path[:-1])
if info.parent is not None:
try:
target = getattr(info.parent, '__class__')
# The object belongs to a class instance.
try:
target = getattr(target, path[-1])
# The class defines the object.
if isinstance(target, property):
oname = root + '.__class__.' + path[-1]
info = Struct(self._ofind(oname))
except AttributeError: pass
except AttributeError: pass

pmethod = getattr(self.shell.inspector,meth)
formatter = info.ismagic and self.format_screen or None
if meth == 'pdoc':
pmethod(info.obj,oname,formatter)
elif meth == 'pinfo':
pmethod(info.obj,oname,formatter,info,**kw)
else:
pmethod(info.obj,oname)
else:
print 'Object `%s` not found.' % oname
return 'not found' # so callers can take other action

#-------------------------------------------------------------------------
# Things related to history management
#-------------------------------------------------------------------------
Expand Down
130 changes: 0 additions & 130 deletions IPython/core/magic.py
Expand Up @@ -207,87 +207,7 @@ def extract_input_slices(self,slices,raw=False):
fin = ini+1
cmds.append(hist[ini:fin])
return cmds

def _ofind(self, oname, namespaces=None):
"""Find an object in the available namespaces.
self._ofind(oname) -> dict with keys: found,obj,ospace,ismagic
Has special code to detect magic functions.
"""
oname = oname.strip()
alias_ns = None
if namespaces is None:
# Namespaces to search in:
# Put them in a list. The order is important so that we
# find things in the same order that Python finds them.
namespaces = [ ('Interactive', self.shell.user_ns),
('IPython internal', self.shell.internal_ns),
('Python builtin', __builtin__.__dict__),
('Alias', self.shell.alias_manager.alias_table),
]
alias_ns = self.shell.alias_manager.alias_table

# initialize results to 'null'
found = False; obj = None; ospace = None; ds = None;
ismagic = False; isalias = False; parent = None

# We need to special-case 'print', which as of python2.6 registers as a
# function but should only be treated as one if print_function was
# loaded with a future import. In this case, just bail.
if (oname == 'print' and not (self.shell.compile.compiler.flags &
__future__.CO_FUTURE_PRINT_FUNCTION)):
return {'found':found, 'obj':obj, 'namespace':ospace,
'ismagic':ismagic, 'isalias':isalias, 'parent':parent}

# Look for the given name by splitting it in parts. If the head is
# found, then we look for all the remaining parts as members, and only
# declare success if we can find them all.
oname_parts = oname.split('.')
oname_head, oname_rest = oname_parts[0],oname_parts[1:]
for nsname,ns in namespaces:
try:
obj = ns[oname_head]
except KeyError:
continue
else:
#print 'oname_rest:', oname_rest # dbg
for part in oname_rest:
try:
parent = obj
obj = getattr(obj,part)
except:
# Blanket except b/c some badly implemented objects
# allow __getattr__ to raise exceptions other than
# AttributeError, which then crashes IPython.
break
else:
# If we finish the for loop (no break), we got all members
found = True
ospace = nsname
if ns == alias_ns:
isalias = True
break # namespace loop

# Try to see if it's magic
if not found:
if oname.startswith(ESC_MAGIC):
oname = oname[1:]
obj = getattr(self,'magic_'+oname,None)
if obj is not None:
found = True
ospace = 'IPython internal'
ismagic = True

# Last try: special-case some literals like '', [], {}, etc:
if not found and oname_head in ["''",'""','[]','{}','()']:
obj = eval(oname_head)
found = True
ospace = 'Interactive'

return {'found':found, 'obj':obj, 'namespace':ospace,
'ismagic':ismagic, 'isalias':isalias, 'parent':parent}

def arg_err(self,func):
"""Print docstring if incorrect arguments were passed"""
print 'Error in arguments:'
Expand Down Expand Up @@ -708,56 +628,6 @@ def magic_pfile(self, parameter_s=''):
return
page.page(self.shell.inspector.format(file(filename).read()))

def _inspect(self,meth,oname,namespaces=None,**kw):
"""Generic interface to the inspector system.
This function is meant to be called by pdef, pdoc & friends."""

#oname = oname.strip()
#print '1- oname: <%r>' % oname # dbg
try:
oname = oname.strip().encode('ascii')
#print '2- oname: <%r>' % oname # dbg
except UnicodeEncodeError:
print 'Python identifiers can only contain ascii characters.'
return 'not found'

info = Struct(self._ofind(oname, namespaces))

if info.found:
try:
IPython.utils.generics.inspect_object(info.obj)
return
except TryNext:
pass
# Get the docstring of the class property if it exists.
path = oname.split('.')
root = '.'.join(path[:-1])
if info.parent is not None:
try:
target = getattr(info.parent, '__class__')
# The object belongs to a class instance.
try:
target = getattr(target, path[-1])
# The class defines the object.
if isinstance(target, property):
oname = root + '.__class__.' + path[-1]
info = Struct(self._ofind(oname))
except AttributeError: pass
except AttributeError: pass

pmethod = getattr(self.shell.inspector,meth)
formatter = info.ismagic and self.format_screen or None
if meth == 'pdoc':
pmethod(info.obj,oname,formatter)
elif meth == 'pinfo':
pmethod(info.obj,oname,formatter,info,**kw)
else:
pmethod(info.obj,oname)
else:
print 'Object `%s` not found.' % oname
return 'not found' # so callers can take other action

def magic_psearch(self, parameter_s=''):
"""Search for object in namespaces by wildcard.
Expand Down

0 comments on commit 4e3685b

Please sign in to comment.