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)
'# distutils: ...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()[:50]
'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)
'@cython.binding(True)\ndef 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 github issue #9976 and github issue #14017, introspection also works for interactively defined Cython code, and with rather tricky argument lines:

sage: # needs sage.misc.cython
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)
FullArgSpec(args=['x', 'a', 'b'], varargs='args', varkw='kwds', defaults=(1, ')"', {False: 'bar'}), kwonlyargs=[], kwonlydefaults=None, annotations={})
class sage.misc.sageinspect.BlockFinder#

Bases: object

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: 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: v = visitor.visit(ast.parse("{'a':('e',2,[None,({False:True},'pi')]), 37.0:'temp'}").body[0].value)
sage: sorted(v.items(), key=lambda x: str(x[0]))
[(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: attrs = [x for x in dir(v) if not x.startswith('__')]
sage: '_attributes' in attrs and '_fields' in attrs and 'col_offset' in attrs
True
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
[11, 15, 6, 2.3333333333333335, 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: v = [vis(d) for d in ['{}', "{1:one, 'two':2, other:bother}"]]
sage: [sorted(d.items(), key=lambda x: str(x[0])) for d in v]
[[], [(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 ['foo', 'bar']]
['foo', 'bar']
sage: [type(vis(n)) for n in ['foo', 'bar']]
[<class 'str'>, <class 'str'>]
visit_NameConstant(node)#

Visit a Python AST ast.NameConstant node.

This is an optimization added in Python 3.4 for the special cases of True, False, and None.

INPUT:

  • node - the node instance to visit

OUTPUT:

  • None, True, False.

EXAMPLES:

sage: import ast, sage.misc.sageinspect as sms
sage: visitor = sms.SageArgSpecVisitor()
sage: vis = lambda x: visitor.visit_NameConstant(ast.parse(x).body[0].value)
sage: [vis(n) for n in ['True', 'False', 'None']]
[True, False, None]
sage: [type(vis(n)) for n in ['True', 'False', 'None']]
[<class 'bool'>, <class 'bool'>, <class 'NoneType'>]
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']]
[123, 0.0]

Note

On Python 3 negative numbers are parsed first, for some reason, as a UnaryOp node.

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"', "'syntax'", r'''r"tr\ee"''']]
['abstract', '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]
visit_arg(node)#

Visit a Python AST ast.arg node.

This node type is only on Python 3, where function arguments are more complex than just an identifier (e.g. they may also include annotations).

For now we simply return the argument identifier as a string.

INPUT:

  • node – the node instance to visit

OUTPUT:

the argument name

EXAMPLES:

sage: import ast, sage.misc.sageinspect as sms
sage: s = "def f(a, b=2, c={'a': [4, 5.5, False]}, d=(None, True)):\n    return"
sage: visitor = sms.SageArgSpecVisitor()
sage: args = ast.parse(s).body[0].args.args
sage: [visitor.visit_arg(n) for n in args]
['a', 'b', 'c', 'd']
sage.misc.sageinspect.formatannotation(annotation, base_module=None)#

This is taken from Python 3.7’s inspect.py; the only change is to add documentation.

INPUT:

  • annotation – annotation for a function

  • base_module (optional, default None)

This is only relevant with Python 3, so the doctests are marked accordingly.

EXAMPLES:

sage: from sage.misc.sageinspect import formatannotation
sage: import inspect
sage: def foo(a, *, b:int, **kwargs):
....:     pass
sage: s = inspect.signature(foo)

sage: a = s.parameters['a'].annotation
sage: a
<class 'inspect._empty'>
sage: formatannotation(a)
'inspect._empty'

sage: b = s.parameters['b'].annotation
sage: b
<class 'int'>
sage: formatannotation(b)
'int'
sage.misc.sageinspect.is_function_or_cython_function(obj)#

Check whether something is a function.

This is a variant of inspect.isfunction(): We assume that anything which has a genuine __code__ attribute (not using __getattr__ overrides) is a function. This is meant to support Cython functions.

Think twice before using this function (or any function from the inspect or sage.misc.sageinspect modules). Most uses of inspect.isfunction() in ordinary library code can be replaced by callable().

EXAMPLES:

sage: from sage.misc.sageinspect import is_function_or_cython_function
sage: def f(): pass
sage: is_function_or_cython_function(f)
True
sage: is_function_or_cython_function(lambda x:x)
True
sage: from sage.categories.coercion_methods import _mul_parent
sage: is_function_or_cython_function(_mul_parent)
True
sage: is_function_or_cython_function(Integer.digits)     # unbound method
False
sage: is_function_or_cython_function(Integer(1).digits)  # bound method
False
sage.misc.sageinspect.isclassinstance(obj)#

Check if argument is instance of non built-in class

INPUT: obj – object

EXAMPLES:

sage: from sage.misc.sageinspect import isclassinstance
sage: isclassinstance(int)
False
sage: class myclass: pass
sage: isclassinstance(myclass())
True
sage: isclassinstance(myclass)
False
sage: class mymetaclass(type): pass
sage: class myclass2(metaclass=mymetaclass): pass
sage: isclassinstance(myclass2)
False
sage.misc.sageinspect.loadable_module_extension()#

Return the filename extension of loadable modules, including the dot.

This function is deprecated.

EXAMPLES:

sage: from sage.misc.sageinspect import loadable_module_extension
sage: from importlib.machinery import EXTENSION_SUFFIXES
sage: loadable_module_extension() in EXTENSION_SUFFIXES
doctest:warning...
DeprecationWarning: loadable_module_extension is deprecated; use importlib.machinery.EXTENSION_SUFFIXES instead
See https://github.com/sagemath/sage/issues/33636 for details.
True
sage.misc.sageinspect.sage_formatargspec(args, varargs=None, varkw=None, defaults=None, kwonlyargs=(), kwonlydefaults=None, annotations={}, formatarg=<class 'str'>, formatvarargs=None, formatvarkw=None, formatvalue=None, formatreturns=None, formatannotation=None)#

Format an argument spec from the values returned by getfullargspec.

The first seven arguments are (args, varargs, varkw, defaults, kwonlyargs, kwonlydefaults, annotations). The other five arguments are the corresponding optional formatting functions that are called to turn names and values into strings. The last argument is an optional function to format the sequence of arguments.

This is taken from Python 3.7’s inspect.py, where it is deprecated. The only change, aside from documentation (this paragraph and the next, plus doctests), is to remove the deprecation warning.

Sage uses this function to format arguments, as obtained by sage_getargspec(). Since sage_getargspec() works for Cython functions while Python’s inspect module does not, it makes sense to keep this function for formatting instances of inspect.FullArgSpec.

EXAMPLES:

sage: from sage.misc.sageinspect import sage_formatargspec
sage: args = ['a', 'b', 'c']
sage: defaults = [3]
sage: sage_formatargspec(args, defaults=defaults)
'(a, b, c=3)'
sage.misc.sageinspect.sage_getargspec(obj)#

Return the names and default values of a function’s arguments.

INPUT:

  • obj – any callable object

OUTPUT:

A named tuple FullArgSpec is returned, as specified by the Python library function inspect.getfullargspec().

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 the CachedMethod 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)
FullArgSpec(args=['x', 'y', 'z', 't'], varargs='args', varkw='keywords',
            defaults=(1, 2), kwonlyargs=[], kwonlydefaults=None, annotations={})

We now run sage_getargspec on some functions from the Sage library:

sage: sage_getargspec(identity_matrix)                                          # needs sage.modules
FullArgSpec(args=['ring', 'n', 'sparse'], varargs=None, varkw=None,
            defaults=(0, False), kwonlyargs=[], kwonlydefaults=None,
            annotations={})
sage: sage_getargspec(factor)
FullArgSpec(args=['n', 'proof', 'int_', 'algorithm', 'verbose'],
            varargs=None, varkw='kwds', defaults=(None, False, 'pari', 0),
            kwonlyargs=[], kwonlydefaults=None, annotations={})

In the case of a class or a class instance, the FullArgSpec of the __new__, __init__ or __call__ method is returned:

sage: P.<x,y> = QQ[]
sage: sage_getargspec(P)                                                        # needs sage.libs.singular
FullArgSpec(args=['base_ring', 'n', 'names', 'order'],
            varargs=None, varkw=None, defaults=('degrevlex',),
            kwonlyargs=[], kwonlydefaults=None, annotations={})
sage: sage_getargspec(P.__class__)                                              # needs sage.libs.singular
FullArgSpec(args=['self', 'x'], varargs='args', varkw='kwds', defaults=(0,),
            kwonlyargs=[], kwonlydefaults=None, annotations={})

The following tests against various bugs that were fixed in github issue #9976:

sage: from sage.rings.polynomial.real_roots import bernstein_polynomial_factory_ratlist     # needs sage.modules
sage: sage_getargspec(bernstein_polynomial_factory_ratlist.coeffs_bitsize)                  # needs sage.modules
FullArgSpec(args=['self'], varargs=None, varkw=None, defaults=None,
            kwonlyargs=[], kwonlydefaults=None, annotations={})
sage: from sage.rings.polynomial.pbori.pbori import BooleanMonomialMonoid       # needs sage.rings.polynomial.pbori
sage: sage_getargspec(BooleanMonomialMonoid.gen)                                # needs sage.rings.polynomial.pbori
FullArgSpec(args=['self', 'i'], varargs=None, varkw=None, defaults=(0,),
            kwonlyargs=[], kwonlydefaults=None, annotations={})
sage: I = P*[x,y]
sage: sage_getargspec(I.groebner_basis)                                         # needs sage.libs.singular
FullArgSpec(args=['self', 'algorithm', 'deg_bound', 'mult_bound', 'prot'],
            varargs='args', varkw='kwds', defaults=('', None, None, False),
            kwonlyargs=[], kwonlydefaults=None, annotations={})
sage: cython("cpdef int foo(x,y) except -1: return 1")                          # needs sage.misc.cython
sage: sage_getargspec(foo)                                                      # needs sage.misc.cython
FullArgSpec(args=['x', 'y'], varargs=None, varkw=None, defaults=None,
            kwonlyargs=[], kwonlydefaults=None, annotations={})

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)
FullArgSpec(args=['a', 'b', 'c', 'd'], varargs=None, varkw=None, defaults=(1,),
            kwonlyargs=[], kwonlydefaults=None, annotations={})

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 - function

  • obj_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)                                              # needs sage.modules
'(ring, n=0, sparse=False)'
sage: sage_getdef(identity_matrix, 'identity_matrix')                           # needs sage.modules
'identity_matrix(ring, n=0, sparse=False)'

Check that github issue #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=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.

The optional boolean argument embedded controls the string formatting. It is False by default.

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]                                      # needs sage.modules
'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 of obj.__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))

    The :class:`Integer` class represents arbitrary precision
    integers. It derives from the :class:`Element` class, so
    integers can be used as ring elements anywhere in Sage.
...

If the class does not have a docstring, the docstring of the __init__ method is used, but not the __init__ method of the base class (this was fixed in github issue #24936):

sage: from sage.categories.category import Category
sage: class A(Category):
....:     def __init__(self):
....:         '''The __init__ docstring'''
sage: sage_getdoc_original(A)
'The __init__ docstring'
sage: class B(Category):
....:     pass
sage: sage_getdoc_original(B)
''

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)          # needs sage.plot
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)
'...sage/rings/rational.pyx'
sage: sage_getfile(Sq)                                                          # needs sage.combinat sage.modules
'...sage/algebras/steenrod/steenrod_algebra.py'
sage: sage_getfile(x)                                                           # needs sage.symbolic
'...sage/symbolic/expression.pyx'

The following tests against some bugs fixed in github issue #9976:

sage: obj = sage.combinat.partition_algebra.SetPartitionsAk                     # needs sage.combinat sage.modules
sage: sage_getfile(obj)                                                         # needs sage.combinat sage.modules
'...sage/combinat/partition_algebra.py'

And here is another bug, fixed in github issue #11298:

sage: P.<x,y> = QQ[]
sage: sage_getfile(P)                                                           # needs sage.libs.singular
'...sage/rings/polynomial/multi_polynomial_libsingular...'

A problem fixed in github issue #16309:

sage: cython(                                                                   # needs sage.misc.cython
....: '''
....: class Bar: pass
....: cdef class Foo: pass
....: ''')
sage: sage_getfile(Bar)                                                         # needs sage.misc.cython
'...pyx'
sage: sage_getfile(Foo)                                                         # needs sage.misc.cython
'...pyx'

By github issue #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_getfile_relative(obj)#

Get the file name associated to obj as a string.

This is the same as sage_getfile(), but if the source file is part of the sage.* namespace, it makes the file name relative so that it starts with sage/.

INPUT: obj, a Sage object, module, etc.

EXAMPLES:

sage: from sage.misc.sageinspect import sage_getfile_relative
sage: sage_getfile_relative(sage.rings.rational)
'sage/rings/rational.pyx'
sage: sage_getfile_relative(Sq)                                                 # needs sage.combinat sage.modules
'sage/algebras/steenrod/steenrod_algebra.py'
sage: sage_getfile_relative(x)                                                  # needs sage.symbolic
'sage/symbolic/expression.pyx'
sage: sage_getfile_relative(range)
''
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]                                    # needs sage.modules
'identity_matrix(ring, n=0, sparse=False):'
sage: sage_getsource(identity_matrix)[19:60]                                    # needs sage.modules
'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, and lineno is an integer.

EXAMPLES:

sage: from sage.misc.sageinspect import sage_getsourcelines
sage: sage_getsourcelines(matrix)[1]                                            # needs sage.modules
21
sage: sage_getsourcelines(matrix)[0][0]                                         # needs sage.modules
'def matrix(*args, **kwds):\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 CachedFunction:

sage: cachedfib = cached_function(fibonacci)                                    # needs sage.combinat
sage: sage_getsourcelines(cachedfib)[0][0]                                      # needs sage.combinat
'def fibonacci(n, algorithm="pari") -> Integer:\n'
sage: sage_getsourcelines(type(cachedfib))[0][0]                                # needs sage.combinat
'cdef class CachedFunction():\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, default True.

OUTPUT:

If the user has assigned an object obj to a variable name, then return that variable name. If several variables point to obj, return a sorted list of those names. If omit_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: # needs sage.modules
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))                               # needs sage.modules
[]