Some tools for developers¶
AUTHORS:
Nicolas M. Thiery: initial version
Vincent Delecroix (2012 and 2013): improve import_statements
- sage.misc.dev_tools.find_object_modules(obj)[source]¶
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 thatobj
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) # 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.dev_tools 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']}
Note
It might be a good idea to move this function in
sage.misc.sageinspect
.
- sage.misc.dev_tools.find_objects_from_name(name, module_name=None, include_lazy_imports=False)[source]¶
Return the list of objects from
module_name
whose name isname
.INPUT:
name
– stringmodule_name
– string orNone
:If
module_name
isNone
, the function runs through all loaded modules and returns the list of objects whose name matchesname
.If
module_name
is a string, then search only in submodules ofmodule_name
.
include_lazy_imports
– boolean (default:False
); whether to include unresolved lazy imports (i.e.,LazyImport
objects) in the output.
In order to search through more modules you might use the function
load_submodules()
.EXAMPLES:
sage: import sage.misc.dev_tools as dt sage: dt.find_objects_from_name('FareySymbol') # needs sage.modular [<class 'sage.modular.arithgroup.farey_symbol.Farey'>] sage: # needs sympy sage: import sympy sage: dt.find_objects_from_name('RR') [Real Field with 53 bits of precision, RR] sage: dt.find_objects_from_name('RR', 'sage') [Real Field with 53 bits of precision] sage: dt.find_objects_from_name('RR', 'sympy') [RR]
>>> from sage.all import * >>> import sage.misc.dev_tools as dt >>> dt.find_objects_from_name('FareySymbol') # needs sage.modular [<class 'sage.modular.arithgroup.farey_symbol.Farey'>] >>> # needs sympy >>> import sympy >>> dt.find_objects_from_name('RR') [Real Field with 53 bits of precision, RR] >>> dt.find_objects_from_name('RR', 'sage') [Real Field with 53 bits of precision] >>> dt.find_objects_from_name('RR', 'sympy') [RR]
Examples that do not belong to the global namespace but in a loaded module:
sage: 'find_objects_from_name' in globals() False sage: objs = dt.find_objects_from_name('find_objects_from_name') sage: len(objs) 1 sage: dt.find_objects_from_name is dt.find_objects_from_name True
>>> from sage.all import * >>> 'find_objects_from_name' in globals() False >>> objs = dt.find_objects_from_name('find_objects_from_name') >>> len(objs) 1 >>> dt.find_objects_from_name is dt.find_objects_from_name True
When
include_lazy_imports=True
is used, severalLazyImport
objects that are resolving to the same object may be included in the output:sage: dt.find_objects_from_name('RR', include_lazy_imports=True) # needs sage.rings.real_mpfr [Real Field with 53 bits of precision, ... Real Field with 53 bits of precision, RR]
>>> from sage.all import * >>> dt.find_objects_from_name('RR', include_lazy_imports=True) # needs sage.rings.real_mpfr [Real Field with 53 bits of precision, ... Real Field with 53 bits of precision, RR]
Note
It might be a good idea to move this function into
sage.misc.sageinspect
.
- sage.misc.dev_tools.import_statement_string(module, names, lazy)[source]¶
Return a (lazy) import statement for
names
frommodule
.INPUT:
module
– the name of a modulenames
– list of 2-tuples containing names and alias to importlazy
– boolean; whether to return a lazy import statement
EXAMPLES:
sage: import sage.misc.dev_tools as dt sage: modname = 'sage.misc.dev_tools' sage: names_and_aliases = [('import_statement_string', 'iss')] sage: dt.import_statement_string(modname, names_and_aliases, False) 'from sage.misc.dev_tools import import_statement_string as iss' sage: dt.import_statement_string(modname, names_and_aliases, True) "lazy_import('sage.misc.dev_tools', 'import_statement_string', 'iss')" sage: dt.import_statement_string(modname, [('a','b'),('c','c'),('d','e')], False) 'from sage.misc.dev_tools import a as b, c, d as e' sage: dt.import_statement_string(modname, [(None,None)], False) 'import sage.misc.dev_tools'
>>> from sage.all import * >>> import sage.misc.dev_tools as dt >>> modname = 'sage.misc.dev_tools' >>> names_and_aliases = [('import_statement_string', 'iss')] >>> dt.import_statement_string(modname, names_and_aliases, False) 'from sage.misc.dev_tools import import_statement_string as iss' >>> dt.import_statement_string(modname, names_and_aliases, True) "lazy_import('sage.misc.dev_tools', 'import_statement_string', 'iss')" >>> dt.import_statement_string(modname, [('a','b'),('c','c'),('d','e')], False) 'from sage.misc.dev_tools import a as b, c, d as e' >>> dt.import_statement_string(modname, [(None,None)], False) 'import sage.misc.dev_tools'
- sage.misc.dev_tools.import_statements(*objects, **kwds)[source]¶
Print import statements for the given objects.
INPUT:
*objects
– a sequence of objects or comma-separated strings of nameslazy
– boolean (default:False
); whether to print a lazy import statementverbose
– boolean (default:True
); whether to print information in case of ambiguityanswer_as_str
– boolean (default:False
); ifTrue
return a string instead of printing the statement
EXAMPLES:
sage: import_statements(WeylGroup, lazy_attribute) # needs sage.libs.gap 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
>>> from sage.all import * >>> import_statements(WeylGroup, lazy_attribute) # needs sage.libs.gap from sage.combinat.root_system.weyl_group import WeylGroup from sage.misc.lazy_attribute import lazy_attribute >>> import_statements(IntegerRing) from sage.rings.integer_ring import IntegerRing
If
lazy
is True, thenlazy_import()
statements are displayed instead:sage: import_statements(WeylGroup, lazy_attribute, lazy=True) # needs sage.libs.gap 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')
>>> from sage.all import * >>> import_statements(WeylGroup, lazy_attribute, lazy=True) # needs sage.libs.gap 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(RDF) from sage.rings.real_double import RDF 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.arith.misc import euler_phi sage: import_statements(x) # needs sage.symbolic from sage.calculus.predefined import x
>>> from sage.all import * >>> import_statements(RDF) from sage.rings.real_double import RDF >>> import_statements(ZZ) # ** Warning **: several names for that object: Z, ZZ from sage.rings.integer_ring import Z >>> import_statements(euler_phi) from sage.arith.misc import euler_phi >>> import_statements(x) # needs sage.symbolic 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) # needs sage.symbolic from sage.calculus.predefined import x
>>> from sage.all import * >>> import_statements(ZZ, verbose=False) from sage.rings.integer_ring import Z >>> import_statements(x, verbose=False) # needs sage.symbolic 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(matrix) # needs sage.modules # ** Warning **: several names for that object: Matrix, matrix from sage.matrix.constructor import Matrix sage: import_statements('cached_function') from sage.misc.cachefunc import cached_function sage: import_statements('Z') # **Warning**: distinct objects with name 'Z' in: # - sage.calculus.predefined # - sage.rings.integer_ring from sage.rings.integer_ring import Z
>>> from sage.all import * >>> import_statements(matrix) # needs sage.modules # ** Warning **: several names for that object: Matrix, matrix from sage.matrix.constructor import Matrix >>> import_statements('cached_function') from sage.misc.cachefunc import cached_function >>> import_statements('Z') # **Warning**: distinct objects with name 'Z' in: # - sage.calculus.predefined # - sage.rings.integer_ring from sage.rings.integer_ring import Z
The strings are allowed to be comma-separated names, and parenthesis are stripped for convenience:
sage: import_statements('(floor, ceil)') # needs sage.symbolic from sage.functions.other import floor, ceil
>>> from sage.all import * >>> import_statements('(floor, ceil)') # needs sage.symbolic from sage.functions.other import floor, ceil
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: import_statement_string Traceback (most recent call last): ... NameError: name 'import_statement_string' is not defined sage: import_statements("import_statement_string") from sage.misc.dev_tools import import_statement_string
>>> from sage.all import * >>> import_statement_string Traceback (most recent call last): ... NameError: name 'import_statement_string' is not defined >>> import_statements("import_statement_string") from sage.misc.dev_tools import import_statement_string
Sometimes objects are imported as an alias (from XXX import YYY as ZZZ) or are affected (XXX = YYY) and the function might detect it:
sage: import_statements('FareySymbol') from sage.modular.arithgroup.farey_symbol import Farey as FareySymbol sage: import_statements('power') from sage.arith.power import generic_power as power
>>> from sage.all import * >>> import_statements('FareySymbol') from sage.modular.arithgroup.farey_symbol import Farey as FareySymbol >>> import_statements('power') from sage.arith.power import generic_power as power
In order to be able to detect functions that belong to a non-loaded module, you might call the helper
load_submodules()
as in the following:sage: import_statements('HeckeMonoid') Traceback (most recent call last): ... LookupError: no object named 'HeckeMonoid' sage: from sage.misc.dev_tools import load_submodules sage: load_submodules(sage.monoids) load sage.monoids.automatic_semigroup... succeeded load sage.monoids.hecke_monoid... succeeded load sage.monoids.indexed_free_monoid... succeeded sage: import_statements('HeckeMonoid') from sage.monoids.hecke_monoid import HeckeMonoid
>>> from sage.all import * >>> import_statements('HeckeMonoid') Traceback (most recent call last): ... LookupError: no object named 'HeckeMonoid' >>> from sage.misc.dev_tools import load_submodules >>> load_submodules(sage.monoids) load sage.monoids.automatic_semigroup... succeeded load sage.monoids.hecke_monoid... succeeded load sage.monoids.indexed_free_monoid... succeeded >>> import_statements('HeckeMonoid') from sage.monoids.hecke_monoid import HeckeMonoid
We test different objects which have no appropriate answer:
sage: import_statements('my_tailor_is_rich') Traceback (most recent call last): ... LookupError: no object named 'my_tailor_is_rich' sage: import_statements(5) Traceback (most recent call last): ... ValueError: no import statement found for '5'.
>>> from sage.all import * >>> import_statements('my_tailor_is_rich') Traceback (most recent call last): ... LookupError: no object named 'my_tailor_is_rich' >>> import_statements(Integer(5)) Traceback (most recent call last): ... ValueError: no import statement found for '5'.
We test that it behaves well with lazy imported objects (Issue #14767):
sage: import_statements(NN) from sage.rings.semirings.non_negative_integer_semiring import NN sage: import_statements('NN') from sage.rings.semirings.non_negative_integer_semiring import NN
>>> from sage.all import * >>> import_statements(NN) from sage.rings.semirings.non_negative_integer_semiring import NN >>> import_statements('NN') from sage.rings.semirings.non_negative_integer_semiring import NN
Deprecated lazy imports are ignored (see Issue #17458):
sage: lazy_import('sage.all', 'RR', 'deprecated_RR', namespace=sage.__dict__, deprecation=17458) sage: import_statements('deprecated_RR') Traceback (most recent call last): ... LookupError: object named 'deprecated_RR' is deprecated (see Issue #17458) sage: lazy_import('sage.all', 'RR', namespace=sage.__dict__, deprecation=17458) sage: import_statements('RR') from sage.rings.real_mpfr import RR
>>> from sage.all import * >>> lazy_import('sage.all', 'RR', 'deprecated_RR', namespace=sage.__dict__, deprecation=Integer(17458)) >>> import_statements('deprecated_RR') Traceback (most recent call last): ... LookupError: object named 'deprecated_RR' is deprecated (see Issue #17458) >>> lazy_import('sage.all', 'RR', namespace=sage.__dict__, deprecation=Integer(17458)) >>> import_statements('RR') from sage.rings.real_mpfr import RR
The following were fixed with Issue #15351:
sage: import_statements('Rationals') from sage.rings.rational_field import RationalField as Rationals sage: import_statements(sage.combinat.partition_algebra.SetPartitionsAk) from sage.combinat.partition_algebra import SetPartitionsAk sage: import_statements(CIF) from sage.rings.cif import CIF sage: import_statements(NaN) # needs sage.symbolic from sage.symbolic.constants import NaN sage: import_statements(pi) # needs sage.symbolic from sage.symbolic.constants import pi sage: import_statements('SAGE_ENV') from sage.env import SAGE_ENV sage: import_statements('graph_decompositions') import sage.graphs.graph_decompositions
>>> from sage.all import * >>> import_statements('Rationals') from sage.rings.rational_field import RationalField as Rationals >>> import_statements(sage.combinat.partition_algebra.SetPartitionsAk) from sage.combinat.partition_algebra import SetPartitionsAk >>> import_statements(CIF) from sage.rings.cif import CIF >>> import_statements(NaN) # needs sage.symbolic from sage.symbolic.constants import NaN >>> import_statements(pi) # needs sage.symbolic from sage.symbolic.constants import pi >>> import_statements('SAGE_ENV') from sage.env import SAGE_ENV >>> import_statements('graph_decompositions') import sage.graphs.graph_decompositions
Check that a name from the global namespace is properly found (see Issue #23779):
sage: import_statements('log') from sage.misc.functional import log
>>> from sage.all import * >>> import_statements('log') from sage.misc.functional import log
Note
The programmers try to made this function as smart as possible. Nevertheless it is far from being perfect (for example it does not detect deprecated stuff). So, if you use it, double check the answer and report weird behaviors.
- sage.misc.dev_tools.load_submodules(module=None, exclude_pattern=None)[source]¶
Load all submodules of a given modules.
This method is intended to be used by developers and especially the one who uses
import_statements()
. By default it load the sage library and it takes around a minute.INPUT:
module
– an optional moduleexclude_pattern
– an optional regular expression pattern of module names that have to be excluded
EXAMPLES:
sage: sage.misc.dev_tools.load_submodules(sage.combinat) load sage.combinat.algebraic_combinatorics... succeeded ... load sage.combinat.words.suffix_trees... succeeded
>>> from sage.all import * >>> sage.misc.dev_tools.load_submodules(sage.combinat) load sage.combinat.algebraic_combinatorics... succeeded ... load sage.combinat.words.suffix_trees... succeeded
Calling a second time has no effect (since the function does not import modules already imported):
sage: sage.misc.dev_tools.load_submodules(sage.combinat)
>>> from sage.all import * >>> sage.misc.dev_tools.load_submodules(sage.combinat)
The second argument allows to exclude a pattern:
sage: sage.misc.dev_tools.load_submodules(sage.geometry, "database$|lattice") load sage.geometry.cone... succeeded load sage.geometry.cone_catalog... succeeded load sage.geometry.fan_isomorphism... succeeded ... load sage.geometry.riemannian_manifolds.surface3d_generators... succeeded sage: sage.misc.dev_tools.load_submodules(sage.geometry) load sage.geometry.polyhedron.lattice_euclidean_group_element... succeeded load sage.geometry.polyhedron.palp_database... succeeded load sage.geometry.polyhedron.ppl_lattice_polygon... succeeded
>>> from sage.all import * >>> sage.misc.dev_tools.load_submodules(sage.geometry, "database$|lattice") load sage.geometry.cone... succeeded load sage.geometry.cone_catalog... succeeded load sage.geometry.fan_isomorphism... succeeded ... load sage.geometry.riemannian_manifolds.surface3d_generators... succeeded >>> sage.misc.dev_tools.load_submodules(sage.geometry) load sage.geometry.polyhedron.lattice_euclidean_group_element... succeeded load sage.geometry.polyhedron.palp_database... succeeded load sage.geometry.polyhedron.ppl_lattice_polygon... succeeded
- sage.misc.dev_tools.runsnake(command)[source]¶
Graphical profiling with
runsnake
.INPUT:
command
– the command to be run as a string
EXAMPLES:
sage: from sage.misc.dev_tools import runsnake sage: runsnake("list(SymmetricGroup(3))") # optional - runsnake
>>> from sage.all import * >>> from sage.misc.dev_tools import runsnake >>> runsnake("list(SymmetricGroup(3))") # optional - runsnake
command
is first preparsed (seepreparse()
):sage: runsnake('for x in range(1,4): print(x^2)') # optional - runsnake 1 4 9
>>> from sage.all import * >>> runsnake('for x in range(1,4): print(x^2)') # optional - runsnake 1 4 9
runsnake()
requires the programrunsnake
. Due to non trivial dependencies (python-wxgtk, …), installing it within the Sage distribution is unpractical. Hence, we recommend installing it with the system wide Python. On Ubuntu 10.10, this can be done with:> sudo apt-get install python-profiler python-wxgtk2.8 python-setuptools > sudo easy_install RunSnakeRun
See the
runsnake
website for instructions for other platforms.runsnake()
further assumes that the system wide Python is installed in/usr/bin/python
.See also
%prun