Source code for chat_archive.profiling

# Easy to use offline chat archive.
#
# Author: Peter Odding <peter@peterodding.com>
# Last Change: July 16, 2018
# URL: https://github.com/xolox/python-chat-archive

"""Easy to use Python code profiling support."""

# Import the fastest available profiling module.
try:
    import cProfile as profile
except ImportError:
    import profile

# External dependencies.
from humanfriendly import Timer
from property_manager import PropertyManager, writable_property
from verboselogs import VerboseLogger

# Initialize a logger for this module.
logger = VerboseLogger(__name__)


[docs]class ProfileManager(PropertyManager): """ Base class for easy to use Python code profiling support. This class makes it easy to enable and disable Python code profiling and save the results to a file. You can use it in a :keyword:`with` statement to guarantee that the profile is saved even when your program is interrupted with Control-C, so when your program is too slow and you're wondering why you can just restart the program with profiling enabled, wait for it to get slow, give it a while to collect profile statistics and then interrupt it with Control-C. When :attr:`profile_file` is set the class initializer method will automatically call :func:`enable_profiling()`. """
[docs] def __init__(self, *args, **kw): """ Initialize a :class:`ProfileManager` object. Please refer to the :class:`~property_manager.PropertyManager` documentation for details about the handling of arguments. """ super(ProfileManager, self).__init__(*args, **kw) if self.profile_file: self.enable_profiling()
[docs] def __enter__(self): """Automatically enable code profiling when the :keyword:`with` block starts.""" if self.can_save_profile: self.enable_profiling() return self
[docs] def __exit__(self, exc_type=None, exc_value=None, traceback=None): """Disable code profiling and save the profile statistics when the :keyword:`with` block ends.""" if self.profiling_enabled: self.disable_profiling() if self.can_save_profile: self.save_profile()
@property def can_save_profile(self): """:data:`True` if :func:`save_profile()` is expected to work, :data:`False` otherwise.""" return self.profile_file is not None
[docs] @writable_property def profile_file(self): """The pathname of a file where Python profile statistics should be saved (a string or :data:`None`)."""
[docs] @writable_property def profiler(self): """A :class:`profile.Profile` object (if :attr:`profile_file` is set) or :data:`None`."""
[docs] @writable_property def profiling_enabled(self): """:data:`True` if code profiling is enabled, :data:`False` otherwise."""
[docs] def enable_profiling(self): """Enable Python code profiling.""" if self.profiler is None: logger.verbose("Initializing Python code profiler ..") self.profiler = profile.Profile() if not self.profiling_enabled: logger.info("Enabling Python code profiling ..") self.profiler.enable() self.profiling_enabled = True
[docs] def disable_profiling(self): """Disable Python code profiling.""" if self.profiler is not None and self.profiling_enabled: logger.verbose("Disabling Python code profiling ..") self.profiler.disable() self.profiling_enabled = False
[docs] def save_profile(self, filename=None): """ Save gathered profile statistics to a file. :param filename: The pathname of the profile file (a string or :data:`None`). Defaults to the value of :attr:`profile_file`. :raises: :exc:`~exceptions.ValueError` when profiling was never enabled or `filename` isn't given and :attr:`profile_file` also isn't set. """ filename = filename or self.profile_file if not filename: raise TypeError("Missing 'filename' argument!") elif self.profiler is None: raise ValueError("Code profiling isn't enabled!") timer = Timer() logger.info("Saving profile statistics to %s ..", self.profile_file) if self.profiling_enabled: self.profiler.disable() self.profiling_enabled = False profiling_disabled = True else: profiling_disabled = False self.profiler.dump_stats(self.profile_file) if profiling_disabled: self.profiler.enable() logger.verbose("Took %s to save profile statistics.", timer)