##// END OF EJS Templates
Print sources for property fget/fset/fdel methods...
immerrr -
Show More
@@ -0,0 +1,5 b''
1 * :func:`IPython.core.oinspect.getsource` call specification has changed:
2
3 * `oname` keyword argument has been added for property source formatting
4 * `is_binary` keyword argument has been dropped, passing ``True`` had
5 previously short-circuited the function to return ``None`` unconditionally
@@ -18,6 +18,7 b" __all__ = ['Inspector','InspectColors']"
18 18 import inspect
19 19 import linecache
20 20 import os
21 from textwrap import dedent
21 22 import types
22 23 import io as stdlib_io
23 24
@@ -28,6 +29,7 b' except ImportError:'
28 29
29 30 # IPython's own
30 31 from IPython.core import page
32 from IPython.lib.pretty import pretty
31 33 from IPython.testing.skipdoctest import skip_doctest_py3
32 34 from IPython.utils import PyColorize
33 35 from IPython.utils import io
@@ -43,7 +45,8 b' from IPython.utils.py3compat import cast_unicode, string_types, PY3'
43 45 _func_call_docstring = types.FunctionType.__call__.__doc__
44 46 _object_init_docstring = object.__init__.__doc__
45 47 _builtin_type_docstrings = {
46 t.__doc__ for t in (types.ModuleType, types.MethodType, types.FunctionType)
48 t.__doc__ for t in (types.ModuleType, types.MethodType, types.FunctionType,
49 property)
47 50 }
48 51
49 52 _builtin_func_type = type(all)
@@ -150,33 +153,68 b' def getdoc(obj):'
150 153 return None
151 154
152 155
153 def getsource(obj,is_binary=False):
156 def getsource(obj, oname=''):
154 157 """Wrapper around inspect.getsource.
155 158
156 159 This can be modified by other projects to provide customized source
157 160 extraction.
158 161
159 Inputs:
160
161 - obj: an object whose source code we will attempt to extract.
162 Parameters
163 ----------
164 obj : object
165 an object whose source code we will attempt to extract
166 oname : str
167 (optional) a name under which the object is known
162 168
163 Optional inputs:
169 Returns
170 -------
171 src : unicode or None
164 172
165 - is_binary: whether the object is known to come from a binary source.
166 This implementation will skip returning any output for binary objects, but
167 custom extractors may know how to meaningfully process them."""
173 """
168 174
169 if is_binary:
175 if isinstance(obj, property):
176 sources = []
177 for attrname in ['fget', 'fset', 'fdel']:
178 fn = getattr(obj, attrname)
179 if fn is not None:
180 encoding = get_encoding(fn)
181 oname_prefix = ('%s.' % oname) if oname else ''
182 sources.append(cast_unicode(
183 ''.join(('# ', oname_prefix, attrname)),
184 encoding=encoding))
185 if inspect.isfunction(fn):
186 sources.append(dedent(getsource(fn)))
187 else:
188 # Default str/repr only prints function name,
189 # pretty.pretty prints module name too.
190 sources.append(cast_unicode(
191 '%s%s = %s\n' % (
192 oname_prefix, attrname, pretty(fn)),
193 encoding=encoding))
194 if sources:
195 return '\n'.join(sources)
196 else:
170 197 return None
198
171 199 else:
172 # get source if obj was decorated with @decorator
200 # Get source for non-property objects.
201
202 # '__wrapped__' attribute is used by some decorators (e.g. ones defined
203 # functools) to provide access to the decorated function.
173 204 if hasattr(obj,"__wrapped__"):
174 205 obj = obj.__wrapped__
206
175 207 try:
176 208 src = inspect.getsource(obj)
177 209 except TypeError:
210 # The object itself provided no meaningful source, try looking for
211 # its class definition instead.
178 212 if hasattr(obj,'__class__'):
213 try:
179 214 src = inspect.getsource(obj.__class__)
215 except TypeError:
216 return None
217
180 218 encoding = get_encoding(obj)
181 219 return cast_unicode(src, encoding=encoding)
182 220
@@ -463,8 +501,11 b' class Inspector:'
463 501 # Flush the source cache because inspect can return out-of-date source
464 502 linecache.checkcache()
465 503 try:
466 src = getsource(obj)
467 except:
504 src = getsource(obj, oname=oname)
505 except Exception:
506 src = None
507
508 if src is None:
468 509 self.noinfo('source',oname)
469 510 else:
470 511 page.page(self.format(src))
@@ -697,32 +738,25 b' class Inspector:'
697 738 fname = 'Dynamically generated function. No source code available.'
698 739 out['file'] = fname
699 740
700 # Docstrings only in detail 0 mode, since source contains them (we
701 # avoid repetitions). If source fails, we add them back, see below.
702 if ds and detail_level == 0:
703 out['docstring'] = ds
704
705 # Original source code for any callable
741 # Original source code for a callable, class or property.
706 742 if detail_level:
707 743 # Flush the source cache because inspect can return out-of-date
708 744 # source
709 745 linecache.checkcache()
710 source = None
711 746 try:
712 try:
713 source = getsource(obj, binary_file)
714 except TypeError:
715 if hasattr(obj, '__class__'):
716 source = getsource(obj.__class__, binary_file)
717 if source is not None:
718 out['source'] = source.rstrip()
747 if isinstance(obj, property) or not binary_file:
748 src = getsource(obj, oname)
749 if src is not None:
750 src = src.rstrip()
751 out['source'] = src
752
719 753 except Exception:
720 754 pass
721 755
722 if ds and source is None:
756 # Add docstring only if no source is to be shown (avoid repetitions).
757 if ds and out.get('source', None) is None:
723 758 out['docstring'] = ds
724 759
725
726 760 # Constructor docstring for classes
727 761 if inspect.isclass(obj):
728 762 out['isclass'] = True
@@ -824,7 +858,6 b' class Inspector:'
824 858
825 859 return object_info(**out)
826 860
827
828 861 def psearch(self,pattern,ns_table,ns_search=[],
829 862 ignore_case=False,show_all=False):
830 863 """Search namespaces with wildcards for objects.
@@ -313,6 +313,54 b' def test_getdoc():'
313 313 nt.assert_equal(oinspect.getdoc(b), "custom docstring")
314 314 nt.assert_equal(oinspect.getdoc(c), "standard docstring")
315 315
316
317 def test_empty_property_has_no_source():
318 i = inspector.info(property(), detail_level=1)
319 nt.assert_is(i['source'], None)
320
321
322 def test_property_sources():
323 import zlib
324
325 class A(object):
326 @property
327 def foo(self):
328 return 'bar'
329
330 foo = foo.setter(lambda self, v: setattr(self, 'bar', v))
331
332 id = property(id)
333 compress = property(zlib.compress)
334
335 i = inspector.info(A.foo, detail_level=1)
336 nt.assert_in('def foo(self):', i['source'])
337 nt.assert_in('lambda self, v:', i['source'])
338
339 i = inspector.info(A.id, detail_level=1)
340 nt.assert_in('fget = <function id>', i['source'])
341
342 i = inspector.info(A.compress, detail_level=1)
343 nt.assert_in('fget = <function zlib.compress>', i['source'])
344
345
346 def test_property_docstring_is_in_info_for_detail_level_0():
347 class A(object):
348 @property
349 def foobar():
350 """This is `foobar` property."""
351 pass
352
353 ip.user_ns['a_obj'] = A()
354 nt.assert_equals(
355 'This is `foobar` property.',
356 ip.object_inspect('a_obj.foobar', detail_level=0)['docstring'])
357
358 ip.user_ns['a_cls'] = A
359 nt.assert_equals(
360 'This is `foobar` property.',
361 ip.object_inspect('a_cls.foobar', detail_level=0)['docstring'])
362
363
316 364 def test_pdef():
317 365 # See gh-1914
318 366 def foo(): pass
General Comments 0
You need to be logged in to leave comments. Login now