def f(wrapper): update_wrapper(wrapper, wrapped, assigned=assigned, updated=updated) wrapper._sage_src_ = lambda: sage_getsource(wrapped) wrapper._sage_src_lines_ = lambda: sage_getsourcelines(wrapped) #Getting the signature right in documentation by Sphinx (Trac 9976) #The attribute _sage_argspec_() is read by Sphinx if present and used #as the argspec of the function instead of using reflection. wrapper._sage_argspec_ = lambda: sage_getargspec(wrapped) return wrapper
def f(wrapper, assigned=assigned, updated=updated): update_wrapper(wrapper, wrapped, assigned=assigned, updated=updated) # For backwards-compatibility with old versions of sage_wraps wrapper.f = wrapped # For forwards-compatibility with functools.wraps on Python 3 wrapper.__wrapped__ = wrapped wrapper._sage_src_ = lambda: sage_getsource(wrapped) wrapper._sage_src_lines_ = lambda: sage_getsourcelines(wrapped) #Getting the signature right in documentation by Sphinx (Trac 9976) #The attribute _sage_argspec_() is read by Sphinx if present and used #as the argspec of the function instead of using reflection. wrapper._sage_argspec_ = lambda: sage_getargspec(wrapped) return wrapper
def _sage_src_(self): """ Returns the source code for the wrapped function. EXAMPLES: sage: from sage.misc.sageinspect import sage_getsource sage: g = CachedFunction(number_of_partitions) sage: 'bober' in sage_getsource(g) True """ from sage.misc.sageinspect import sage_getsource return sage_getsource(self.f)
def _sage_src_(self): """ Returns the source code for the wrapped function. EXAMPLES: This class is rather abstract so we showcase its features using one of its subclasses:: sage: P.<x,y,z> = PolynomialRing(ZZ) sage: I = ideal( x^2 - 3*y, y^3 - x*y, z^3 - x, x^4 - y*z + 1 ) sage: "primary" in I.primary_decomposition._sage_src_() # indirect doctest True """ from sage.misc.sageinspect import sage_getsource return sage_getsource(self.f)
def _sage_src_(self): """ Returns the source code for the wrapped function. EXAMPLE: This class is rather abstract so we showcase its features using one of its subclasses:: sage: P.<x,y,z> = PolynomialRing(ZZ) sage: I = ideal( x^2 - 3*y, y^3 - x*y, z^3 - x, x^4 - y*z + 1 ) sage: "primary" in I.primary_decomposition._sage_src_() # indirect doctest True """ from sage.misc.sageinspect import sage_getsource return sage_getsource(self.f)
def _sage_src_(self): r""" Returns the source code for the wrapped function. TESTS:: sage: from sage.misc.sageinspect import sage_getsource sage: from sage.sets.set_from_iterator import Decorator sage: d = Decorator() sage: d.f = Rational.is_square sage: print sage_getsource(d.f) # indirect doctest def is_square(self): ... return mpq_sgn(self.value) >= 0 and mpz_perfect_square_p(mpq_numref(self.value)) and mpz_perfect_square_p(mpq_denref(self.value)) """ from sage.misc.sageinspect import sage_getsource return sage_getsource(self.f)
def _sage_src_(self): r""" Returns the source code for the wrapped function. TESTS:: sage: from sage.misc.sageinspect import sage_getsource sage: from sage.sets.set_from_iterator import Decorator sage: d = Decorator() sage: d.f = Rational.is_square sage: print(sage_getsource(d.f)) # indirect doctest def is_square(self): ... return mpq_sgn(self.value) >= 0 and mpz_perfect_square_p(mpq_numref(self.value)) and mpz_perfect_square_p(mpq_denref(self.value)) """ from sage.misc.sageinspect import sage_getsource return sage_getsource(self.f)
def _sage_src_(self): """ Returns the source code for this object, which is just the source code for the underlying function. See :module:`sage.misc.sageinspect` for more information on this convention. EXAMPLES:: sage: from sage.parallel.decorate import Parallel sage: p = Parallel(2) sage: def f(x, y): ... return x + y sage: from sage.misc.sageinspect import sage_getsource sage: 'return x + y' in sage_getsource(p(f)) True """ from sage.misc.sageinspect import sage_getsource return sage_getsource(self.func)
def _sage_src_(self): """ Returns the source code for this object, which is just the source code for the underlying function. See :module:`sage.misc.sageinspect` for more information on this convention. EXAMPLES:: sage: from sage.parallel.decorate import Parallel sage: p = Parallel(2) sage: def f(x, y): ....: return x + y sage: from sage.misc.sageinspect import sage_getsource sage: 'return x + y' in sage_getsource(p(f)) True """ from sage.misc.sageinspect import sage_getsource return sage_getsource(self.func)
def __call__(self, func): """Returns a function which acts as an inline operator.""" left_meth = self.operators[self.precedence]['left'] right_meth = self.operators[self.precedence]['right'] wrapper_name = func.__name__ wrapper_members = { 'function': staticmethod(func), left_meth: _infix_wrapper._left, right_meth: _infix_wrapper._right, '_sage_src_': lambda: sage_getsource(func) } for attr in WRAPPER_ASSIGNMENTS: try: wrapper_members[attr] = getattr(func, attr) except AttributeError: pass wrapper = type(wrapper_name, (_infix_wrapper, ), wrapper_members) wrapper_inst = wrapper() wrapper_inst.__dict__.update(getattr(func, '__dict__', {})) return wrapper_inst
def find_object_modules(obj): r""" Return a dictionary whose keys are the names of the modules where ``obj`` appear and the value at a given module name is the list of names that ``obj`` have in that module. It is very unlikely that the output dictionary has several keys except when ``obj`` is an instance of a class. EXAMPLES:: sage: from sage.misc.dev_tools import find_object_modules sage: find_object_modules(RR) {'sage.rings.real_mpfr': ['RR']} sage: find_object_modules(ZZ) {'sage.rings.integer_ring': ['Z', 'ZZ']} .. NOTE:: It might be a good idea to move this function in :mod:`sage.misc.sageinspect`. """ from sage.misc import sageinspect # see if the object is defined in its own module # might be wrong for class instances as the instanciation might appear # outside of the module !! module_name = None if sageinspect.isclassinstance(obj): module_name = obj.__class__.__module__ elif hasattr(obj, '__module__') and obj.__module__: module_name = obj.__module__ if module_name: if module_name not in sys.modules: raise ValueError("This should not happen!") d = sys.modules[module_name].__dict__ matching = sorted(key for key in d if d[key] is obj) if matching: return {module_name: matching} # otherwise, we parse all (already loaded) modules and hope to find # something module_to_obj = {} for module_name, module in sys.modules.items(): if module_name != '__main__' and hasattr(module, '__dict__'): d = module.__dict__ names = [key for key in d if d[key] is obj] if names: module_to_obj[module_name] = names # if the object is an instance, we try to guess where it is defined if sageinspect.isclassinstance(obj): dec_pattern = re.compile(r"^(\w[\w0-9\_]*)\s*=", re.MULTILINE) module_to_obj2 = {} for module_name, obj_names in module_to_obj.items(): module_to_obj2[module_name] = [] try: src = sageinspect.sage_getsource(sys.modules[module_name]) except TypeError: pass else: m = dec_pattern.search(src) while m: if m.group(1) in obj_names: module_to_obj2[module_name].append(m.group(1)) m = dec_pattern.search(src, m.end()) if not module_to_obj2[module_name]: del module_to_obj2[module_name] if module_to_obj2: return module_to_obj2 return module_to_obj
def __call__(self, func): """ Returns a function which acts as an inline operator. EXAMPLES:: sage: from sage.misc.decorators import infix_operator sage: def dot(a,b): return a.dot_product(b) sage: dot=infix_operator('multiply')(dot) sage: u=vector([1,2,3]) sage: v=vector([5,4,3]) sage: u *dot* v 22 sage: def eadd(a,b): ... return a.parent([i+j for i,j in zip(a,b)]) sage: eadd=infix_operator('add')(eadd) sage: u=vector([1,2,3]) sage: v=vector([5,4,3]) sage: u +eadd+ v (6, 6, 6) sage: 2*u +eadd+ v (7, 8, 9) sage: def thendo(a,b): return b(a) sage: thendo=infix_operator('or')(thendo) sage: x |thendo| cos |thendo| (lambda x: x^2) cos(x)^2 """ def left_func(self, right): """ The function for the operation on the left (e.g., __add__). EXAMPLES:: sage: def dot(a,b): return a.dot_product(b) sage: dot=infix_operator('multiply')(dot) sage: u=vector([1,2,3]) sage: v=vector([5,4,3]) sage: u *dot* v 22 """ if self.left is None: if self.right is None: new = copy(self) new.right = right return new else: raise SyntaxError("Infix operator already has its " "right argument") else: return self.function(self.left, right) def right_func(self, left): """ The function for the operation on the right (e.g., __radd__). EXAMPLES:: sage: def dot(a,b): return a.dot_product(b) sage: dot=infix_operator('multiply')(dot) sage: u=vector([1,2,3]) sage: v=vector([5,4,3]) sage: u *dot* v 22 """ if self.right is None: if self.left is None: new = copy(self) new.left = left return new else: raise SyntaxError("Infix operator already has its " "left argument") else: return self.function(left, self.right) @sage_wraps(func) class wrapper: def __init__(self, left=None, right=None): """ Initialize the actual infix object, with possibly a specified left and/or right operand. EXAMPLES:: sage: def dot(a,b): return a.dot_product(b) sage: dot=infix_operator('multiply')(dot) sage: u=vector([1,2,3]) sage: v=vector([5,4,3]) sage: u *dot* v 22 """ self.function = func self.left = left self.right = right def __call__(self, *args, **kwds): """ Call the passed function. EXAMPLES:: sage: def dot(a,b): return a.dot_product(b) sage: dot=infix_operator('multiply')(dot) sage: u=vector([1,2,3]) sage: v=vector([5,4,3]) sage: dot(u,v) 22 """ return self.function(*args, **kwds) setattr(wrapper, self.operators[self.precedence]['left'], left_func) setattr(wrapper, self.operators[self.precedence]['right'], right_func) wrapper._sage_src_ = lambda: sage_getsource(func) return wrapper()
def import_statements(*objects, **options): """ Print import statements for the given objects. INPUT: - ``*objects`` -- a sequence of objects. - ``lazy`` -- a boolean (default: ``False``) Whether to print a lazy import statement. - ``verbose`` -- a boolean (default: ``True``) Whether to print information in case of ambiguity. EXAMPLES:: sage: import_statements(WeylGroup, lazy_attribute) from sage.combinat.root_system.weyl_group import WeylGroup from sage.misc.lazy_attribute import lazy_attribute sage: import_statements(IntegerRing) from sage.rings.integer_ring import IntegerRing If ``lazy`` is True, then :func:`lazy_import` statements are displayed instead:: sage: import_statements(WeylGroup, lazy_attribute, lazy=True) from sage.misc.lazy_import import lazy_import lazy_import('sage.combinat.root_system.weyl_group', 'WeylGroup') lazy_import('sage.misc.lazy_attribute', 'lazy_attribute') In principle, the function should also work on object which are instances. In case of ambiguity, one or two warning lines are printed:: sage: import_statements(NN) from sage.rings.semirings.non_negative_integer_semiring import NN sage: import_statements(ZZ) ** Warning **: several names for that object: Z, ZZ from sage.rings.integer_ring import Z sage: import_statements(euler_phi) from sage.rings.arith import euler_phi sage: import_statements(x) ** Warning **: several modules for that object: sage.all_cmdline, sage.calculus.predefined, sage.interacts.library from sage.calculus.predefined import x If you don't like the warning you can disable them with the option ``verbose``:: sage: import_statements(ZZ, verbose=False) from sage.rings.integer_ring import Z sage: import_statements(x, verbose=False) from sage.calculus.predefined import x If the object has several names, an other way to get the import statement you expect is to use a string instead of the object:: sage: import_statements(cached_function) ** Warning **: several names for that object: CachedFunction, cached_function from sage.misc.cachefunc import CachedFunction sage: import_statements('cached_function') from sage.misc.cachefunc import cached_function sage: import_statements('Z') from sage.rings.integer_ring import Z Specifying a string is also useful for objects that are not imported in the Sage interpreter namespace by default. In this case, an object with that name is looked up in all the modules that have been imported in this session:: sage: print_import_statement Traceback (most recent call last): ... NameError: name 'print_import_statement' is not defined sage: import_statements("print_import_statement") from sage.misc.dev_tools import print_import_statement We test different object which have no appropriate answer:: sage: import_statements('my_tailor_is_rich') Traceback (most recent call last): ... ValueError: no import statement for my_tailor_is_rich sage: import_statements(5) Traceback (most recent call last): ... ValueError: no import statement for 5 """ import inspect, sys, re import sage.all from sage.misc import sageinspect from sage.misc.flatten import flatten lazy = options.get("lazy", False) verbose = options.get("verbose", True) if lazy: print "from sage.misc.lazy_import import lazy_import" for obj in objects: # if obj is a string use it has a name and look for an object if isinstance(obj, str): name = obj if name in sage.all.__dict__: obj = sage.all.__dict__[name] else: # Look for the first module which contains that name. # TODO: improve this heuristic. for module in sys.modules.values(): if hasattr(module, '__dict__') and name in module.__dict__: obj = module.__dict__[name] break else: name = None # Case 1: the object is a module if inspect.ismodule(obj): if lazy: print "lazy_import('%s')" % obj.__name__ else: print "import %s" % obj.__name__ continue # Case 2: the object is defined in its module module = None if sageinspect.isclassinstance(obj): module = obj.__class__.__module__ elif hasattr(obj, '__module__') and obj.__module__: module = obj.__module__ if module: d = sys.modules[module].__dict__ if name is None: names = sorted(key for key in d if d[key] is obj) else: names = [name] if names: if verbose and len(names) > 1: print " ** Warning **: several names for that object: %s" % ', '.join( names) print_import_statement(module, names[0], lazy) continue # Case 3: search for this object in all modules names = {} # dictionnary: module -> names of the object in that module for module in sys.modules: if module != '__main__' and hasattr(sys.modules[module], '__dict__'): d = sys.modules[module].__dict__ if name is not None: if name in d and d[name] is obj: names[module] = name else: n = [key for key in d if d[key] is obj] if n: names[module] = n all_names = sorted(set(flatten(names.values()))) if len(all_names) == 0: raise ValueError("no import statement for %s" % obj) elif verbose and len(all_names) > 1: print " ** Warning **: several names for that object:", print ", ".join(sorted(all_names)) modules = sorted(flatten(names), cmp=module_names_cmp) if verbose and len(modules) > 1: print " ** Warning **: several modules for that object:", print ", ".join(modules[:4]), if len(modules) > 4: print "..." else: print # Case 4: if the object is a class instance, we look for a # module where it is instanciated if sageinspect.isclassinstance(obj): names_pattern = dict( (name, re.compile("^%s\ *=" % name, re.MULTILINE)) for name in all_names) for module in modules: sources = sageinspect.sage_getsource(sys.modules[module]) for name in names[module]: if names_pattern[name].search(sources): break else: continue break else: module = modules[0] name = names[module][0] if name is not None: print_import_statement(module, name, lazy) else: raise ValueError("no import statement for %s" % obj)
def import_statements(*objects, **options): """ Print import statements for the given objects. INPUT: - ``*objects`` -- a sequence of objects. - ``lazy`` -- a boolean (default: ``False``) Whether to print a lazy import statement. - ``verbose`` -- a boolean (default: ``True``) Whether to print information in case of ambiguity. EXAMPLES:: sage: import_statements(WeylGroup, lazy_attribute) from sage.combinat.root_system.weyl_group import WeylGroup from sage.misc.lazy_attribute import lazy_attribute sage: import_statements(IntegerRing) from sage.rings.integer_ring import IntegerRing If ``lazy`` is True, then :func:`lazy_import` statements are displayed instead:: sage: import_statements(WeylGroup, lazy_attribute, lazy=True) from sage.misc.lazy_import import lazy_import lazy_import('sage.combinat.root_system.weyl_group', 'WeylGroup') lazy_import('sage.misc.lazy_attribute', 'lazy_attribute') In principle, the function should also work on object which are instances. In case of ambiguity, one or two warning lines are printed:: sage: import_statements(NN) from sage.rings.semirings.non_negative_integer_semiring import NN sage: import_statements(ZZ) ** Warning **: several names for that object: Z, ZZ from sage.rings.integer_ring import Z sage: import_statements(euler_phi) from sage.rings.arith import euler_phi sage: import_statements(x) ** Warning **: several modules for that object: sage.all_cmdline, sage.calculus.predefined, sage.interacts.library from sage.calculus.predefined import x If you don't like the warning you can disable them with the option ``verbose``:: sage: import_statements(ZZ, verbose=False) from sage.rings.integer_ring import Z sage: import_statements(x, verbose=False) from sage.calculus.predefined import x If the object has several names, an other way to get the import statement you expect is to use a string instead of the object:: sage: import_statements(cached_function) ** Warning **: several names for that object: CachedFunction, cached_function from sage.misc.cachefunc import CachedFunction sage: import_statements('cached_function') from sage.misc.cachefunc import cached_function sage: import_statements('Z') from sage.rings.integer_ring import Z Specifying a string is also useful for objects that are not imported in the Sage interpreter namespace by default. In this case, an object with that name is looked up in all the modules that have been imported in this session:: sage: print_import_statement Traceback (most recent call last): ... NameError: name 'print_import_statement' is not defined sage: import_statements("print_import_statement") from sage.misc.dev_tools import print_import_statement We test different object which have no appropriate answer:: sage: import_statements('my_tailor_is_rich') Traceback (most recent call last): ... ValueError: no import statement for my_tailor_is_rich sage: import_statements(5) Traceback (most recent call last): ... ValueError: no import statement for 5 """ import inspect, sys, re import sage.all from sage.misc import sageinspect from sage.misc.flatten import flatten lazy = options.get("lazy", False) verbose = options.get("verbose", True) if lazy: print "from sage.misc.lazy_import import lazy_import" for obj in objects: # if obj is a string use it has a name and look for an object if isinstance(obj, str): name = obj if name in sage.all.__dict__: obj = sage.all.__dict__[name] else: # Look for the first module which contains that name. # TODO: improve this heuristic. for module in sys.modules.values(): if hasattr(module, '__dict__') and name in module.__dict__: obj = module.__dict__[name] break else: name = None # Case 1: the object is a module if inspect.ismodule(obj): if lazy: print "lazy_import('%s')"%obj.__name__ else: print "import %s"%obj.__name__ continue # Case 2: the object is defined in its module module = None if sageinspect.isclassinstance(obj): module = obj.__class__.__module__ elif hasattr(obj, '__module__') and obj.__module__: module = obj.__module__ if module: d = sys.modules[module].__dict__ if name is None: names = sorted(key for key in d if d[key] is obj) else: names = [name] if names: if verbose and len(names) > 1: print " ** Warning **: several names for that object: %s"%', '.join(names) print_import_statement(module, names[0], lazy) continue # Case 3: search for this object in all modules names = {} # dictionnary: module -> names of the object in that module for module in sys.modules: if module != '__main__' and hasattr(sys.modules[module],'__dict__'): d = sys.modules[module].__dict__ if name is not None: if name in d and d[name] is obj: names[module] = name else: n = [key for key in d if d[key] is obj] if n: names[module] = n all_names = sorted(set(flatten(names.values()))) if len(all_names) == 0: raise ValueError("no import statement for %s"%obj) elif verbose and len(all_names) > 1: print " ** Warning **: several names for that object:", print ", ".join(sorted(all_names)) modules = sorted(flatten(names),cmp=module_names_cmp) if verbose and len(modules) > 1: print " ** Warning **: several modules for that object:", print ", ".join(modules[:4]), if len(modules) > 4: print "..." else: print # Case 4: if the object is a class instance, we look for a # module where it is instanciated if sageinspect.isclassinstance(obj): names_pattern = dict((name,re.compile("^%s\ *="%name, re.MULTILINE)) for name in all_names) for module in modules: sources = sageinspect.sage_getsource(sys.modules[module]) for name in names[module]: if names_pattern[name].search(sources): break else: continue break else: module = modules[0] name = names[module][0] if name is not None: print_import_statement(module, name, lazy) else: raise ValueError("no import statement for %s"%obj)
def find_object_modules(obj): r""" Return a dictionnary whose keys are the names of the modules where ``obj`` appear and the value at a given module name is the list of names that ``obj`` have in that module. It is very unlikely that the output dictionnary has several keys except when ``obj`` is an instance of a class. EXAMPLES:: sage: from sage.misc.dev_tools import find_object_modules sage: find_object_modules(RR) {'sage.rings.real_mpfr': ['RR']} sage: find_object_modules(ZZ) {'sage.rings.integer_ring': ['Z', 'ZZ']} .. NOTE:: It might be a good idea to move this function in :mod:`sage.misc.sageinspect`. """ from sage.misc import sageinspect # see if the object is defined in its own module # might be wrong for class instances as the instanciation might appear # outside of the module !! module_name = None if sageinspect.isclassinstance(obj): module_name = obj.__class__.__module__ elif hasattr(obj, '__module__') and obj.__module__: module_name = obj.__module__ if module_name: import sys if module_name not in sys.modules: raise ValueError("This should not happen!") d = sys.modules[module_name].__dict__ matching = sorted(key for key in d if d[key] is obj) if matching: return {module_name: matching} # otherwise, we parse all (already loaded) modules and hope to find # something import sys module_to_obj = {} for module_name, module in sys.modules.iteritems(): if module_name != '__main__' and hasattr(module, '__dict__'): d = module.__dict__ names = [key for key in d if d[key] is obj] if names: module_to_obj[module_name] = names # if the object is an instance, we try to guess where it is defined if sageinspect.isclassinstance(obj): import re dec_pattern = re.compile("^(\w[\w0-9\_]*)\s*=", re.MULTILINE) module_to_obj2 = {} for module_name, obj_names in module_to_obj.iteritems(): module_to_obj2[module_name] = [] src = sageinspect.sage_getsource(sys.modules[module_name]) m = dec_pattern.search(src) while m: if m.group(1) in obj_names: module_to_obj2[module_name].append(m.group(1)) m = dec_pattern.search(src, m.end()) if not module_to_obj2[module_name]: del module_to_obj2[module_name] if module_to_obj2: return module_to_obj2 return module_to_obj