Inspect Python, Sage, and Cython objects¶
This module extends parts of Python’s inspect module to Cython objects.
EXAMPLES:
sage: from sage.misc.sageinspect import *
>>> from sage.all import *
>>> 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...'
>>> from sage.all import *
>>> sage_getfile(sage.rings.rational)
'.../rational.pyx'
>>> sage_getdoc(sage.rings.rational).lstrip()
'Rational Numbers...'
>>> 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()[51:-1]
'Inspect Python, Sage, and Cython objects...'
>>> from sage.all import *
>>> sage_getfile(sage.misc.sageinspect)
'.../sageinspect.py'
>>> print(sage_getdoc(sage.misc.sageinspect).lstrip()[:Integer(40)])
Inspect Python, Sage, and Cython objects
>>> sage_getsource(sage.misc.sageinspect).lstrip()[Integer(51):-Integer(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...'
>>> from sage.all import *
>>> sage_getfile(sage.rings.rational.Rational)
'.../rational.pyx'
>>> sage_getdoc(sage.rings.rational.Rational).lstrip()
'A rational number...'
>>> 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]                                        # needs sphinx
'Provide a "tokeneater()" method to detect the end '
sage: sage_getsource(BlockFinder)
'class BlockFinder:...'
>>> from sage.all import *
>>> sage_getfile(BlockFinder)
'.../sage/misc/sageinspect.py'
>>> sage_getdoc(BlockFinder).lstrip()[:Integer(50)]                                        # needs sphinx
'Provide a "tokeneater()" method to detect the end '
>>> 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):...'
>>> from sage.all import *
>>> sage_getdef(sage.rings.rational.make_rational, obj_name='mr')
'mr(s)'
>>> sage_getfile(sage.rings.rational.make_rational)
'.../rational.pyx'
>>> sage_getdoc(sage.rings.rational.make_rational).lstrip()
'Make a rational number ...'
>>> 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):...'
>>> from sage.all import *
>>> sage_getdef(sage.misc.sageinspect.sage_getfile, obj_name='sage_getfile')
'sage_getfile(obj)'
>>> sage_getfile(sage.misc.sageinspect.sage_getfile)
'.../sageinspect.py'
>>> sage_getdoc(sage.misc.sageinspect.sage_getfile).lstrip()
'Get the full file name associated to "obj" as a string...'
>>> sage_getsource(sage.misc.sageinspect.sage_getfile)[Integer(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)'
>>> from sage.all import *
>>> sage_getdef(''.find, 'find')
'find(*args, **kwds)'
>>> sage_getdef(str.find, 'find')
'find(*args, **kwds)'
By Issue #9976 and 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={})
>>> from sage.all import *
>>> # needs sage.misc.cython
>>> cython('def foo(unsigned int x=1, a=\')"\', b={not (2+1==3):\'bar\'}, *args, **kwds): return')
>>> print(sage_getsource(foo))
def foo(unsigned int x=1, a=')"', b={not (2+1==3):'bar'}, *args, **kwds): return
>>> sage_getargspec(foo)
FullArgSpec(args=['x', 'a', 'b'], varargs='args', varkw='kwds', defaults=(1, ')"', {False: 'bar'}), kwonlyargs=[], kwonlydefaults=None, annotations={})
AUTHORS:
- Originally taken from Fernando Perez’s IPython 
- William Stein: extensive modifications 
- William Stein: in - _sage_getargspec_cython(), a modified version of- inspect.getargspecfrom the Python Standard Library, which was taken from IPython for use in Sage
- Nick Alexander: extensions, testing 
- Simon King: some extension for Cython, generalisation of SageArgSpecVisitor 
- Simon King: in - sage_getsourcelines(), if a class has no docstring then let the class definition be found starting from the- __init__method.
- Simon King: in - sage_getsourcelines(), get source lines for dynamic classes
- Simon King: in - _sage_getargspec_cython(), return an- ArgSpec, fix some bugs
- Simon King (2011-09): added - _sage_getsourcelines_name_with_dot()
- Simon King (2013-02): in - _sage_getargspec_cython(), recognise varargs and default values in cython code, and return an- ArgSpec
- class sage.misc.sageinspect.BlockFinder[source]¶
- Bases: - object- Provide a - tokeneater()method to detect the end of a code block.- This is the Python library’s - inspect.BlockFindermodified to recognize Cython definitions.
- class sage.misc.sageinspect.SageArgSpecVisitor[source]¶
- 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'] - >>> from sage.all import * >>> import ast, sage.misc.sageinspect as sms >>> visitor = sms.SageArgSpecVisitor() >>> visitor.visit(ast.parse('[1,2,3]').body[Integer(0)].value) [1, 2, 3] >>> v = visitor.visit(ast.parse("{'a':('e',2,[None,({False:True},'pi')]), 37.0:'temp'}").body[Integer(0)].value) >>> sorted(v.items(), key=lambda x: str(x[Integer(0)])) [(37.0, 'temp'), ('a', ('e', 2, [None, ({False: True}, 'pi')]))] >>> v = ast.parse("jc = ['veni', 'vidi', 'vici']").body[Integer(0)]; v <...ast.Assign object at ...> >>> attrs = [x for x in dir(v) if not x.startswith('__')] >>> '_attributes' in attrs and '_fields' in attrs and 'col_offset' in attrs True >>> visitor.visit(v.targets[Integer(0)]) 'jc' >>> visitor.visit(v.value) ['veni', 'vidi', 'vici'] - visit_BinOp(node)[source]¶
- Visit a Python AST - ast.BinOpnode.- INPUT: - node– the node instance to visit
 - OUTPUT: the result that - noderepresents- 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] - >>> from sage.all import * >>> import ast, sage.misc.sageinspect as sms >>> visitor = sms.SageArgSpecVisitor() >>> vis = lambda x: visitor.visit(ast.parse(x).body[Integer(0)].value) >>> [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)[source]¶
- Visit a Python AST - ast.BoolOpnode.- INPUT: - node– the node instance to visit
 - OUTPUT: the result that - noderepresents- 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] - >>> from sage.all import * >>> import ast, sage.misc.sageinspect as sms >>> visitor = sms.SageArgSpecVisitor() >>> vis = lambda x: visitor.visit(ast.parse(x).body[Integer(0)].value) >>> [vis(d) for d in ['True and 1', 'False or 3 or None', '3 and 4']] #indirect doctest [1, 3, 4] 
 - visit_Compare(node)[source]¶
- Visit a Python AST - ast.Comparenode.- INPUT: - node– the node instance to visit
 - OUTPUT: the result that - noderepresents- 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] - >>> from sage.all import * >>> import ast, sage.misc.sageinspect as sms >>> visitor = sms.SageArgSpecVisitor() >>> vis = lambda x: visitor.visit_Compare(ast.parse(x).body[Integer(0)].value) >>> [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)[source]¶
- Visit a Python AST - ast.Dictnode.- INPUT: - node– the node instance to visit
 - OUTPUT: the dictionary the - noderepresents- 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)]] - >>> from sage.all import * >>> import ast, sage.misc.sageinspect as sms >>> visitor = sms.SageArgSpecVisitor() >>> vis = lambda x: visitor.visit_Dict(ast.parse(x).body[Integer(0)].value) >>> v = [vis(d) for d in ['{}', "{1:one, 'two':2, other:bother}"]] >>> [sorted(d.items(), key=lambda x: str(x[Integer(0)])) for d in v] [[], [(1, 'one'), ('other', 'bother'), ('two', 2)]] 
 - visit_List(node)[source]¶
- Visit a Python AST - ast.Listnode.- INPUT: - node– the node instance to visit
 - OUTPUT: the list the - noderepresents- 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']]] - >>> from sage.all import * >>> import ast, sage.misc.sageinspect as sms >>> visitor = sms.SageArgSpecVisitor() >>> vis = lambda x: visitor.visit_List(ast.parse(x).body[Integer(0)].value) >>> [vis(l) for l in ['[]', "['s', 't', 'u']", '[[e], [], [pi]]']] [[], ['s', 't', 'u'], [['e'], [], ['pi']]] 
 - visit_Name(node)[source]¶
- Visit a Python AST - ast.Namenode.- 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'>] - >>> from sage.all import * >>> import ast, sage.misc.sageinspect as sms >>> visitor = sms.SageArgSpecVisitor() >>> vis = lambda x: visitor.visit_Name(ast.parse(x).body[Integer(0)].value) >>> [vis(n) for n in ['foo', 'bar']] ['foo', 'bar'] >>> [type(vis(n)) for n in ['foo', 'bar']] [<class 'str'>, <class 'str'>] 
 - visit_NameConstant(node)[source]¶
- Visit a Python AST - ast.NameConstantnode.- 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'>] - >>> from sage.all import * >>> import ast, sage.misc.sageinspect as sms >>> visitor = sms.SageArgSpecVisitor() >>> vis = lambda x: visitor.visit_NameConstant(ast.parse(x).body[Integer(0)].value) >>> [vis(n) for n in ['True', 'False', 'None']] [True, False, None] >>> [type(vis(n)) for n in ['True', 'False', 'None']] [<class 'bool'>, <class 'bool'>, <class 'NoneType'>] 
 - visit_Num(node)[source]¶
- Visit a Python AST - ast.Numnode.- INPUT: - node– the node instance to visit
 - OUTPUT: the number the - noderepresents- 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] - >>> from sage.all import * >>> import ast, sage.misc.sageinspect as sms >>> visitor = sms.SageArgSpecVisitor() >>> vis = lambda x: visitor.visit_Num(ast.parse(x).body[Integer(0)].value) >>> [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)[source]¶
- Visit a Python AST - ast.Strnode.- INPUT: - node– the node instance to visit
 - OUTPUT: the string the - noderepresents- 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'] - >>> from sage.all import * >>> import ast, sage.misc.sageinspect as sms >>> visitor = sms.SageArgSpecVisitor() >>> vis = lambda x: visitor.visit_Str(ast.parse(x).body[Integer(0)].value) >>> [vis(s) for s in ['"abstract"', "'syntax'", r'''r"tr\ee"''']] ['abstract', 'syntax', 'tr\\ee'] 
 - visit_Tuple(node)[source]¶
- Visit a Python AST - ast.Tuplenode.- INPUT: - node– the node instance to visit
 - OUTPUT: the tuple the - noderepresents- 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')] - >>> from sage.all import * >>> import ast, sage.misc.sageinspect as sms >>> visitor = sms.SageArgSpecVisitor() >>> vis = lambda x: visitor.visit_Tuple(ast.parse(x).body[Integer(0)].value) >>> [vis(t) for t in ['()', '(x,y)', '("Au", "Al", "Cu")']] [(), ('x', 'y'), ('Au', 'Al', 'Cu')] 
 - visit_UnaryOp(node)[source]¶
- Visit a Python AST - ast.BinOpnode.- INPUT: - node– the node instance to visit
 - OUTPUT: the result that - noderepresents- 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] - >>> from sage.all import * >>> import ast, sage.misc.sageinspect as sms >>> visitor = sms.SageArgSpecVisitor() >>> vis = lambda x: visitor.visit_UnaryOp(ast.parse(x).body[Integer(0)].value) >>> [vis(d) for d in ['+(3*2)', '-(3*2)']] [6, -6] 
 - visit_arg(node)[source]¶
- Visit a Python AST - ast.argnode.- 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'] - >>> from sage.all import * >>> import ast, sage.misc.sageinspect as sms >>> s = "def f(a, b=2, c={'a': [4, 5.5, False]}, d=(None, True)):\n return" >>> visitor = sms.SageArgSpecVisitor() >>> args = ast.parse(s).body[Integer(0)].args.args >>> [visitor.visit_arg(n) for n in args] ['a', 'b', 'c', 'd'] 
 
- sage.misc.sageinspect.find_object_modules(obj)[source]¶
- Return a dictionary whose keys are the names of the modules where - objappear and the value at a given module name is the list of names that- objhave in that module.- It is very unlikely that the output dictionary has several keys except when - objis an instance of a class.- EXAMPLES: - sage: from sage.misc.sageinspect import find_object_modules sage: find_object_modules(RR) # needs sage.rings.real_mpfr {'sage.rings.real_mpfr': ['RR']} sage: find_object_modules(ZZ) {'sage.rings.integer_ring': ['Z', 'ZZ']} - >>> from sage.all import * >>> from sage.misc.sageinspect import find_object_modules >>> find_object_modules(RR) # needs sage.rings.real_mpfr {'sage.rings.real_mpfr': ['RR']} >>> find_object_modules(ZZ) {'sage.rings.integer_ring': ['Z', 'ZZ']} 
- sage.misc.sageinspect.formatannotation(annotation, base_module=None)[source]¶
- 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– (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' - >>> from sage.all import * >>> from sage.misc.sageinspect import formatannotation >>> import inspect >>> def foo(a, *, b:int, **kwargs): ... pass >>> s = inspect.signature(foo) >>> a = s.parameters['a'].annotation >>> a <class 'inspect._empty'> >>> formatannotation(a) 'inspect._empty' >>> b = s.parameters['b'].annotation >>> b <class 'int'> >>> formatannotation(b) 'int' 
- sage.misc.sageinspect.is_function_or_cython_function(obj)[source]¶
- 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 - inspector- sage.misc.sageinspectmodules). 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 - >>> from sage.all import * >>> from sage.misc.sageinspect import is_function_or_cython_function >>> def f(): pass >>> is_function_or_cython_function(f) True >>> is_function_or_cython_function(lambda x:x) True >>> from sage.categories.coercion_methods import _mul_parent >>> is_function_or_cython_function(_mul_parent) True >>> is_function_or_cython_function(Integer.digits) # unbound method False >>> is_function_or_cython_function(Integer(Integer(1)).digits) # bound method False 
- sage.misc.sageinspect.isclassinstance(obj)[source]¶
- 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 - >>> from sage.all import * >>> from sage.misc.sageinspect import isclassinstance >>> isclassinstance(int) False >>> class myclass: pass >>> isclassinstance(myclass()) True >>> isclassinstance(myclass) False >>> class mymetaclass(type): pass >>> class myclass2(metaclass=mymetaclass): pass >>> isclassinstance(myclass2) False 
- 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)[source]¶
- 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)' - >>> from sage.all import * >>> from sage.misc.sageinspect import sage_formatargspec >>> args = ['a', 'b', 'c'] >>> defaults = [Integer(3)] >>> sage_formatargspec(args, defaults=defaults) '(a, b, c=3)' 
- sage.misc.sageinspect.sage_getargspec(obj)[source]¶
- Return the names and default values of a function’s arguments. - INPUT: - obj– any callable object
 - OUTPUT: - A named tuple - FullArgSpecis 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- CachedMethoddecorator 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={}) - >>> from sage.all import * >>> from sage.misc.sageinspect import sage_getargspec >>> def f(x, y, z=Integer(1), t=Integer(2), *args, **keywords): ... pass >>> 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={}) - >>> from sage.all import * >>> sage_getargspec(identity_matrix) # needs sage.modules FullArgSpec(args=['ring', 'n', 'sparse'], varargs=None, varkw=None, defaults=(0, False), kwonlyargs=[], kwonlydefaults=None, annotations={}) >>> 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 - FullArgSpecof 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={}) - >>> from sage.all import * >>> P = QQ['x, y']; (x, y,) = P._first_ngens(2) >>> 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_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 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={}) - >>> from sage.all import * >>> from sage.rings.polynomial.real_roots import bernstein_polynomial_factory_ratlist # needs sage.modules >>> sage_getargspec(bernstein_polynomial_factory_ratlist.coeffs_bitsize) # needs sage.modules FullArgSpec(args=['self'], varargs=None, varkw=None, defaults=None, kwonlyargs=[], kwonlydefaults=None, annotations={}) >>> from sage.rings.polynomial.pbori.pbori import BooleanMonomialMonoid # needs sage.rings.polynomial.pbori >>> sage_getargspec(BooleanMonomialMonoid.gen) # needs sage.rings.polynomial.pbori FullArgSpec(args=['self', 'i'], varargs=None, varkw=None, defaults=(0,), kwonlyargs=[], kwonlydefaults=None, annotations={}) >>> I = P*[x,y] >>> 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={}) >>> cython("cpdef int foo(x,y) except -1: return 1") # needs sage.misc.cython >>> 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={}) - >>> from sage.all import * >>> def f(a, b, c, d=Integer(1)): ... return a + b + c + d >>> import functools >>> f1 = functools.partial(f, Integer(1), c=Integer(2)) >>> sage_getargspec(f1) FullArgSpec(args=['a', 'b', 'c', 'd'], varargs=None, varkw=None, defaults=(1,), kwonlyargs=[], kwonlydefaults=None, annotations={}) 
- sage.misc.sageinspect.sage_getdef(obj, obj_name='')[source]¶
- Return the definition header for any callable object. - INPUT: - obj– function
- obj_name– string (default:- ''); 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)' - >>> from sage.all import * >>> from sage.misc.sageinspect import sage_getdef >>> sage_getdef(identity_matrix) # needs sage.modules '(ring, n=0, sparse=False)' >>> sage_getdef(identity_matrix, 'identity_matrix') # needs sage.modules 'identity_matrix(ring, n=0, sparse=False)' - Check that Issue #6848 has been fixed: - sage: sage_getdef(RDF.random_element) '(min=-1, max=1)' - >>> from sage.all import * >>> sage_getdef(RDF.random_element) '(min=-1, max=1)' - If an exception is generated, None is returned instead and the exception is suppressed. 
- sage.misc.sageinspect.sage_getdoc(obj, obj_name='', embedded=False)[source]¶
- Return the docstring associated to - objas a string.- If - objis a Cython object with an embedded position in its docstring, the embedded position is stripped.- The optional boolean argument - embeddedcontrols 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 '...the n x n identity matrix...' 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' - >>> from sage.all import * >>> from sage.misc.sageinspect import sage_getdoc >>> sage_getdoc(identity_matrix)[Integer(87):Integer(124)] # needs sage.modules '...the n x n identity matrix...' >>> def f(a, b, c, d=Integer(1)): return a+b+c+d ... >>> import functools >>> f1 = functools.partial(f, Integer(1),c=Integer(2)) >>> f.__doc__ = "original documentation" >>> f1.__doc__ = "specialised documentation" >>> sage_getdoc(f) 'original documentation\n' >>> sage_getdoc(f1) 'specialised documentation\n' 
- sage.misc.sageinspect.sage_getdoc_original(obj)[source]¶
- Return the unformatted docstring associated to - objas a string.- If - objis 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 - >>> from sage.all import * >>> 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. ... - >>> from sage.all import * >>> print(sage_getdoc_original(sage.rings.integer.Integer)) <BLANKLINE> 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 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) '' - >>> from sage.all import * >>> from sage.categories.category import Category >>> class A(Category): ... def __init__(self): ... '''The __init__ docstring''' >>> sage_getdoc_original(A) 'The __init__ docstring' >>> class B(Category): ... pass >>> 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 - >>> from sage.all import * >>> class OldStyleClass: ... def __init__(self): ... '''The __init__ docstring''' ... pass >>> 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) '' - >>> from sage.all import * >>> class OldStyleClass: ... pass >>> 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 - >>> from sage.all import * >>> sage_getdoc_original(sage.plot.colors.aliceblue) == sage_getdoc_original(sage.plot.colors.Color) # needs sage.plot True 
- sage.misc.sageinspect.sage_getfile(obj)[source]¶
- Get the full file name associated to - objas 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: from sage.algebras.steenrod.steenrod_algebra import Sq # needs sage.combinat sage.modules 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' - >>> from sage.all import * >>> from sage.misc.sageinspect import sage_getfile >>> sage_getfile(sage.rings.rational) '...sage/rings/rational.pyx' >>> from sage.algebras.steenrod.steenrod_algebra import Sq # needs sage.combinat sage.modules >>> sage_getfile(Sq) # needs sage.combinat sage.modules '...sage/algebras/steenrod/steenrod_algebra.py' >>> sage_getfile(x) # needs sage.symbolic '...sage/symbolic/expression.pyx' - The following tests against some bugs fixed in 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' - >>> from sage.all import * >>> obj = sage.combinat.partition_algebra.SetPartitionsAk # needs sage.combinat sage.modules >>> sage_getfile(obj) # needs sage.combinat sage.modules '...sage/combinat/partition_algebra.py' - And here is another bug, fixed in Issue #11298: - sage: P.<x,y> = QQ[] sage: sage_getfile(P) # needs sage.libs.singular '...sage/rings/polynomial/multi_polynomial_libsingular...' - >>> from sage.all import * >>> P = QQ['x, y']; (x, y,) = P._first_ngens(2) >>> sage_getfile(P) # needs sage.libs.singular '...sage/rings/polynomial/multi_polynomial_libsingular...' - Another bug with editable meson install: - sage: P.<x,y> = QQ[] sage: I = P * [x,y] sage: path = sage_getfile(I.groebner_basis); path '.../sage/rings/qqbar_decorators.py' sage: path == sage_getfile(sage.rings.qqbar_decorators) True - >>> from sage.all import * >>> P = QQ['x, y']; (x, y,) = P._first_ngens(2) >>> I = P * [x,y] >>> path = sage_getfile(I.groebner_basis); path '.../sage/rings/qqbar_decorators.py' >>> path == sage_getfile(sage.rings.qqbar_decorators) True - A problem fixed in 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' - >>> from sage.all import * >>> cython( # needs sage.misc.cython ... ''' ... class Bar: pass ... cdef class Foo: pass ... ''') >>> sage_getfile(Bar) # needs sage.misc.cython '...pyx' >>> sage_getfile(Foo) # needs sage.misc.cython '...pyx' - By 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) '' - >>> from sage.all import * >>> sage_getfile(range) '' 
- sage.misc.sageinspect.sage_getfile_relative(obj)[source]¶
- Get the file name associated to - objas 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: from sage.algebras.steenrod.steenrod_algebra import Sq # needs sage.combinat sage.modules 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) '' - >>> from sage.all import * >>> from sage.misc.sageinspect import sage_getfile_relative >>> sage_getfile_relative(sage.rings.rational) 'sage/rings/rational.pyx' >>> from sage.algebras.steenrod.steenrod_algebra import Sq # needs sage.combinat sage.modules >>> sage_getfile_relative(Sq) # needs sage.combinat sage.modules 'sage/algebras/steenrod/steenrod_algebra.py' >>> sage_getfile_relative(x) # needs sage.symbolic 'sage/symbolic/expression.pyx' >>> sage_getfile_relative(range) '' 
- sage.misc.sageinspect.sage_getsource(obj)[source]¶
- 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):' - >>> from sage.all import * >>> from sage.misc.sageinspect import sage_getsource >>> sage_getsource(identity_matrix)[Integer(19):Integer(60)] # needs sage.modules 'identity_matrix(ring, n=0, sparse=False):' >>> sage_getsource(identity_matrix)[Integer(19):Integer(60)] # needs sage.modules 'identity_matrix(ring, n=0, sparse=False):' 
- sage.misc.sageinspect.sage_getsourcelines(obj)[source]¶
- 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_linesis a list of strings, and- linenois an integer.- EXAMPLES: - sage: from sage.misc.sageinspect import sage_getsourcelines sage: # needs sage.modules sage: sage_getsourcelines(matrix)[1] 21 sage: sage_getsourcelines(matrix)[0][0] 'def matrix(*args, **kwds):\n' - >>> from sage.all import * >>> from sage.misc.sageinspect import sage_getsourcelines >>> # needs sage.modules >>> sage_getsourcelines(matrix)[Integer(1)] 21 >>> sage_getsourcelines(matrix)[Integer(0)][Integer(0)] '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: # needs sage.combinat sage: cachedfib = cached_function(fibonacci) sage: sage_getsourcelines(cachedfib)[0][0] "def fibonacci(n, algorithm='pari') -> Integer:\n" sage: sage_getsourcelines(type(cachedfib))[0][0] 'cdef class CachedFunction():\n' - >>> from sage.all import * >>> # needs sage.combinat >>> cachedfib = cached_function(fibonacci) >>> sage_getsourcelines(cachedfib)[Integer(0)][Integer(0)] "def fibonacci(n, algorithm='pari') -> Integer:\n" >>> sage_getsourcelines(type(cachedfib))[Integer(0)][Integer(0)] 'cdef class CachedFunction():\n' 
- sage.misc.sageinspect.sage_getvariablename(self, omit_underscore_names=True)[source]¶
- 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 - objto a variable name, then return that variable name. If several variables point to- obj, return a sorted list of those names. If- omit_underscore_namesis- True(the default) then omit names starting with an underscore “_”.- 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'] - >>> from sage.all import * >>> # needs sage.modules >>> from sage.misc.sageinspect import sage_getvariablename >>> A = random_matrix(ZZ, Integer(100)) >>> sage_getvariablename(A) 'A' >>> B = A >>> 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 [] - >>> from sage.all import * >>> sage_getvariablename(random_matrix(ZZ, Integer(60))) # needs sage.modules []