Ticket #11287: trac_11287-runsnake-nt.patch

File trac_11287-runsnake-nt.patch, 11.9 KB (added by nthiery, 11 years ago)
  • doc/en/reference/misc.rst

    # HG changeset patch
    # User Nicolas M. Thiery <nthiery@users.sf.net>
    # Date 1306923828 -10800
    # Node ID 6889efdf6ac5a8afaf37f204ecf93c6d90fcbafa
    # Parent  28cfb99720c7c07e46cf9409a066ce50d38ffde7
    #11287: Interface to runsnake and import_statements
    
    diff --git a/doc/en/reference/misc.rst b/doc/en/reference/misc.rst
    a b Miscellaneous 
    99   sage/misc/abstract_method
    1010   sage/misc/cachefunc
    1111   sage/misc/classgraph
     12   sage/misc/dev_tools
     13   sage/misc/profiler
    1214   sage/misc/function_mangling
    1315   sage/misc/exceptions
    1416   sage/misc/misc
  • sage/misc/all.py

    diff --git a/sage/misc/all.py b/sage/misc/all.py
    a b from misc import (alarm, ellipsis_range, 
    1111
    1212from misc_c import prod, running_total, balanced_sum
    1313
     14from dev_tools import runsnake, import_statements
     15
    1416from html import html
    1517
    1618from sage_timeit_class import timeit
  • new file sage/misc/dev_tools.py

    diff --git a/sage/misc/dev_tools.py b/sage/misc/dev_tools.py
    new file mode 100644
    - +  
     1r"""
     2Some tools for developers
     3"""
     4#*****************************************************************************
     5#  Copyright (C) 2011 Nicolas M. Thiery <nthiery at users.sf.net>
     6#
     7#  Distributed under the terms of the GNU General Public License (GPL)
     8#                  http://www.gnu.org/licenses/
     9#******************************************************************************
     10
     11def runsnake(command):
     12    """
     13    Graphical profiling with ``runsnake``
     14
     15    INPUT:
     16
     17    - ``command`` -- the command to be run as a string.
     18
     19    EXAMPLES::
     20
     21        sage: runsnake("list(SymmetricGroup(3))")        # optional - requires runsnake
     22
     23    ``command`` is first preparsed (see :func:`preparse`)::
     24
     25        sage: runsnake('for x in range(1,4): print x^2') # optional - requires runsnake
     26        1
     27        4
     28        9
     29
     30    :func:`runsnake` requires the program ``runsnake``. Due to non
     31    trivial dependencies (python-wxgtk, ...), installing it within the
     32    Sage distribution is unpractical. Hence, we recommend installing
     33    it with the system wide Python. On Ubuntu 10.10, this can be done
     34    with::
     35
     36        > sudo apt-get install python-profiler python-wxgtk2.8 python-setuptools
     37        > sudo easy_install RunSnakeRun
     38
     39    See the ``runsnake`` website for instructions for other platforms.
     40
     41    :func:`runsnake` further assumes that the system wide Python is
     42    installed in ``/usr/bin/python``.
     43
     44    .. seealso::
     45
     46        - `The runsnake website <http://www.vrplumber.com/programming/runsnakerun/>`_
     47        - ``%prun``
     48        - :class:`Profiler`
     49
     50    """
     51    import cProfile, os
     52    from sage.misc.misc import tmp_filename, get_main_globals
     53    from sage.misc.preparser import preparse
     54    tmpfile = tmp_filename()
     55    cProfile.runctx(preparse(command.lstrip().rstrip()), get_main_globals(), locals(), filename=tmpfile)
     56    os.system("/usr/bin/python -E `which runsnake` %s &"%tmpfile)
     57
     58def import_statements(*objects, **options):
     59    """
     60    Display import statements for the given objects
     61
     62    INPUT:
     63
     64    - ``*objects`` -- a sequence of objects
     65    - ``lazy`` -- a boolean (default: True)
     66
     67    EXAMPLES::
     68
     69        sage: import_statements(WeylGroup, lazy_attribute)
     70        from sage.combinat.root_system.weyl_group import WeylGroup
     71        from sage.misc.lazy_attribute import lazy_attribute
     72
     73    If ``lazy`` is True, then :func:`lazy_import` statements are
     74    displayed instead::
     75
     76        sage: import_statements(WeylGroup, lazy_attribute, lazy=True)
     77        from sage.misc.lazy_import import lazy_import
     78        lazy_import('sage.combinat.root_system.weyl_group', 'WeylGroup')
     79        lazy_import('sage.misc.lazy_attribute', 'lazy_attribute')
     80
     81    .. todo::
     82
     83        This is not correct::
     84
     85            sage: import_statements(ZZ)
     86            from sage.categories.euclidean_domains import EuclideanDomains.parent_class
     87
     88        This should be::
     89
     90            sage: import_statements(ZZ)      # todo: not implemented
     91            from sage.rings.integer_ring import ZZ
     92    """
     93    lazy = "lazy" in options and options["lazy"]
     94    if lazy:
     95        print "from sage.misc.lazy_import import lazy_import"
     96    for obj in objects:
     97        if hasattr(obj, '__name__'):
     98            name = obj.__name__
     99        else:
     100            name = obj
     101        if lazy:
     102            print "lazy_import('%s', '%s')"%(obj.__module__, name)
     103        else:
     104            print "from %s import %s"%(obj.__module__, name)
     105
  • sage/misc/misc.py

    diff --git a/sage/misc/misc.py b/sage/misc/misc.py
    a b def is_in_string(line, pos): 
    24052405    return in_quote()
    24062406
    24072407
     2408def get_main_globals():
     2409    """
     2410    Return the main global namespace
     2411
     2412    EXAMPLES::
     2413
     2414        sage: from sage.misc.misc import get_main_globals
     2415        sage: G = get_main_globals()
     2416        sage: bla = 1
     2417        sage: G['bla']
     2418        1
     2419        sage: bla = 2
     2420        sage: G['bla']
     2421        2
     2422        sage: G['ble'] = 5
     2423        sage: ble
     2424        5
     2425
     2426    This is analogous to :func:`globals`, except that it can be called
     2427    from any function, even if it is in a Python module::
     2428
     2429        sage: def f():
     2430        ...       G = get_main_globals()
     2431        ...       assert G['bli'] == 14
     2432        ...       G['blo'] = 42
     2433        sage: bli = 14
     2434        sage: f()
     2435        sage: blo
     2436        42
     2437
     2438    ALGORITHM:
     2439
     2440    The main global namespace is discovered by going up the frame
     2441    stack until the frame for the :mod:`__main__` module is found.
     2442    Should this frame not be found (this should not occur in normal
     2443    operation), an exception "ValueError: call stack is not deep
     2444    enough" will be raised by ``_getframe``.
     2445
     2446    See :meth:`inject_variable_test` for a real test that this works
     2447    within deeply nested calls in a function defined in a Python
     2448    module.
     2449    """
     2450    import sys
     2451    depth = 0
     2452    while True:
     2453        G = sys._getframe(depth).f_globals
     2454        if G["__name__"] == "__main__" and G["__package__"] is None:
     2455            break
     2456        depth += 1
     2457    return G
     2458
     2459
    24082460def inject_variable(name, value):
    24092461    """
    24102462    inject a variable into the main global namespace
    def inject_variable(name, value): 
    24402492    Use with care!
    24412493    """
    24422494    assert type(name) is str
    2443     import sys
    24442495    # Using globals() does not work, even in Cython, because
    2445     # inject_variable is to be called not only from the interpreter,
    2446     # but also from functions in various modules
    2447     #
    2448     # This instead looks up the main global namespace by going up the
    2449     # frame stack until it finds the frame for the __main__ module.
    2450     #
    2451     # If for some reason this frame is not found (this should not
    2452     # occur in normal operation), an exception "ValueError: call stack
    2453     # is not deep enough" will be raised by _getframe.
    2454     depth = 0
    2455     while True:
    2456         G = sys._getframe(depth).f_globals
    2457         if G["__name__"] == "__main__" and G["__package__"] is None:
    2458             break
    2459         depth += 1
     2496    # inject_variable is called not only from the interpreter, but
     2497    # also from functions in various modules.
     2498    G = get_main_globals()
    24602499    if name in G:
    24612500        warn("redefining global value `%s`"%name, RuntimeWarning, stacklevel = 2)
    24622501    G[name] = value
  • sage/misc/profiler.py

    diff --git a/sage/misc/profiler.py b/sage/misc/profiler.py
    a b  
    1 r""" Simple profiling tool.
     1r"""
     2Simple profiling tool
    23
    3 AUTHOR:
    4     -- David Harvey (August 2006)
    5     -- Martin Albrecht
     4AUTHORS:
     5
     6- David Harvey (August 2006)
     7- Martin Albrecht
    68"""
    79
    810#*****************************************************************************
    import sys 
    1921
    2022
    2123class Profiler:
    22     """
     24    r"""
    2325    Keeps track of CPU time used between a series of user-defined checkpoints.
    2426
    2527    It's probably not a good idea to use this class in an inner loop :-)
    2628
    27     EXAMPLE:
    28         sage: def f():                 # not tested
    29         ...      p = Profiler()        # not tested
     29    EXAMPLE::
    3030
    31         Calling p(message) creates a checkpoint:
    32         sage:    p("try factoring 15")        # not tested
     31        sage: def f():                        # not tested
     32        ...       p = Profiler()              # not tested
    3333
    34         Do something time-consuming:
    35         sage:    x = factor(15)               # not tested
     34    Calling ``p(message)`` creates a checkpoint::
    3635
    37         You can create a checkpoints without a string; the Profiler
    38         will use the source code instead:
    39         sage:    p()                          # not tested
    40    
    41         sage:    y = factor(25)               # not tested
    42         sage:    p("last step")               # not tested
    43         sage:    z = factor(35)               # not tested
    44         sage:    p()                          # not tested
     36        sage: p("try factoring 15")           # not tested
    4537
    46         This will give a nice list of timings between checkpoints:
    47         sage:    print p                      # not tested
     38    Do something time-consuming::
    4839
    49         Let's try it out:
    50         sage: f()                            # not tested
     40        sage: x = factor(15)                  # not tested
     41
     42    You can create a checkpoints without a string; ``Profiler``
     43    will use the source code instead::
     44
     45        sage: p()                             # not tested
     46        sage: y = factor(25)                  # not tested
     47        sage: p("last step")                  # not tested
     48        sage: z = factor(35)                  # not tested
     49        sage: p()                             # not tested
     50
     51    This will give a nice list of timings between checkpoints::
     52
     53        sage: print p                         # not tested
     54
     55    Let's try it out::
     56
     57        sage: f()                             # not tested
    5158            3.020s -- try factoring 15
    5259           15.240s -- line 17: y = factor(25)
    53          5000.190s -- last step 
    54        
    55     TODO:
    56         -- Add Pyrex source code inspection (I assume it doesn't
    57            currently do this)
    58         -- Add ability to sort output by time
    59         -- Add option to constructor to print timing immediately when
    60            checkpoint is reached
    61         -- Migrate to Pyrex?
    62         -- Add ability to return timings in a more machine-friendly
    63            format
     60         5000.190s -- last step
     61
     62    .. seealso:: :func:`runsnake`
     63
     64    .. todo::
     65
     66        - Add Pyrex source code inspection (I assume it doesn't
     67          currently do this)
     68        - Add ability to sort output by time
     69        - Add option to constructor to print timing immediately when
     70          checkpoint is reached
     71        - Migrate to Pyrex?
     72        - Add ability to return timings in a more machine-friendly
     73          format
    6474
    6575    AUTHOR:
    66         -- David Harvey (August 2006)
     76
     77    - David Harvey (August 2006)
    6778    """
    6879
    6980    def __init__(self, systems=[], verbose=False):
    class Profiler: 
    7788        self._cputime_functions = [cputime] + list(systems)
    7889        self._verbose = bool(verbose)
    7990        self.clear()
    80        
     91
    8192    def clear(self):
    8293        # _checkpoints is list of pairs (details, time), where time is a float
    8394        # and details is a triple (line_number, context, message)
    class Profiler: 
    8899    def __call__(self, message=None):
    89100        """ Adds a checkpoint. """
    90101        entry_times = [fn() for fn in self._cputime_functions ]
    91        
     102
    92103        frame = inspect.currentframe().f_back
    93104        try:
    94105            frame_info = inspect.getframeinfo(frame, 9)
  • sage/misc/sage_timeit_class.pyx

    diff --git a/sage/misc/sage_timeit_class.pyx b/sage/misc/sage_timeit_class.pyx
    a b class SageTimeit: 
    2929    The input can contain newlines:
    3030        sage: timeit("a = 2\nb=131\nfactor(a^b-1)", number=25)
    3131        25 loops, best of 3: ... per loop
     32
     33    .. seealso:: :func:`runsnake`
    3234    """
    3335    def eval(self, code, globs=None, locals=None, **kwds):
    3436        r"""