##// 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 import inspect
18 import inspect
19 import linecache
19 import linecache
20 import os
20 import os
21 from textwrap import dedent
21 import types
22 import types
22 import io as stdlib_io
23 import io as stdlib_io
23
24
@@ -28,6 +29,7 b' except ImportError:'
28
29
29 # IPython's own
30 # IPython's own
30 from IPython.core import page
31 from IPython.core import page
32 from IPython.lib.pretty import pretty
31 from IPython.testing.skipdoctest import skip_doctest_py3
33 from IPython.testing.skipdoctest import skip_doctest_py3
32 from IPython.utils import PyColorize
34 from IPython.utils import PyColorize
33 from IPython.utils import io
35 from IPython.utils import io
@@ -43,7 +45,8 b' from IPython.utils.py3compat import cast_unicode, string_types, PY3'
43 _func_call_docstring = types.FunctionType.__call__.__doc__
45 _func_call_docstring = types.FunctionType.__call__.__doc__
44 _object_init_docstring = object.__init__.__doc__
46 _object_init_docstring = object.__init__.__doc__
45 _builtin_type_docstrings = {
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 _builtin_func_type = type(all)
52 _builtin_func_type = type(all)
@@ -150,33 +153,68 b' def getdoc(obj):'
150 return None
153 return None
151
154
152
155
153 def getsource(obj,is_binary=False):
156 def getsource(obj, oname=''):
154 """Wrapper around inspect.getsource.
157 """Wrapper around inspect.getsource.
155
158
156 This can be modified by other projects to provide customized source
159 This can be modified by other projects to provide customized source
157 extraction.
160 extraction.
158
161
159 Inputs:
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
160
168
161 - obj: an object whose source code we will attempt to extract.
169 Returns
170 -------
171 src : unicode or None
162
172
163 Optional inputs:
173 """
164
174
165 - is_binary: whether the object is known to come from a binary source.
175 if isinstance(obj, property):
166 This implementation will skip returning any output for binary objects, but
176 sources = []
167 custom extractors may know how to meaningfully process them."""
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:
197 return None
168
198
169 if is_binary:
170 return None
171 else:
199 else:
172 # get source if obj was decorated with @decorator
200 # Get source for non-property objects.
173 if hasattr(obj,"__wrapped__"):
201
202 # '__wrapped__' attribute is used by some decorators (e.g. ones defined
203 # functools) to provide access to the decorated function.
204 if hasattr(obj, "__wrapped__"):
174 obj = obj.__wrapped__
205 obj = obj.__wrapped__
206
175 try:
207 try:
176 src = inspect.getsource(obj)
208 src = inspect.getsource(obj)
177 except TypeError:
209 except TypeError:
178 if hasattr(obj,'__class__'):
210 # The object itself provided no meaningful source, try looking for
179 src = inspect.getsource(obj.__class__)
211 # its class definition instead.
212 if hasattr(obj, '__class__'):
213 try:
214 src = inspect.getsource(obj.__class__)
215 except TypeError:
216 return None
217
180 encoding = get_encoding(obj)
218 encoding = get_encoding(obj)
181 return cast_unicode(src, encoding=encoding)
219 return cast_unicode(src, encoding=encoding)
182
220
@@ -457,15 +495,18 b' class Inspector:'
457 else:
495 else:
458 page.page('\n'.join(lines))
496 page.page('\n'.join(lines))
459
497
460 def psource(self,obj,oname=''):
498 def psource(self, obj, oname=''):
461 """Print the source code for an object."""
499 """Print the source code for an object."""
462
500
463 # Flush the source cache because inspect can return out-of-date source
501 # Flush the source cache because inspect can return out-of-date source
464 linecache.checkcache()
502 linecache.checkcache()
465 try:
503 try:
466 src = getsource(obj)
504 src = getsource(obj, oname=oname)
467 except:
505 except Exception:
468 self.noinfo('source',oname)
506 src = None
507
508 if src is None:
509 self.noinfo('source', oname)
469 else:
510 else:
470 page.page(self.format(src))
511 page.page(self.format(src))
471
512
@@ -696,32 +737,25 b' class Inspector:'
696 elif fname.endswith('<string>'):
737 elif fname.endswith('<string>'):
697 fname = 'Dynamically generated function. No source code available.'
738 fname = 'Dynamically generated function. No source code available.'
698 out['file'] = fname
739 out['file'] = fname
699
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
740
705 # Original source code for any callable
741 # Original source code for a callable, class or property.
706 if detail_level:
742 if detail_level:
707 # Flush the source cache because inspect can return out-of-date
743 # Flush the source cache because inspect can return out-of-date
708 # source
744 # source
709 linecache.checkcache()
745 linecache.checkcache()
710 source = None
711 try:
746 try:
712 try:
747 if isinstance(obj, property) or not binary_file:
713 source = getsource(obj, binary_file)
748 src = getsource(obj, oname)
714 except TypeError:
749 if src is not None:
715 if hasattr(obj, '__class__'):
750 src = src.rstrip()
716 source = getsource(obj.__class__, binary_file)
751 out['source'] = src
717 if source is not None:
752
718 out['source'] = source.rstrip()
719 except Exception:
753 except Exception:
720 pass
754 pass
721
755
722 if ds and source is None:
756 # Add docstring only if no source is to be shown (avoid repetitions).
723 out['docstring'] = ds
757 if ds and out.get('source', None) is None:
724
758 out['docstring'] = ds
725
759
726 # Constructor docstring for classes
760 # Constructor docstring for classes
727 if inspect.isclass(obj):
761 if inspect.isclass(obj):
@@ -824,7 +858,6 b' class Inspector:'
824
858
825 return object_info(**out)
859 return object_info(**out)
826
860
827
828 def psearch(self,pattern,ns_table,ns_search=[],
861 def psearch(self,pattern,ns_table,ns_search=[],
829 ignore_case=False,show_all=False):
862 ignore_case=False,show_all=False):
830 """Search namespaces with wildcards for objects.
863 """Search namespaces with wildcards for objects.
@@ -313,6 +313,54 b' def test_getdoc():'
313 nt.assert_equal(oinspect.getdoc(b), "custom docstring")
313 nt.assert_equal(oinspect.getdoc(b), "custom docstring")
314 nt.assert_equal(oinspect.getdoc(c), "standard docstring")
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 def test_pdef():
364 def test_pdef():
317 # See gh-1914
365 # See gh-1914
318 def foo(): pass
366 def foo(): pass
General Comments 0
You need to be logged in to leave comments. Login now