Source code for schrodinger.infra.mminit

"""
Assist in initialization and termination of mmlibs.

"""
# Copyright Schrodinger, LLC. All rights reserved.

import contextlib
import functools

from schrodinger.infra import mm


[docs]class Initializer: """ A class to handle initialization and termination of needed mmlibs. It is designed to be created on import and initialize needed mmlibs for a module. In general, automatic termination is not supported, but terminate method can be called manually. """
[docs] def __init__(self, initializers, terminators): self.initializers = initializers self.terminators = terminators self.error_handler = None self.init_count = 0 self.initialize()
[docs] def initialize(self, error_handler=None): """ Initialize all needed mmlibs. """ if error_handler is None: error_handler = mm.error_handler # Keep track of the error handler used to initialize. self.error_handler = error_handler for init in self.initializers: init(error_handler) self.init_count += 1
[docs] def terminate(self): """ Terminate all previously initialized mmlibs. """ for term in self.terminators: term() self.init_count -= 1
def __copy__(self): # This implementation just returns 'self', effectively preventing # copying. Each Initializer instance should be a singleton providing # for initialization and termination of its set of mmlibs. # # I can't think of a reason to need an actual copy, but if a need # arises, be sure that init_count in the new instance is reset to # zero. return self def __deepcopy__(self, memo=None): # Prevent copying. See discussion in __copy__. return self
class _mmlib_new_delete: """ Use new and delete as context manager pairs. Useful if new returns an `int`, which of course has no knowledge of the underlying object's lifetime. """ def __init__(self, new, delete): self._new = new self._delete = delete def new(self, *args): v = self._new(*args) @contextlib.contextmanager def scope(): try: yield v finally: self._delete(v) return scope()
[docs]@contextlib.contextmanager def MMLib(init, term, new=None, delete=None): """ Decorator and context manager to control initialization of a single library. """ init(mm.error_handler) try: obj = None if new and delete: obj = _mmlib_new_delete(new, delete) elif new or delete: raise ValueError( 'Please provide both `new` and `delete`, or neither.') yield obj finally: term()
# Make life easier by canning definitions for specific mmlibs: # # Use like:: # # with mminit.mmfrag() as mmfrag: # with mmfrag.new() as h: # # do stuff with `h` # mmct = functools.partial(MMLib, mm.mmct_initialize, mm.mmct_terminate) mmfrag = functools.partial(MMLib, mm.mmfrag_initialize, mm.mmfrag_terminate, mm.mmfrag_new, mm.mmfrag_delete)