Skip to content
This repository has been archived by the owner on Jan 30, 2023. It is now read-only.

Commit

Permalink
Improve _sage_src_lines_()
Browse files Browse the repository at this point in the history
  • Loading branch information
jdemeyer committed Jun 16, 2016
1 parent 744ffa6 commit f5361d9
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 18 deletions.
46 changes: 34 additions & 12 deletions src/sage/misc/sageinspect.py
Original file line number Diff line number Diff line change
Expand Up @@ -1283,7 +1283,7 @@ def sage_getargspec(obj):
sage: from sage.misc.sageinspect import sage_getargspec
sage: def f(x, y, z=1, t=2, *args, **keywords):
... pass
....: pass
sage: sage_getargspec(f)
ArgSpec(args=['x', 'y', 'z', 't'], varargs='args', keywords='keywords', defaults=(1, 2))
Expand Down Expand Up @@ -1323,8 +1323,8 @@ def sage_getargspec(obj):
If a ``functools.partial`` instance is involved, we see no other meaningful solution
than to return the argspec of the underlying function::
sage: def f(a,b,c,d=1): return a+b+c+d
...
sage: def f(a,b,c,d=1):
....: return a+b+c+d
sage: import functools
sage: f1 = functools.partial(f, 1,c=2)
sage: sage_getargspec(f1)
Expand Down Expand Up @@ -1435,7 +1435,10 @@ def foo(x, a='\')"', b={not (2+1==3):'bar'}): return
pass
# If we are lucky, the function signature is embedded in the docstring.
docstring = _sage_getdoc_unformatted(obj)
name = obj.__name__ if hasattr(obj,'__name__') else type(obj).__name__
try:
name = obj.__name__
except AttributeError:
name = type(obj).__name__
argspec = _extract_embedded_signature(docstring, name)[1]
if argspec is not None:
return argspec
Expand Down Expand Up @@ -1983,6 +1986,16 @@ def sage_getsourcelines(obj):
sage: sage_getsourcelines(matrix)[0][0][6:]
'MatrixFactory(object):\n'
Some classes customize this using a ``_sage_src_lines_`` method,
which gives the source lines of a class instance, but not the class
itself. We demonstrate this for :class:`CachedFunction`::
sage: cachedfib = cached_function(fibonacci)
sage: sage_getsourcelines(cachedfib)[0][0]
'def fibonacci(n, algorithm="pari"):\n'
sage: sage_getsourcelines(type(cachedfib))[0][0]
'cdef class CachedFunction(object):\n'
TESTS::
sage: cython('''cpdef test_funct(x,y): return''')
Expand Down Expand Up @@ -2050,7 +2063,7 @@ class Element:
sage: sage_getsourcelines(HC)
([' class Homsets(HomsetsCategory):\n', ...], ...)
Testing against a bug that has occured during work on #11768::
Testing against a bug that has occured during work on :trac:`11768`::
sage: P.<x,y> = QQ[]
sage: I = P*[x,y]
Expand All @@ -2070,18 +2083,27 @@ class Element:
- Simon King: If a class has no docstring then let the class
definition be found starting from the ``__init__`` method.
- Simon King: Get source lines for dynamic classes.
"""

# First try the method _sage_src_lines_(), which is meant to give
# the source lines of an object (not of its type!).
try:
return obj._sage_src_lines_()
sage_src_lines = obj._sage_src_lines_
except AttributeError:
pass
except TypeError:
# That happes for instances of dynamic classes
return sage_getsourcelines(obj.__class__)
else:
try:
return sage_src_lines()
except (NotImplementedError, TypeError):
# NotImplementedError can be raised by _sage_src_lines_()
# to indicate that it didn't find the source lines.
#
# TypeError can happen when obj is a type and
# obj._sage_src_lines_ is an unbound method. In this case,
# we don't want to use _sage_src_lines_(), we just want to
# get the source of the type itself.
pass

# Check if we deal with instance
# Check if we deal with an instance
if isclassinstance(obj):
if isinstance(obj,functools.partial):
return sage_getsourcelines(obj.func)
Expand Down
33 changes: 27 additions & 6 deletions src/sage/structure/dynamic_class.py
Original file line number Diff line number Diff line change
Expand Up @@ -389,12 +389,9 @@ def dynamic_class_internal(name, bases, cls=None, reduction=None, doccls=None, p
assert bases != ()
doccls = bases[0]
methods['_reduction'] = reduction
if "_sage_src_lines_" not in methods:
from sage.misc.sageinspect import sage_getsourcelines
@staticmethod
def _sage_src_lines():
return sage_getsourcelines(doccls)
methods['_sage_src_lines_'] = _sage_src_lines
# HACK: _doccls is a 1-element tuple to avoid __classget__
# or trouble with binding behaviour...
methods['_doccls'] = (doccls,)
methods['__doc__'] = doccls.__doc__
methods['__module__'] = doccls.__module__

Expand All @@ -412,10 +409,34 @@ def _sage_src_lines():
metaclass = DynamicInheritComparisonMetaclass
return metaclass(name, bases, methods)


class DynamicMetaclass(type):
"""
A metaclass implementing an appropriate reduce-by-construction method
"""
def _sage_src_lines_(self):
r"""
Get the source lines of the dynamic class. This defers to the
source lines of the ``_doccls`` attribute, which is set when
the dynamic class is constructed.
EXAMPLES::
sage: from sage.misc.sageinspect import sage_getsourcelines
sage: from sage.structure.dynamic_class import dynamic_class
sage: C = dynamic_class("SomeClass", [object], doccls=Integer)
sage: sage_getsourcelines(C)[0][0]
'cdef class Integer(sage.structure.element.EuclideanDomainElement):\n'
"""
try:
# HACK: _doccls is a 1-element tuple to avoid __classget__
# or trouble with binding behaviour...
doccls = self._doccls[0]
except AttributeError:
raise NotImplementedError("no _doccls found")
from sage.misc.sageinspect import sage_getsourcelines
return sage_getsourcelines(doccls)

def __reduce__(self):
"""
See :func:`sage.structure.dynamic_class.dynamic_class` for
Expand Down

0 comments on commit f5361d9

Please sign in to comment.