Source code for openquake.hazardlib.speedups
# The Hazard Library
# Copyright (C) 2012-2016 GEM Foundation
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
Module :mod:`openquake.hazardlib.speedups` contains internal utilities for
managing alternative implementation of the same functionality depending on
their availability.
"""
import inspect
[docs]class SpeedupsRegistry(object):
"""
Speedups registry allows to manage alternative implementations
of functions. Typical use case for it is something like this:
.. code-block:: python
# in the module namespace
def do_foo(foo, bar):
# code in pure python
...
def do_bar(baz, quux):
# code in pure python
...
# in the end of the module
try:
import _foobar_speedups
except ImportError:
import warnings
warnings.warn("foobar speedups are not available", RuntimeWarning)
else:
from openquake.hazardlib import speedups
def _c_do_foo(foo, bar):
return _foobar_speedups.do_foo(foo, bar)
speedups.register(do_foo, _c_do_foo)
del _c_do_foo
def _c_do_bar(baz, quux):
return _foobar_speedups.do_foo(baz, quux)
speedups.register(do_bar, _c_do_bar)
del _c_do_bar
Global registry is being used here. All speedups are enabled by default.
In order to disable them, use :meth:`disable`.
"""
def __init__(self):
self.enabled = True
self.funcs = {}
[docs] def register(self, func, altfunc):
"""
Add a function and its alternative implementation to the registry.
If registry is enabled, function code will be substituted
by an alternative implementation immediately.
:param func:
A function object to patch.
:param altfunc:
An alternative implementation of the function. Must have
the same signature and is supposed to behave exactly
the same way as ``func``.
"""
assert inspect.getargspec(func) == inspect.getargspec(altfunc), \
"functions signatures are different in %s and %s" % \
(func, altfunc)
self.funcs[func] = (func.__code__, altfunc.__code__)
if self.enabled:
# here we substitute the "func_code" attribute of the function,
# which allows us not to worry of when and how is this function
# being imported by other modules
func.__code__ = altfunc.__code__
[docs] def enable(self):
"""
Set implementation to "alternative" for all the registered functions.
"""
for func in self.funcs:
origcode, altcode = self.funcs[func]
func.__code__ = altcode
self.enabled = True
[docs] def disable(self):
"""
Set implementation to "original" for all the registered functions.
"""
for func in self.funcs:
origcode, altcode = self.funcs[func]
func.__code__ = origcode
self.enabled = False
global_registry = SpeedupsRegistry()
#: Global (default) registry :meth:`register`.
register = global_registry.register
#: Global (default) registry :meth:`enable`.
enable = global_registry.enable
#: Global (default) registry :meth:`disable`.
disable = global_registry.disable