nose: builtin plugin: prof

Use the profile plugin with --with-profile or NOSE_WITH_PROFILE to enable profiling using the hotshot profiler. Profiler output can be controlled with the --profile-sort and --profile-restrict, and the profiler output file may be changed with --profile-stats-file.

See the hotshot documentation in the standard library documentation for more details on the various output options.

Plugin Methods Implemented

This plugin implements the following plugin interface methods:

Commandline Options

This plugin adds the following commandline options:

options:
  --with-profile        Enable plugin Profile:  Use this plugin to run tests
                        using the hotshot profiler.   [NOSE_WITH_PROFILE]
  --profile-sort=PROFILE_SORT
                        Set sort order for profiler output
  --profile-stats-file=PROFILE_STATS_FILE
                        Profiler stats file; default is a new temp file on
                        each run
  --profile-restrict=PROFILE_RESTRICT
                        Restrict profiler output. See help for pstats.Stats
                        for details

Source

"""Use the profile plugin with --with-profile or NOSE_WITH_PROFILE to
enable profiling using the hotshot profiler. Profiler output can be
controlled with the --profile-sort and --profile-restrict, and the
profiler output file may be changed with --profile-stats-file.

See the hotshot documentation in the standard library documentation for
more details on the various output options.
"""

import hotshot, hotshot.stats
import logging
import os
import sys
import tempfile
from nose.plugins.base import Plugin
from nose.util import tolist

log = logging.getLogger('nose.plugins')

class Profile(Plugin):
    """
    Use this plugin to run tests using the hotshot profiler. 
    """
    pfile = None
    clean_stats_file = False
    def options(self, parser, env=os.environ):
        Plugin.options(self, parser, env)                
        parser.add_option('--profile-sort', action='store', dest='profile_sort',
                          default=env.get('NOSE_PROFILE_SORT', 'cumulative'),
                          help="Set sort order for profiler output")
        parser.add_option('--profile-stats-file', action='store',
                          dest='profile_stats_file',
                          default=env.get('NOSE_PROFILE_STATS_FILE'),
                          help='Profiler stats file; default is a new '
                          'temp file on each run')
        parser.add_option('--profile-restrict', action='append',
                          dest='profile_restrict',
                          default=env.get('NOSE_PROFILE_RESTRICT'),
                          help="Restrict profiler output. See help for "
                          "pstats.Stats for details")
    
    def begin(self):
        self._create_pfile()
        self.prof = hotshot.Profile(self.pfile)

    def configure(self, options, conf):
        Plugin.configure(self, options, conf)
        self.options = options
        self.conf = conf

        if options.profile_stats_file:
            self.pfile = options.profile_stats_file
            self.clean_stats_file = False
        else:
            self.pfile = None
            self.clean_stats_file = True
        self.fileno = None
        self.sort = options.profile_sort
        self.restrict = tolist(options.profile_restrict)
            
    def prepareTest(self, test):
        log.debug('preparing test %s' % test)
        def run_and_profile(result, prof=self.prof, test=test):
            self._create_pfile()
            prof.runcall(test, result)
        return run_and_profile
        
    def report(self, stream):
        log.debug('printing profiler report')
        self.prof.close()
        stats = hotshot.stats.load(self.pfile)
        stats.sort_stats(self.sort)

        # 2.5 has completely different stream handling from 2.4 and earlier.
        # Before 2.5, stats objects have no stream attribute; in 2.5 and later
        # a reference sys.stdout is stored before we can tweak it.
        compat_25 = hasattr(stats, 'stream')
        if compat_25:
            tmp = stats.stream
            stats.stream = stream
        else:
            tmp = sys.stdout
            sys.stdout = stream
        try:
            if self.restrict:
                log.debug('setting profiler restriction to %s', self.restrict)
                stats.print_stats(*self.restrict)
            else:
                stats.print_stats()
        finally:
            if compat_25:
                stats.stream = tmp
            else:
                sys.stdout = tmp

    def finalize(self, result):
        try:
            self.prof.close()
        except AttributeError:
            pass
        if self.clean_stats_file:
            if self.fileno:
                try:
                    os.close(self.fileno)
                except OSError:
                    pass
            try:
                os.unlink(self.pfile)
            except OSError:
                pass
        return None

    def _create_pfile(self):
        if not self.pfile:
            self.fileno, self.pfile = tempfile.mkstemp()
            self.clean_stats_file = True