def test_begin_twice():
    transaction = Transaction(Collection([]))
    transaction.begin()
    raises(TransactionAlreadyActiveError, transaction.begin)

    # no exception raised if transaction is already finished
    transaction.rollback()
    transaction.begin()
def test_commit_group():
    ref_collection = Collection([(1,2),(1,3),(2,4)])

    # index-based grouping
    col = ref_collection.factory(ref_collection)
    transaction = Transaction(col)
    transaction._commit_group([0])
    assert len(col) == 2
    assert set(col[0].children) < set(ref_collection)

    # aka
    col2 = ref_collection.factory(ref_collection)
    col2.transaction.add('group', 0)
    assert set(col2) == set(col)

    # fn based grouping
    col = ref_collection.factory(ref_collection)
    transaction = Transaction(col)
    transaction._commit_group([lambda x: x[1]])
    assert len(col) == 3
    assert set(col[0].children) < set(ref_collection)

    # aka
    col2 = ref_collection.factory(ref_collection)
    col2.transaction.add('group', lambda x: x[1])
    assert set(col2) == set(col)
Example #3
0
    def __init__(self, data, **kwargs):
        self.data = [list(x) for x in data]
        self.width = 0 if not self.data else len(self.data[0])
        self.transaction = Transaction(self)

        # State vars
        self._child_collections = {}

        # Add filters
        def _common_kwarg_handling():
            if 'filter' in kwargs:
                for filter_fn in kwargs['filter']:
                    self.filter(filter_fn)
            if 'group' in kwargs:
                self.group(kwargs['group'])

        self._handle_kwargs(_common_kwarg_handling, **kwargs)
def test_commit_error():
    transaction = Transaction(Collection([[1]]))

    # test long way
    transaction.begin()
    transaction.add('group', 1) # <- Column "1" doesn't exist.
    raises(DependencyResolutionError, transaction.commit)

    # shorter test (but this does the same thing)
    raises(DependencyResolutionError, transaction.add, 'group', 1)

    # check exception error message
    try:
        transaction.add('group', 1)
    except DependencyResolutionError, e:
        assert str(e) == "[('group', 'list index out of range')]"
def test_commit_filter():
    ref_collection = Collection([(1,2),(2,3),(3,4)])

    # test impossible filter
    col1 = ref_collection.factory(ref_collection)
    t1 = Transaction(col1)
    t1._commit_filter([lambda x: False])
    assert col1.data == []

    # something more reasonable
    col2 = ref_collection.factory(ref_collection)
    t2 = Transaction(col2)
    t2._commit_filter([lambda x: x[0] > 2])
    assert len(col2) == 1
    assert set(col2) < set(ref_collection)
Example #6
0
class Collection(object):
    """Basic data-collection.
    
    Example:
    >>> Collection(((1,2,3), (2,3,4)))
    <Collection 2 rows, 3 columns>
    >>> Collection([])
    <Collection Empty>
    """

    def __init__(self, data, **kwargs):
        self.data = [list(x) for x in data]
        self.width = 0 if not self.data else len(self.data[0])
        self.transaction = Transaction(self)

        # State vars
        self._child_collections = {}

        # Add filters
        def _common_kwarg_handling():
            if 'filter' in kwargs:
                for filter_fn in kwargs['filter']:
                    self.filter(filter_fn)
            if 'group' in kwargs:
                self.group(kwargs['group'])

        self._handle_kwargs(_common_kwarg_handling, **kwargs)


    def __len__(self):
        return len(self.data)


    def __iter__(self):
        for idx, record in enumerate(self.data):
            if idx in self._child_collections:
                children = self._child_collections[idx]
            else:
                children = None
            yield Record(record, children)


    def __getitem__(self, key):
        if key in self._child_collections:
            return Record(self.data[key], self._child_collections[key])
        else:
            return Record(self.data[key])


    def __enter__(self):
        self.transaction.begin()


    def __exit__(self, exc_type, exc_value, traceback):
        if not exc_type:
            self.transaction.commit()
        else:
            self.transaction.rollback()


    def __repr__(self):
        if self.data:
            return ("<Collection %s rows, %s columns>" 
                    % (len(self.data), len(self.data[0])))
        else:
            return "<Collection Empty>"


    def add_formatted_column(self, fmt):
        """Add new column defined by given format string.

        The python format specification is used to create the resulting 
        columns. (http://docs.python.org/library/string.html#formatstrings)

        >>> col = Collection((('a', 'b'), ('c', 'd')))
        >>> col.add_formatted_column('{0}, {1}')
        >>> col[0][2]
        'a, b'
        >>> col[1][2]
        'c, d'
        """
        def _do_format(row, collection):
            return fmt.format(*row)

        self.transaction.add('new_cols', _do_format)


    def add_calculated_column(self, calculation):
        """Add new column whose value is the result of the given calculation."""
        # replace place-holders with dictionary refs
        calculation = calculation.replace('{', 'r[').replace('}', ']')

        # create new function and return
        exec '_do_calc = lambda r, c: ' + calculation
        self.transaction.add('new_cols', _do_calc)


    def factory(self, data):
        """Returns method to generate similar collection instance."""
        return type(self)(data)


    def filter(self, fn):
        """Filter rows that match given function."""
        self.transaction.add('filter', fn)


    def group(self, groupby_list):
        """Group rows with the same values for the given column positions."""
        for groupby in groupby_list:
            self.transaction.add('group', groupby)


    def _handle_kwargs(self, common_kwarg_handling, **kwargs):
        """Handle kwargs passed in on __init__."""
        with self:
            common_kwarg_handling()
            if 'coerce' in kwargs:
                for i in xrange(len(self.data)):
                    for idx, type_ in kwargs['coerce'].iteritems():
                        self.data[i][idx] = type_(self.data[i][idx])
            if 'formatted_columns' in kwargs:
                for col in kwargs['formatted_columns']:
                    self.add_formatted_column(col)
            if 'calculated_columns' in kwargs:
                for col in kwargs['calculated_columns']:
                    self.add_calculated_column(col)