Source code for schrodinger.infra.mmobject

"""
A base class for creation of garbage collected, object-oriented wrappers of
the mmlibs.

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

from schrodinger.infra import mm


[docs]class MmObject: """ An abstraction of the bookkeeping needed to create a garbage collected MM object. To subclass, you must provide: 1. a static initialize() function that calls the necessary mmlib initialize functions. Takes a single argument that is the error handler. 2. a static terminate() function that takes no arguments and calls the mmlib terminate functions for everything initialized in init(). 3. a _delete() instance method that takes no arguments (other than self) and deletes the object via mmlib calls. """
[docs] def __init__(self, handle, manage_handle=True, error_handler=None): """ Initialize an object with an existing MM handle - i.e. one created with direct calls to the mmlibs. By default, the MM resources will be managed by the object. To keep these from being cleaned up on object deletion, set manage_handle=False. """ # Only track integer handles, not other objects. self.handle = int(handle) self.manage_handle = manage_handle # The _instances class dict will keep track of the number of objects # for each handle, so we know when to call mm*delete. This allows a # user to use, for example, x = mmct(1) as a way of gaining access # to a garbage collected mmct handle. if not hasattr(self.__class__, '_instances'): self.__class__._instances = {} # Keep track of instances. self._instances[self.handle] = self._instances.get(self.handle, 0) + 1 if error_handler is None: error_handler = mm.error_handler # Initialize the mmlib for each object to make sure that the # reference count never goes to zero while an object exists. self.initialize(error_handler)
def __index__(self): """ Return the handle of the object so that the object reference can be used in functions that expect an integer handle. """ return self.handle def __del__(self): """ Decrement the reference count. If the handle is being actively managed, call _delete when it the count hits zero. """ try: self._instances[self.handle] -= 1 if self.manage_handle and self._instances[self.handle] == 0: self._delete() self.terminate() except (AttributeError, TypeError): # Look for an AttributeError in case the subclass failed before # calling MmObject.__init__(). In this case, just skip the # cleanup. # TypeError occurs with TypeError("'NoneType' object is not callable",) # while the object is deleted pass