Inspect Python, Sage, and Cython objects¶
This module extends parts of Python’s inspect module to Cython objects.
AUTHORS:
- originally taken from Fernando Perez’s IPython
- William Stein (extensive modifications)
- Nick Alexander (extensions)
- Nick Alexander (testing)
- Simon King (some extension for Cython, generalisation of SageArgSpecVisitor)
EXAMPLES:
sage: from sage.misc.sageinspect import *
Test introspection of modules defined in Python and Cython files:
Cython modules:
sage: sage_getfile(sage.rings.rational)
'.../rational.pyx'
sage: sage_getdoc(sage.rings.rational).lstrip()
'Rational Numbers...'
sage: sage_getsource(sage.rings.rational)[5:]
'Rational Numbers...'
Python modules:
sage: sage_getfile(sage.misc.sageinspect)
'.../sageinspect.py'
sage: print(sage_getdoc(sage.misc.sageinspect).lstrip()[:40])
Inspect Python, Sage, and Cython objects
sage: sage_getsource(sage.misc.sageinspect).lstrip()[5:-1]
'Inspect Python, Sage, and Cython objects...'
Test introspection of classes defined in Python and Cython files:
Cython classes:
sage: sage_getfile(sage.rings.rational.Rational)
'.../rational.pyx'
sage: sage_getdoc(sage.rings.rational.Rational).lstrip()
'A rational number...'
sage: sage_getsource(sage.rings.rational.Rational)
'cdef class Rational...'
Python classes:
sage: sage_getfile(BlockFinder)
'.../sage/misc/sageinspect.py'
sage: sage_getdoc(BlockFinder).lstrip()
'Provide a tokeneater() method to detect the...'
sage: sage_getsource(BlockFinder)
'class BlockFinder:...'
Test introspection of functions defined in Python and Cython files:
Cython functions:
sage: sage_getdef(sage.rings.rational.make_rational, obj_name='mr')
'mr(s)'
sage: sage_getfile(sage.rings.rational.make_rational)
'.../rational.pyx'
sage: sage_getdoc(sage.rings.rational.make_rational).lstrip()
'Make a rational number ...'
sage: sage_getsource(sage.rings.rational.make_rational)[4:]
'make_rational(s):...'
Python functions:
sage: sage_getdef(sage.misc.sageinspect.sage_getfile, obj_name='sage_getfile')
'sage_getfile(obj)'
sage: sage_getfile(sage.misc.sageinspect.sage_getfile)
'.../sageinspect.py'
sage: sage_getdoc(sage.misc.sageinspect.sage_getfile).lstrip()
'Get the full file name associated to "obj" as a string...'
sage: sage_getsource(sage.misc.sageinspect.sage_getfile)[4:]
'sage_getfile(obj):...'
Unfortunately, no argspec is extractable from builtins. Hence, we use a generic argspec:
sage: sage_getdef(''.find, 'find')
'find(*args, **kwds)'
sage: sage_getdef(str.find, 'find')
'find(*args, **kwds)'
By trac ticket #9976 and trac ticket #14017, introspection also works for interactively defined Cython code, and with rather tricky argument lines:
sage: cython('def foo(unsigned int x=1, a=\')"\', b={not (2+1==3):\'bar\'}, *args, **kwds): return')
sage: print(sage_getsource(foo))
def foo(unsigned int x=1, a=')"', b={not (2+1==3):'bar'}, *args, **kwds): return
sage: sage_getargspec(foo)
ArgSpec(args=['x', 'a', 'b'], varargs='args', keywords='kwds', defaults=(1, ')"', {False: 'bar'}))
-
class
sage.misc.sageinspect.
BlockFinder
¶ Provide a tokeneater() method to detect the end of a code block.
This is the Python library’s
inspect.BlockFinder
modified to recognize Cython definitions.-
tokeneater
(type, token, srow_scol, erow_ecol, line)¶
-
-
class
sage.misc.sageinspect.
SageArgSpecVisitor
¶ Bases:
ast.NodeVisitor
A simple visitor class that walks an abstract-syntax tree (AST) for a Python function’s argspec. It returns the contents of nodes representing the basic Python types: None, booleans, numbers, strings, lists, tuples, and dictionaries. We use this class in
_sage_getargspec_from_ast()
to extract an argspec from a function’s or method’s source code.EXAMPLES:
sage: import ast, sage.misc.sageinspect as sms sage: visitor = sms.SageArgSpecVisitor() sage: visitor.visit(ast.parse('[1,2,3]').body[0].value) [1, 2, 3] sage: visitor.visit(ast.parse("{'a':('e',2,[None,({False:True},'pi')]), 37.0:'temp'}").body[0].value) {37.0: 'temp', 'a': ('e', 2, [None, ({False: True}, 'pi')])} sage: v = ast.parse("jc = ['veni', 'vidi', 'vici']").body[0]; v <_ast.Assign object at ...> sage: [x for x in dir(v) if not x.startswith('__')] ['_attributes', '_fields', 'col_offset', 'lineno', 'targets', 'value'] sage: visitor.visit(v.targets[0]) 'jc' sage: visitor.visit(v.value) ['veni', 'vidi', 'vici']
-
visit_BinOp
(node)¶ Visit a Python AST
ast.BinOp
node.INPUT:
node
- the node instance to visit
OUTPUT:
- The result that
node
represents
AUTHOR:
- Simon King
EXAMPLES:
sage: import ast, sage.misc.sageinspect as sms sage: visitor = sms.SageArgSpecVisitor() sage: vis = lambda x: visitor.visit(ast.parse(x).body[0].value) sage: [vis(d) for d in ['(3+(2*4))', '7|8', '5^3', '7/3', '7//3', '3<<4']] #indirect doctest # optional - python2 [11, 15, 6, 2, 2, 48]
-
visit_BoolOp
(node)¶ Visit a Python AST
ast.BoolOp
node.INPUT:
node
- the node instance to visit
OUTPUT:
- The result that
node
represents
AUTHOR:
- Simon King
EXAMPLES:
sage: import ast, sage.misc.sageinspect as sms sage: visitor = sms.SageArgSpecVisitor() sage: vis = lambda x: visitor.visit(ast.parse(x).body[0].value) sage: [vis(d) for d in ['True and 1', 'False or 3 or None', '3 and 4']] #indirect doctest [1, 3, 4]
-
visit_Compare
(node)¶ Visit a Python AST
ast.Compare
node.INPUT:
node
- the node instance to visit
OUTPUT:
- The result that
node
represents
AUTHOR:
- Simon King
EXAMPLES:
sage: import ast, sage.misc.sageinspect as sms sage: visitor = sms.SageArgSpecVisitor() sage: vis = lambda x: visitor.visit_Compare(ast.parse(x).body[0].value) sage: [vis(d) for d in ['1<2==2!=3', '1==1>2', '1<2>1', '1<3<2<4']] [True, False, True, False]
-
visit_Dict
(node)¶ Visit a Python AST
ast.Dict
node.INPUT:
node
- the node instance to visit
OUTPUT:
- the dictionary the
node
represents
EXAMPLES:
sage: import ast, sage.misc.sageinspect as sms sage: visitor = sms.SageArgSpecVisitor() sage: vis = lambda x: visitor.visit_Dict(ast.parse(x).body[0].value) sage: [vis(d) for d in ['{}', "{1:one, 'two':2, other:bother}"]] [{}, {1: 'one', 'other': 'bother', 'two': 2}]
-
visit_List
(node)¶ Visit a Python AST
ast.List
node.INPUT:
node
- the node instance to visit
OUTPUT:
- the list the
node
represents
EXAMPLES:
sage: import ast, sage.misc.sageinspect as sms sage: visitor = sms.SageArgSpecVisitor() sage: vis = lambda x: visitor.visit_List(ast.parse(x).body[0].value) sage: [vis(l) for l in ['[]', "['s', 't', 'u']", '[[e], [], [pi]]']] [[], ['s', 't', 'u'], [['e'], [], ['pi']]]
-
visit_Name
(node)¶ Visit a Python AST
ast.Name
node.INPUT:
node
- the node instance to visit
OUTPUT:
- None, True, False, or the
node
‘s name as a string.
EXAMPLES:
sage: import ast, sage.misc.sageinspect as sms sage: visitor = sms.SageArgSpecVisitor() sage: vis = lambda x: visitor.visit_Name(ast.parse(x).body[0].value) sage: [vis(n) for n in ['True', 'False', 'None', 'foo', 'bar']] [True, False, None, 'foo', 'bar'] sage: [type(vis(n)) for n in ['True', 'False', 'None', 'foo', 'bar']] [<type 'bool'>, <type 'bool'>, <type 'NoneType'>, <type 'str'>, <type 'str'>]
-
visit_Num
(node)¶ Visit a Python AST
ast.Num
node.INPUT:
node
- the node instance to visit
OUTPUT:
- the number the
node
represents
EXAMPLES:
sage: import ast, sage.misc.sageinspect as sms sage: visitor = sms.SageArgSpecVisitor() sage: vis = lambda x: visitor.visit_Num(ast.parse(x).body[0].value) sage: [vis(n) for n in ['123', '0.0', str(-pi.n())]] [123, 0.0, -3.14159265358979]
-
visit_Str
(node)¶ Visit a Python AST
ast.Str
node.INPUT:
node
- the node instance to visit
OUTPUT:
- the string the
node
represents
EXAMPLES:
sage: import ast, sage.misc.sageinspect as sms sage: visitor = sms.SageArgSpecVisitor() sage: vis = lambda x: visitor.visit_Str(ast.parse(x).body[0].value) sage: [vis(s) for s in ['"abstract"', "u'syntax'", '''r"tr\ee"''']] ['abstract', u'syntax', 'tr\\ee']
-
visit_Tuple
(node)¶ Visit a Python AST
ast.Tuple
node.INPUT:
node
- the node instance to visit
OUTPUT:
- the tuple the
node
represents
EXAMPLES:
sage: import ast, sage.misc.sageinspect as sms sage: visitor = sms.SageArgSpecVisitor() sage: vis = lambda x: visitor.visit_Tuple(ast.parse(x).body[0].value) sage: [vis(t) for t in ['()', '(x,y)', '("Au", "Al", "Cu")']] [(), ('x', 'y'), ('Au', 'Al', 'Cu')]
-
visit_UnaryOp
(node)¶ Visit a Python AST
ast.BinOp
node.INPUT:
node
- the node instance to visit
OUTPUT:
- The result that
node
represents
AUTHOR:
- Simon King
EXAMPLES:
sage: import ast, sage.misc.sageinspect as sms sage: visitor = sms.SageArgSpecVisitor() sage: vis = lambda x: visitor.visit_UnaryOp(ast.parse(x).body[0].value) sage: [vis(d) for d in ['+(3*2)', '-(3*2)']] [6, -6]
-
-
sage.misc.sageinspect.
isclassinstance
(obj)¶ Checks if argument is instance of non built-in class
INPUT:
obj
- objectEXAMPLES:
sage: from sage.misc.sageinspect import isclassinstance sage: isclassinstance(int) False sage: isclassinstance(FreeModule) True sage: class myclass: pass sage: isclassinstance(myclass) False sage: class mymetaclass(type): pass sage: class myclass2: ....: __metaclass__ = mymetaclass sage: isclassinstance(myclass2) False
-
sage.misc.sageinspect.
loadable_module_extension
()¶ Return the filename extension of loadable modules, including the dot. It is ‘.dll’ on cygwin, ‘.so’ otherwise.
EXAMPLES:
sage: from sage.misc.sageinspect import loadable_module_extension sage: sage.structure.sage_object.__file__.endswith(loadable_module_extension()) True
-
sage.misc.sageinspect.
sage_getargspec
(obj)¶ Return the names and default values of a function’s arguments.
INPUT:
obj
, any callable objectOUTPUT:
An
ArgSpec
is returned. This is a named tuple(args, varargs, keywords, defaults)
.args
is a list of the argument names (it may contain nested lists).varargs
andkeywords
are the names of the*
and**
arguments orNone
.defaults
is an \(n\)-tuple of the default values of the last \(n\) arguments.
NOTE:
If the object has a method
_sage_argspec_
then the output of that method is transformed into a named tuple and then returned.If a class instance has a method
_sage_src_
then its output is studied to determine the argspec. This is because currently theCachedMethod
decorator has no_sage_argspec_
method.EXAMPLES:
sage: from sage.misc.sageinspect import sage_getargspec sage: def f(x, y, z=1, t=2, *args, **keywords): ....: pass sage: sage_getargspec(f) ArgSpec(args=['x', 'y', 'z', 't'], varargs='args', keywords='keywords', defaults=(1, 2))
We now run sage_getargspec on some functions from the Sage library:
sage: sage_getargspec(identity_matrix) ArgSpec(args=['ring', 'n', 'sparse'], varargs=None, keywords=None, defaults=(0, False)) sage: sage_getargspec(factor) ArgSpec(args=['n', 'proof', 'int_', 'algorithm', 'verbose'], varargs=None, keywords='kwds', defaults=(None, False, 'pari', 0))
In the case of a class or a class instance, the
ArgSpec
of the__new__
,__init__
or__call__
method is returned:sage: P.<x,y> = QQ[] sage: sage_getargspec(P) ArgSpec(args=['base_ring', 'n', 'names', 'order'], varargs=None, keywords=None, defaults=('degrevlex',)) sage: sage_getargspec(P.__class__) ArgSpec(args=['self', 'x'], varargs='args', keywords='kwds', defaults=(0,))
The following tests against various bugs that were fixed in trac ticket #9976:
sage: from sage.rings.polynomial.real_roots import bernstein_polynomial_factory_ratlist sage: sage_getargspec(bernstein_polynomial_factory_ratlist.coeffs_bitsize) ArgSpec(args=['self'], varargs=None, keywords=None, defaults=None) sage: from sage.rings.polynomial.pbori import BooleanMonomialMonoid sage: sage_getargspec(BooleanMonomialMonoid.gen) ArgSpec(args=['self', 'i'], varargs=None, keywords=None, defaults=(0,)) sage: I = P*[x,y] sage: sage_getargspec(I.groebner_basis) ArgSpec(args=['self', 'algorithm', 'deg_bound', 'mult_bound', 'prot'], varargs='args', keywords='kwds', defaults=('', None, None, False)) sage: cython("cpdef int foo(x,y) except -1: return 1") sage: sage_getargspec(foo) ArgSpec(args=['x', 'y'], varargs=None, keywords=None, defaults=None)
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: import functools sage: f1 = functools.partial(f, 1,c=2) sage: sage_getargspec(f1) ArgSpec(args=['a', 'b', 'c', 'd'], varargs=None, keywords=None, defaults=(1,))
TESTS:
By trac ticket #9976, rather complicated cases work. In the following example, we dynamically create an extension class that returns some source code, and the example shows that the source code is taken for granted, i.e., the argspec of an instance of that class does not coincide with the argspec of its call method. That behaviour is intended, since a decorated method appears to have the generic signature
*args,**kwds
, but in fact it is only supposed to be called with the arguments requested by the underlying undecorated method. We saw an easy example above, namelyI.groebner_basis
. Here is a more difficult one:sage: cython_code = [ ....: 'cdef class MyClass:', ....: ' def _sage_src_(self):', ....: ' return "def foo(x, a=\\\')\\\"\\\', b={(2+1):\\\'bar\\\', not 1:3, 3<<4:5}): return\\n"', ....: ' def __call__(self, m,n): return "something"'] sage: cython('\n'.join(cython_code)) sage: O = MyClass() sage: print(sage.misc.sageinspect.sage_getsource(O)) def foo(x, a=')"', b={(2+1):'bar', not 1:3, 3<<4:5}): return sage: sage.misc.sageinspect.sage_getargspec(O) ArgSpec(args=['x', 'a', 'b'], varargs=None, keywords=None, defaults=(')"', {False: 3, 48: 5, 3: 'bar'})) sage: sage.misc.sageinspect.sage_getargspec(O.__call__) ArgSpec(args=['self', 'm', 'n'], varargs=None, keywords=None, defaults=None)
sage: cython('def foo(x, a=\'\\\')"\', b={not (2+1==3):\'bar\'}): return') sage: print(sage.misc.sageinspect.sage_getsource(foo)) def foo(x, a='\')"', b={not (2+1==3):'bar'}): return <BLANKLINE> sage: sage.misc.sageinspect.sage_getargspec(foo) ArgSpec(args=['x', 'a', 'b'], varargs=None, keywords=None, defaults=('\')"', {False: 'bar'}))
The following produced a syntax error before the patch at trac ticket #11913:
sage: sage.misc.sageinspect.sage_getargspec(r.lm)
The following was fixed in trac ticket #16309:
sage: cython(''' ....: class Foo: ....: @staticmethod ....: def join(categories, bint as_list = False, tuple ignore_axioms=(), tuple axioms=()): pass ....: cdef class Bar: ....: @staticmethod ....: def join(categories, bint as_list = False, tuple ignore_axioms=(), tuple axioms=()): pass ....: cpdef meet(categories, bint as_list = False, tuple ignore_axioms=(), tuple axioms=()): pass ....: ''') sage: sage_getargspec(Foo.join) ArgSpec(args=['categories', 'as_list', 'ignore_axioms', 'axioms'], varargs=None, keywords=None, defaults=(False, (), ())) sage: sage_getargspec(Bar.join) ArgSpec(args=['categories', 'as_list', 'ignore_axioms', 'axioms'], varargs=None, keywords=None, defaults=(False, (), ())) sage: sage_getargspec(Bar.meet) ArgSpec(args=['categories', 'as_list', 'ignore_axioms', 'axioms'], varargs=None, keywords=None, defaults=(False, (), ()))
Test that trac ticket #17009 is fixed:
sage: sage_getargspec(gap) ArgSpec(args=['self', 'x', 'name'], varargs=None, keywords=None, defaults=(None,))
By trac ticket #17814, the following gives the correct answer (previously, the defaults would have been found
None
):sage: from sage.misc.nested_class import MainClass sage: sage_getargspec(MainClass.NestedClass.NestedSubClass.dummy) ArgSpec(args=['self', 'x', 'r'], varargs='args', keywords='kwds', defaults=((1, 2, 3.4),))
In trac ticket #18249 was decided to return a generic signature for Python builtin functions, rather than to raise an error (which is what Python’s inspect module does):
sage: import inspect sage: inspect.getargspec(range) Traceback (most recent call last): ... TypeError: <built-in function range> is not a Python function sage: sage_getargspec(range) ArgSpec(args=[], varargs='args', keywords='kwds', defaults=None)
AUTHORS:
- William Stein: a modified version of inspect.getargspec from the Python Standard Library, which was taken from IPython for use in Sage.
- Extensions by Nick Alexander
- Simon King: Return an
ArgSpec
, fix some bugs.
-
sage.misc.sageinspect.
sage_getdef
(obj, obj_name='')¶ Return the definition header for any callable object.
INPUT:
obj
- functionobj_name
- string (optional, default ‘’)
obj_name
is prepended to the output.EXAMPLES:
sage: from sage.misc.sageinspect import sage_getdef sage: sage_getdef(identity_matrix) '(ring, n=0, sparse=False)' sage: sage_getdef(identity_matrix, 'identity_matrix') 'identity_matrix(ring, n=0, sparse=False)'
Check that trac ticket #6848 has been fixed:
sage: sage_getdef(RDF.random_element) '(min=-1, max=1)'
If an exception is generated, None is returned instead and the exception is suppressed.
AUTHORS:
- William Stein
- extensions by Nick Alexander
-
sage.misc.sageinspect.
sage_getdoc
(obj, obj_name='', embedded_override=False)¶ Return the docstring associated to
obj
as a string.If
obj
is a Cython object with an embedded position in its docstring, the embedded position is stripped.If optional argument
embedded_override
is False (its default value), then the string is formatted according to the value of EMBEDDED_MODE. If this argument is True, then it is formatted as if EMBEDDED_MODE were True.INPUT:
obj
– a function, module, etc.: something with a docstring.
EXAMPLES:
sage: from sage.misc.sageinspect import sage_getdoc sage: sage_getdoc(identity_matrix)[87:124] 'Return the n x n identity matrix over' 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: f.__doc__ = "original documentation" sage: f1.__doc__ = "specialised documentation" sage: sage_getdoc(f) 'original documentation\n' sage: sage_getdoc(f1) 'specialised documentation\n'
AUTHORS:
- William Stein
- extensions by Nick Alexander
-
sage.misc.sageinspect.
sage_getdoc_original
(obj)¶ Return the unformatted docstring associated to
obj
as a string.If
obj
is a Cython object with an embedded position or signature in its docstring, the embedded information is stripped. If the stripped docstring is empty, then the stripped docstring ofobj.__init__
is returned instead.Feed the results from this into the function
sage.misc.sagedoc.format()
for printing to the screen.INPUT:
obj
– a function, module, etc.: something with a docstring.
EXAMPLES:
sage: from sage.misc.sageinspect import sage_getdoc_original
Here is a class that has its own docstring:
sage: print(sage_getdoc_original(sage.rings.integer.Integer)) <BLANKLINE> The ``Integer`` class represents arbitrary precision integers. It derives from the ``Element`` class, so integers can be used as ring elements anywhere in Sage. ...
Here is a class that does not have its own docstring, so that the docstring of the
__init__
method is used:sage: print(sage_getdoc_original(Parent)) <BLANKLINE> Base class for all parents. <BLANKLINE> Parents are the Sage/mathematical analogues of container objects in computer science. ...
Old-style classes are supported:
sage: class OldStyleClass: ....: def __init__(self): ....: '''The __init__ docstring''' ....: pass sage: print(sage_getdoc_original(OldStyleClass)) The __init__ docstring
When there is no
__init__
method, we just get an empty string:sage: class OldStyleClass: ....: pass sage: sage_getdoc_original(OldStyleClass) ''
If an instance of a class does not have its own docstring, the docstring of its class results:
sage: sage_getdoc_original(sage.plot.colors.aliceblue) == sage_getdoc_original(sage.plot.colors.Color) True
-
sage.misc.sageinspect.
sage_getfile
(obj)¶ Get the full file name associated to
obj
as a string.INPUT:
obj
, a Sage object, module, etc.EXAMPLES:
sage: from sage.misc.sageinspect import sage_getfile sage: sage_getfile(sage.rings.rational)[-23:] 'sage/rings/rational.pyx' sage: sage_getfile(Sq)[-42:] 'sage/algebras/steenrod/steenrod_algebra.py'
The following tests against some bugs fixed in trac ticket #9976:
sage: obj = sage.combinat.partition_algebra.SetPartitionsAk sage: obj = sage.combinat.partition_algebra.SetPartitionsAk sage: sage_getfile(obj) '...sage/combinat/partition_algebra.py'
And here is another bug, fixed in trac ticket #11298:
sage: P.<x,y> = QQ[] sage: sage_getfile(P) '...sage/rings/polynomial/multi_polynomial_libsingular.pyx'
A problem fixed in trac ticket #16309:
sage: cython(''' ....: class Bar: pass ....: cdef class Foo: pass ....: ''') sage: sage_getfile(Bar) '...pyx' sage: sage_getfile(Foo) '...pyx'
By trac ticket #18249, we return an empty string for Python builtins. In that way, there is no error when the user types, for example,
range?
:sage: sage_getfile(range) ''
AUTHORS:
- Nick Alexander
- Simon King
-
sage.misc.sageinspect.
sage_getsource
(obj)¶ Return the source code associated to obj as a string, or None.
INPUT:
obj
– function, etc.
EXAMPLES:
sage: from sage.misc.sageinspect import sage_getsource sage: sage_getsource(identity_matrix)[19:60] 'identity_matrix(ring, n=0, sparse=False):' sage: sage_getsource(identity_matrix)[19:60] 'identity_matrix(ring, n=0, sparse=False):'
AUTHORS:
- William Stein
- extensions by Nick Alexander
-
sage.misc.sageinspect.
sage_getsourcelines
(obj)¶ Return a pair ([source_lines], starting line number) of the source code associated to obj, or None.
INPUT:
obj
– function, etc.
OUTPUT:
(source_lines, lineno) or None:
source_lines
is a list of strings, andlineno
is an integer.EXAMPLES:
sage: from sage.misc.sageinspect import sage_getsourcelines sage: sage_getsourcelines(matrix)[1] 27 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 forCachedFunction
: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''') sage: sage_getsourcelines(test_funct) (['cpdef test_funct(x,y): return\n'], 6)
The following tests that an instance of
functools.partial
is correctly dealt with (see trac ticket #9976):sage: obj = sage.combinat.partition_algebra.SetPartitionsAk sage: sage_getsourcelines(obj) (['def create_set_partition_function(letter, k):\n', ... ' raise ValueError("k must be an integer or an integer + 1/2")\n'], 36)
Here are some cases that were covered in trac ticket #11298; note that line numbers may easily change, and therefore we do not test them:
sage: P.<x,y> = QQ[] sage: I = P*[x,y] sage: sage_getsourcelines(P) (['cdef class MPolynomialRing_libsingular(MPolynomialRing_generic):\n', '\n', ' def __cinit__(self):\n', ...) sage: sage_getsourcelines(I) (['class MPolynomialIdeal( MPolynomialIdeal_singular_repr, \\\n', ...) sage: x = var('x') sage: sage_getsourcelines(x) (['cdef class Expression(CommutativeRingElement):\n', ' cpdef object pyobject(self):\n', ...) sage: sage_getsourcelines(x)[0][-1] # last line ' return S\n'
We show some enhancements provided by trac ticket #11768. First, we use a dummy parent class that has defined an element class by a nested class definition:
sage: from sage.misc.nested_class_test import TestNestedParent sage: from sage.misc.sageinspect import sage_getsource sage: P = TestNestedParent() sage: E = P.element_class sage: E.__bases__ (<class sage.misc.nested_class_test.TestNestedParent.Element at ...>, <class 'sage.categories.sets_cat.Sets.element_class'>) sage: print(sage_getsource(E)) class Element: "This is a dummy element class" pass sage: print(sage_getsource(P)) class TestNestedParent(UniqueRepresentation, Parent): ... class Element: "This is a dummy element class" pass
Here is another example that relies on a nested class definition in the background:
sage: C = AdditiveMagmas() sage: HC = C.Homsets() sage: sage_getsourcelines(HC) ([' class Homsets(HomsetsCategory):\n', ...], ...)
Testing against a bug that has occured during work on trac ticket #11768:
sage: P.<x,y> = QQ[] sage: I = P*[x,y] sage: sage_getsourcelines(I) (['class MPolynomialIdeal( MPolynomialIdeal_singular_repr, \\\n', ' MPolynomialIdeal_macaulay2_repr, \\\n', ' MPolynomialIdeal_magma_repr, \\\n', ' Ideal_generic ):\n', ' def __init__(self, ring, gens, coerce=True):\n', ...)
AUTHORS:
- William Stein
- Extensions by Nick Alexander
- Extension to interactive Cython code by Simon King
- 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.
-
sage.misc.sageinspect.
sage_getvariablename
(self, omit_underscore_names=True)¶ Attempt to get the name of a Sage object.
INPUT:
self
– any object.omit_underscore_names
– boolean, defaultTrue
.
OUTPUT:
If the user has assigned an object
obj
to a variable name, then return that variable name. If several variables point toobj
, return a sorted list of those names. Ifomit_underscore_names
is True (the default) then omit names starting with an underscore “_”.This is a modified version of code taken from http://pythonic.pocoo.org/2009/5/30/finding-objects-names, written by Georg Brandl.
EXAMPLES:
sage: from sage.misc.sageinspect import sage_getvariablename sage: A = random_matrix(ZZ, 100) sage: sage_getvariablename(A) 'A' sage: B = A sage: sage_getvariablename(A) ['A', 'B']
If an object is not assigned to a variable, an empty list is returned:
sage: sage_getvariablename(random_matrix(ZZ, 60)) []