def create_table(self):
     cli, sess = self.create_client()
     ftc = FeatureTableConnection(client=cli, tableName=self.tableName)
     desc = [('a', 3), ('b', 1)]
     ftc.createNewTable('ID', desc)
     tid = ftc.tableId
     ftc.close()
     return tid
    def test_getHeaders(self):
        tid = self.create_table()
        ftc = FeatureTableConnection(client=self.cli, tableName=self.tableName)
        ftc.openTable(tid)

        headers = ftc.getHeaders()
        self.assertEqual(len(headers), 3)
        self.assertEqual([h.name for h in headers], ['ID', 'a', 'b'])
    def test_readSubArray_ordered(self):
        tid = self.create_table_with_data()
        ftc = FeatureTableConnection(client=self.cli, tableName=self.tableName)
        ftc.openTable(tid)

        can = collections.OrderedDict([(2, [0]), (1, [0,2])])
        xs = ftc.readSubArray(can, 0, 4)
        self.assertEqual(xs[1].values, [[], [1., 3.], [4., 6.], []])
        self.assertEqual(xs[0].values, [[7.], [], [8.], []])
    def test_readSubArray(self):
        tid = self.create_table_with_data()
        ftc = FeatureTableConnection(client=self.cli, tableName=self.tableName)
        ftc.openTable(tid)

        can = {1:[0,2], 2:[0]}
        xs = ftc.readSubArray(can, 0, 4)
        self.assertEqual(xs[0].values, [[], [1., 3.], [4., 6.], []])
        self.assertEqual(xs[1].values, [[7.], [], [8.], []])
    def test_isValid(self):
        tid = self.create_table_with_data()
        ftc = FeatureTableConnection(client=self.cli, tableName=self.tableName)
        ftc.openTable(tid)
        bs = ftc.isValid([2, 0, 1], 0, 4)

        self.assertEqual(bs[1].values, [True, True, True, True])
        self.assertEqual(bs[2].values, [False, True, True, False])
        self.assertEqual(bs[0].values, [True, False, True, False])
    def test_createNewTable(self):
        tid = self.create_table()
        ftc = FeatureTableConnection(client=self.cli, tableName=self.tableName)
        ftc.openTable(tid)

        headers = ftc.table.getHeaders()
        self.assertEqual(len(headers), 6)
        self.assertEqual([h.name for h in headers[:3]], ['ID', 'a', 'b'])
        self.assertEqual([h.name for h in headers[3:]],
                         ['_b_ID', '_b_a', '_b_b'])
    def test_addPartialData(self):
        tid = self.create_table_with_data()
        ftc = FeatureTableConnection(client=self.cli, tableName=self.tableName)
        ftc.openTable(tid)

        cols = ftc.getHeaders()
        cols = [cols[2], cols[0]]
        cols[1].values = [2, 4]
        cols[0].values = [[], [18.]]
        ftc.addPartialData(cols)

        xs = ftc.readArray(range(len(ftc.getHeaders())), 0,
                           ftc.getNumberOfRows(), chunk=4)
        self.assertEqual(xs[0].values, [1, 8, 3, 6, 2, 4])
        self.assertEqual(xs[1].values, [[], [1., 2., 3.], [4., 5., 6.], [],
                                        [], []])
        self.assertEqual(xs[2].values, [[7.], [], [8.], [], [], [18.]])
    def create_table_with_data(self):
        cli, sess = self.create_client()
        ftc = FeatureTableConnection(client=cli, tableName=self.tableName)
        desc = [('a', 3), ('b', 1)]
        ftc.createNewTable('ID', desc)

        cols = ftc.getHeaders()
        cols[0].values = [1, 8, 3, 6]
        cols[1].values = [[], [1., 2., 3.], [4., 5., 6.], []]
        cols[2].values = [[7.], [], [8.], []]
        ftc.addData(cols)

        tid = ftc.tableId
        ftc.close()
        return tid
    def test_getRowId(self):
        tid = self.create_table_with_data()
        ftc = FeatureTableConnection(client=self.cli, tableName=self.tableName)
        ftc.openTable(tid)

        self.assertEqual(ftc.getRowId(1), 0)
        self.assertEqual(ftc.getRowId(3), 2)
        self.assertEqual(ftc.getRowId(6), 3)
        self.assertEqual(ftc.getRowId(8), 1)
        self.assertIsNone(ftc.getRowId(1000))
    def test_readArray(self):
        tid = self.create_table_with_data()
        ftc = FeatureTableConnection(client=self.cli, tableName=self.tableName)
        ftc.openTable(tid)

        xs = ftc.readArray([0, 2], 0, 3, chunk=2)
        self.assertEqual(xs[0].values, [1, 8, 3])
        self.assertEqual(xs[1].values, [[7.], [], [8.]])

        xs = ftc.readArray([2, 0, 1], 0,
                           ftc.getNumberOfRows(), chunk=3)
        self.assertEqual(xs[1].values, [1, 8, 3, 6])
        self.assertEqual(xs[2].values, [[], [1., 2., 3.], [4., 5., 6.], []])
        self.assertEqual(xs[0].values, [[7.], [], [8.], []])
 def __init__(self, client, tableName):
     self.tc = FeatureTableConnection(client=client, tableName=tableName)
     self.versiontag = None
class FeatureTable(object):
    def __init__(self, client, tableName):
        self.tc = FeatureTableConnection(client=client, tableName=tableName)
        self.versiontag = None

    def close(self):
        self.tc.close(False)

    @property
    def conn(self):
        return self.tc.conn


    def createTable(self, featureNames, version):
        """
        Initialise an OMERO.table for storing features
        @param featureNames Either a mapping of feature names to feature sizes,
        or a list of single value feature names which can be parsed using
        parseFeatureName
        """
        # Unparsed list or dict?
        if hasattr(featureNames, 'keys'):
            features = featureNames
        else:
            features = featureSizes(featureNames)

        colNames = sorted(features.keys())
        desc = [(name, features[name]) for name in colNames]
        self.tc.createNewTable('id', desc)

        self.versiontag = getVersionAnnotation(self.conn, version)
        if not self.versiontag:
            self.versiontag = createVersionAnnotation(self.conn, version)
        addTagTo(self.conn, self.versiontag, 'OriginalFile', self.tc.tableId)

        # TODO: There's a bug or race condition somewhere which means this
        # annotation may be lost. Closing and reopening the table seems to
        # avoid this.
        tid = self.tc.tableId
        self.close()
        self.openTable(tid, version)

    def openTable(self, tableId, version=None):
        try:
            vertag = getVersion(self.conn, 'OriginalFile', tableId)
            if not vertag:
                raise WndcharmStorageError(
                    'Table id %d has no version tag' % tableId)
            if version is not None:
                assertVersionMatch(version, vertag, 'table:%d' % tableId)
            self.tc.openTable(tableId)
            self.versiontag = vertag
            return True
        except TableConnectionError as e:
            print "No table found: %s" % e
            return False


    def isTableCompatible(self, features):
        """
        Check whether an existing table is compatible with this set of features,
        that is whether suitable columns exist
        @return true if this set of features can be stored in this table
        """
        cols = self.tc.getHeaders()
        colMap = dict([(c.name, c) for c in cols])
        featSizes = featureSizes(features.names)

        for (ft, sz) in featSizes.iteritems():
            if (ft not in colMap or colMap[ft].size != sz):
                print '%s [%d] is incompatible' %  (ft, sz)
                return False
        return True


    def tableContainsId(self, id):
        """
        Check whether this ID is already present in the table
        """
        return self.tc.getRowId(id) is not None


    def saveFeatures(self, id, features):
        """
        Save the features to a table
        @param features an object with field names holding a list of single
        value feature names, and values holding a list of doubles corresponding
        to names
        """
        cols = self.tc.getHeaders()
        colMap = dict([(c.name, c) for c in cols])
        cols[0].values = [id]

        for (name, value) in izip(features.names, features.values):
            ft, idx = parseFeatureName(name)
            col = colMap[ft]
            if not col.values:
                col.values = [[float('nan')] * col.size]
            col.values[0][idx] = value

        self.tc.addData(cols)


    def loadFeatures(self, id):
        """
        Load features for an object from a table
        @return a (names, values) tuple where names is a list of single value
        features and value are the corresponding feature values
        """
        r = self.tc.getRowId(id)
        # Skip the first id column
        colNumbers = range(1, len(self.tc.getHeaders()))
        cols = self.tc.readArray(colNumbers, r, r + 1)
        names = []
        values = []
        for col in cols:
            names.extend([createFeatureName(col.name, x)
                          for x in xrange(col.size)])
            values.extend(col.values[0])

        return (names, values)


    def bulkLoadFeatures(self):
        """
        Load features for all objects in a table
        @return a (names, values, ids) tuple where names is a list of single
        value features, values is a list of lists of the corresponding feature
        values and ids is a list of object IDs.
        In other words values[i] is the list of feature values corresponding to
        object with ID given by ids[i].
        """
        colNumbers = range(len(self.tc.getHeaders()))
        nr = self.tc.getNumberOfRows()
        cols = self.tc.readArray(colNumbers, 0, nr, CHUNK_SIZE)
        names = []
        ids = cols[0].values

        for col in cols[1:]:
            names.extend([createFeatureName(col.name, x) for x in xrange(col.size)])
            values = map(lambda *args: list(chain.from_iterable(args)),
                         *[c.values for c in cols[1:]])

        return (names, values, ids)