def can_document_member(cls, member, membername, isattr, parent): # It can be documented if it is a genuine function. # Often, a class instance has the same documentation as its class, # and then we typically want to document the class and not the instance. # However, there is an exception: CachedFunction(f) returns a class instance, # whose doc string coincides with that of f and is thus different from # that of the class CachedFunction. In that situation, we want that f is documented. # This is part of SAGE TRAC 9976 return isinstance(member, (FunctionType, BuiltinFunctionType)) or (isclassinstance(member) and _sage_getdoc_unformatted(member)!=_sage_getdoc_unformatted(member.__class__))
def args_on_obj(obj): if hasattr(obj, "_sage_argspec_"): return obj._sage_argspec_() if inspect.isbuiltin(obj) or \ inspect.ismethoddescriptor(obj): # can never get arguments of a C function or method unless # a function to do so is supplied if self.env.config.autodoc_builtin_argspec: argspec = self.env.config.autodoc_builtin_argspec(obj) return argspec else: return None argspec = sage_getargspec(obj) #inspect.getargspec(obj) if isclassinstance(obj) or inspect.isclass(obj): # if a class should be documented as function, we try # to use the constructor signature as function # signature without the first argument. if argspec is not None and argspec[0]: del argspec[0][0] return argspec
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 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
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)