예제 #1
0
    def testChecksumAfterSaveRestore(self):
        """
        A backend that has a sequence added to it, which is then saved and
        restored, and then has a second sequence is added to it must have the
        same checksum as a backend that simply has the two sequences added to
        it without interruption.
        """
        seq1 = 'FRRRFRRRFASAASA'
        seq2 = 'MMMMMMMMMFRRRFR'
        dbParams1 = DatabaseParameters(landmarks=[AlphaHelix, BetaStrand],
                                       trigPoints=[Peaks, Troughs])
        be1 = Backend()
        be1.configure(dbParams1, 'name1', 0)
        be1.addSubject(AARead('id1', seq1), '0')
        fp = StringIO()
        be1.save(fp)
        fp.seek(0)
        be1 = Backend.restore(fp)
        be1.addSubject(AARead('id2', seq2), '1')

        dbParams2 = DatabaseParameters(landmarks=[AlphaHelix, BetaStrand],
                                       trigPoints=[Peaks, Troughs])
        be2 = Backend()
        be2.configure(dbParams2, 'name2', 0)
        be2.addSubject(AARead('id1', seq1), '0')
        be2.addSubject(AARead('id2', seq2), '1')

        self.assertEqual(be1.checksum(), be2.checksum())
예제 #2
0
    def testSaveContentIncludesExpectedKeysAndValues(self):
        """
        When a backend saves, its JSON content must include the expected
        keys and values.
        """
        dbParams = DatabaseParameters(landmarks=[], trigPoints=[],
                                      limitPerLandmark=16, maxDistance=17,
                                      minDistance=18, distanceBase=19.0)
        be = Backend()
        be.configure(dbParams, 'backend', 33)
        fp = StringIO()
        be.save(fp)
        fp.seek(0)

        DatabaseParameters.restore(fp)
        SubjectStore.restore(fp)
        state = loads(fp.readline()[:-1])

        # Keys
        self.assertEqual(
            set(['checksum', 'd', 'name', '_totalCoveredResidues']),
            set(state.keys()))

        # Values
        self.assertEqual(be.checksum(), state['checksum'])
        self.assertEqual({}, state['d'])
        self.assertEqual('backend', state['name'])
        self.assertEqual(0, state['_totalCoveredResidues'])
예제 #3
0
 def testSaveRestoreWithNonDefaultParameters(self):
     """
     When asked to save and then restore a backend with non-default
     parameters, a backend with the correct parameters must result.
     """
     dbParams = DatabaseParameters(landmarks=[], trigPoints=[],
                                   limitPerLandmark=16, maxDistance=17,
                                   minDistance=18, distanceBase=19.0)
     be = Backend()
     be.configure(dbParams)
     fp = StringIO()
     be.save(fp)
     fp.seek(0)
     result = be.restore(fp)
     self.assertIs(None, dbParams.compare(result.dbParams))
예제 #4
0
 def testSaveRestoreNonEmpty(self):
     """
     When asked to save and then restore a non-empty backend, the correct
     backend must result.
     """
     dbParams = DatabaseParameters(landmarks=[AlphaHelix, BetaStrand],
                                   trigPoints=[Peaks, Troughs])
     be = Backend()
     be.configure(dbParams)
     be.addSubject(AARead('id', 'FRRRFRRRFASAASA'), '0')
     fp = StringIO()
     be.save(fp)
     fp.seek(0)
     result = Backend.restore(fp)
     self.assertEqual(be.subjectCount(), result.subjectCount())
     self.assertEqual(be.d, result.d)
     self.assertEqual(be.checksum(), result.checksum())
     self.assertIs(None, be.dbParams.compare(result.dbParams))
예제 #5
0
class SimpleConnector(object):
    """
    Provide a simple in-memory connection between a Database and a single
    Backend.

    @param dbParams: A C{DatabaseParameters} instance.
    @param backend: A C{Backend} instance, or C{None} if a backend should be
        created.
    @param filePrefix: Either a C{str} file name prefix to use as a default
        when saving or C{None} if no default save file is needed.
    """

    SAVE_SUFFIX = '.lmco'

    def __init__(self, dbParams, backend=None, filePrefix=None):
        self.dbParams = dbParams
        if backend:
            self._backend = backend
        else:
            self._backend = Backend(filePrefix=filePrefix)
            self._backend.configure(dbParams)
        self._filePrefix = filePrefix

        # Most of our implementation comes directly from our backend.
        for method in ('addSubject', 'getIndexBySubject', 'getSubjectByIndex',
                       'getSubjects', 'subjectCount', 'hashCount',
                       'totalResidues', 'totalCoveredResidues', 'checksum'):
            setattr(self, method, getattr(self._backend, method))

    def find(self,
             read,
             findParams=None,
             storeFullAnalysis=False,
             subjectIndices=None):
        """
        Check which database sequences a read matches.

        @param read: A C{dark.read.AARead} instance.
        @param findParams: An instance of C{light.parameters.FindParameters} or
            C{None} to use default find parameters.
        @param storeFullAnalysis: A C{bool}. If C{True} the intermediate
            significance analysis computed in the Result will be stored.
        @param subjectIndices: A C{set} of subject indices, or C{None}. If a
            set is passed, only subject indices in the set will be returned
            in the results. If C{None}, all matching subject indices are
            returned.
        @return: A C{light.result.Result} instance.
        """
        matches, hashCount, nonMatchingHashes = self._backend.find(
            read,
            storeFullAnalysis=storeFullAnalysis,
            subjectIndices=subjectIndices)

        return Result(read,
                      self,
                      matches,
                      hashCount,
                      findParams,
                      nonMatchingHashes=nonMatchingHashes,
                      storeFullAnalysis=storeFullAnalysis)

    def shutdown(self, save, filePrefix):
        """
        Shut down the connector.

        @param save: If C{True}, save the connector state.
        @param filePrefix: When saving, use this C{str} as a file name prefix.
        """
        self._backend.shutdown(save, filePrefix)

        if save:
            self.save(filePrefix)

    def save(self, fpOrFilePrefix=None):
        """
        Save state to a file.

        @param fpOrFilePrefix: A file pointer, or the C{str} prefix of a file
            name, or C{None}. If a C{str}, self.SAVE_SUFFIX is appended to get
            the full file name. If C{None}, self._filePrefix will be used as a
            file prefix unless it is also C{None}.
        @raises ValueError: If C{fpOrFilePrefix} and C{self._filePrefix} are
            both C{None}
        """
        if isinstance(fpOrFilePrefix, str):
            saveFile = fpOrFilePrefix + self.SAVE_SUFFIX
        elif fpOrFilePrefix is None:
            if self._filePrefix is None:
                raise ValueError('save must be given an argument (or the '
                                 'database must have been restored from a '
                                 'file).')
            else:
                saveFile = self._filePrefix + self.SAVE_SUFFIX
        else:
            saveFile = fpOrFilePrefix

        with as_handle(saveFile, 'w') as fp:
            self.dbParams.save(fp)

        self._backend.save(fpOrFilePrefix)

    @classmethod
    def restore(cls, fpOrFilePrefix):
        """
        Restore state from a file.

        @param fpOrFilePrefix: A file pointer or the C{str} prefix of a file
            name. If a C{str}, self.SAVE_SUFFIX is appended to get the full
            file name.
        @return: An instance of L{SimpleConnector}.
        @raises ValueError: If valid JSON cannot be loaded from C{fp}.
        """
        if isinstance(fpOrFilePrefix, str):
            saveFile = fpOrFilePrefix + cls.SAVE_SUFFIX
            filePrefix = fpOrFilePrefix
        else:
            saveFile = fpOrFilePrefix
            filePrefix = None

        with as_handle(saveFile) as fp:
            dbParams = DatabaseParameters.restore(fp)

        return cls(dbParams,
                   backend=Backend.restore(fpOrFilePrefix),
                   filePrefix=filePrefix)

    def print_(self, printHashes=False, margin='', result=None):
        """
        Print information about this connector.

        @param printHashes: If C{True}, print all hashes and associated
            subjects from the backend.
        @param margin: A C{str} that should be inserted at the start of each
            line of output.
        @param result: A C{MultilineString} instance, or C{None} if a new
            C{MultilineString} should be created.
        @return: If C{result} was C{None}, return a C{str} representation of
            the connector, else C{None}.
        """
        if result is None:
            result = MultilineString(margin=margin)
            returnNone = False
        else:
            returnNone = True

        if printHashes:
            result.append('Backends:')
            result.indent()
            self._backend.print_(margin=margin, result=result)
            result.outdent()

        if not returnNone:
            return str(result)