diff --git a/gcloud/datastore/_implicit_environ.py b/gcloud/datastore/_implicit_environ.py index 4427ee1aa07f..88d19c15682a 100644 --- a/gcloud/datastore/_implicit_environ.py +++ b/gcloud/datastore/_implicit_environ.py @@ -2,9 +2,6 @@ Acts as a mutable namespace to allow the datastore package to imply the current dataset and connection from the enviroment. - -Also provides a base class for classes in the `datastore` package -which could utilize the implicit enviroment. """ @@ -16,15 +13,3 @@ CONNECTION = None """Module global to allow persistent implied connection from enviroment.""" - - -class _DatastoreBase(object): - """Base for all classes in the datastore package. - - Uses the implicit DATASET object as a default dataset attached - to the instances being created. Stores the dataset passed in - on the protected (i.e. non-public) attribute `_dataset`. - """ - - def __init__(self, dataset=None): - self._dataset = dataset or DATASET diff --git a/gcloud/datastore/connection.py b/gcloud/datastore/connection.py index a8bc9880a92b..eeacc44ba35c 100644 --- a/gcloud/datastore/connection.py +++ b/gcloud/datastore/connection.py @@ -149,7 +149,7 @@ def mutation(self): (if one exists) or or a new mutation instance. """ if self.transaction(): - return self.transaction().mutation() + return self.transaction().mutation else: return datastore_pb.Mutation() @@ -358,7 +358,7 @@ def commit(self, dataset_id, mutation_pb): if self.transaction(): request.mode = datastore_pb.CommitRequest.TRANSACTIONAL - request.transaction = self.transaction().id() + request.transaction = self.transaction().id else: request.mode = datastore_pb.CommitRequest.NON_TRANSACTIONAL @@ -378,11 +378,11 @@ def rollback(self, dataset_id): :type dataset_id: string :param dataset_id: The dataset to which the transaction belongs. """ - if not self.transaction() or not self.transaction().id(): + if not self.transaction() or not self.transaction().id: raise ValueError('No transaction to rollback.') request = datastore_pb.RollbackRequest() - request.transaction = self.transaction().id() + request.transaction = self.transaction().id # Nothing to do with this response, so just execute the method. self._rpc(dataset_id, 'rollback', request, datastore_pb.RollbackResponse) @@ -549,7 +549,7 @@ def _set_read_options(self, request, eventual): if eventual: opts.read_consistency = datastore_pb.ReadOptions.EVENTUAL elif transaction: - opts.transaction = transaction.id() + opts.transaction = transaction.id def _copy_deferred_keys(lookup_request, lookup_response): diff --git a/gcloud/datastore/test_connection.py b/gcloud/datastore/test_connection.py index bba6371219c3..2224c121f8cd 100644 --- a/gcloud/datastore/test_connection.py +++ b/gcloud/datastore/test_connection.py @@ -203,8 +203,8 @@ class Mutation(object): pass class Xact(object): - def mutation(self): - return Mutation() + mutation = Mutation() + conn = self._makeOne() conn.transaction(Xact()) found = conn.mutation() @@ -765,8 +765,8 @@ def test_commit_w_transaction(self): from gcloud.datastore import datastore_v1_pb2 as datastore_pb class Xact(object): - def id(self): - return 'xact' + id = 'xact' + DATASET_ID = 'DATASET' key_pb = self._make_key_pb(DATASET_ID) rsp_pb = datastore_pb.CommitResponse() @@ -808,9 +808,8 @@ def test_rollback_wo_existing_transaction(self): def test_rollback_w_existing_transaction_no_id(self): class Xact(object): + id = None - def id(self): - return None DATASET_ID = 'DATASET' conn = self._makeOne() conn.transaction(Xact()) @@ -823,9 +822,8 @@ def test_rollback_ok(self): TRANSACTION = 'xact' class Xact(object): + id = TRANSACTION - def id(self): - return TRANSACTION rsp_pb = datastore_pb.RollbackResponse() conn = self._makeOne() conn.transaction(Xact()) @@ -1038,11 +1036,9 @@ def test_save_entity_wo_transaction_w_auto_id(self): def test_save_entity_w_transaction(self): from gcloud.datastore import datastore_v1_pb2 as datastore_pb - mutation = datastore_pb.Mutation() - class Xact(object): - def mutation(self): - return mutation + mutation = datastore_pb.Mutation() + DATASET_ID = 'DATASET' key_pb = self._make_key_pb(DATASET_ID) rsp_pb = datastore_pb.CommitResponse() @@ -1059,11 +1055,9 @@ def test_save_entity_w_transaction_nested_entity(self): from gcloud.datastore import datastore_v1_pb2 as datastore_pb from gcloud.datastore.entity import Entity - mutation = datastore_pb.Mutation() - class Xact(object): - def mutation(self): - return mutation + mutation = datastore_pb.Mutation() + DATASET_ID = 'DATASET' nested = Entity() nested['bar'] = u'Bar' @@ -1114,11 +1108,9 @@ def test_delete_entities_wo_transaction(self): def test_delete_entities_w_transaction(self): from gcloud.datastore import datastore_v1_pb2 as datastore_pb - mutation = datastore_pb.Mutation() - class Xact(object): - def mutation(self): - return mutation + mutation = datastore_pb.Mutation() + DATASET_ID = 'DATASET' key_pb = self._make_key_pb(DATASET_ID) rsp_pb = datastore_pb.CommitResponse() @@ -1162,6 +1154,7 @@ class Transaction(object): def __init__(self, id): self._id = id + @property def id(self): return self._id diff --git a/gcloud/datastore/test_entity.py b/gcloud/datastore/test_entity.py index 62afa4f365fe..4a54ce7198be 100644 --- a/gcloud/datastore/test_entity.py +++ b/gcloud/datastore/test_entity.py @@ -21,11 +21,19 @@ class TestEntity(unittest2.TestCase): - def _getTargetClass(self): + def setUp(self): from gcloud.datastore import _implicit_environ - from gcloud.datastore.entity import Entity + self._replaced_dataset = _implicit_environ.DATASET + self._replaced_dataset_id = _implicit_environ.DATASET_ID + _implicit_environ.DATASET = _implicit_environ.DATASET_ID = None + + def tearDown(self): + from gcloud.datastore import _implicit_environ + _implicit_environ.DATASET = self._replaced_dataset + _implicit_environ.DATASET_ID = self._replaced_dataset_id - _implicit_environ.DATASET = None + def _getTargetClass(self): + from gcloud.datastore.entity import Entity return Entity def _makeOne(self, key=None, exclude_from_indexes=()): diff --git a/gcloud/datastore/test_helpers.py b/gcloud/datastore/test_helpers.py index d3fc0243f21e..5809a427f24d 100644 --- a/gcloud/datastore/test_helpers.py +++ b/gcloud/datastore/test_helpers.py @@ -20,11 +20,13 @@ class Test_entity_from_protobuf(unittest2.TestCase): def setUp(self): from gcloud.datastore import _implicit_environ self._replaced_dataset = _implicit_environ.DATASET - _implicit_environ.DATASET = None + self._replaced_dataset_id = _implicit_environ.DATASET_ID + _implicit_environ.DATASET = _implicit_environ.DATASET_ID = None def tearDown(self): from gcloud.datastore import _implicit_environ _implicit_environ.DATASET = self._replaced_dataset + _implicit_environ.DATASET_ID = self._replaced_dataset_id def _callFUT(self, val): from gcloud.datastore.helpers import entity_from_protobuf diff --git a/gcloud/datastore/test_key.py b/gcloud/datastore/test_key.py index d4c3eceac5f2..beb6fd92ef4a 100644 --- a/gcloud/datastore/test_key.py +++ b/gcloud/datastore/test_key.py @@ -20,6 +20,16 @@ class TestKey(unittest2.TestCase): def setUp(self): self._DEFAULT_DATASET = 'DATASET' + from gcloud.datastore import _implicit_environ + self._replaced_dataset = _implicit_environ.DATASET + self._replaced_dataset_id = _implicit_environ.DATASET_ID + _implicit_environ.DATASET = _implicit_environ.DATASET_ID = None + + def tearDown(self): + from gcloud.datastore import _implicit_environ + _implicit_environ.DATASET = self._replaced_dataset + _implicit_environ.DATASET_ID = self._replaced_dataset_id + def _getTargetClass(self): from gcloud.datastore import _implicit_environ from gcloud.datastore.dataset import Dataset diff --git a/gcloud/datastore/test_transaction.py b/gcloud/datastore/test_transaction.py index b48b51208331..985b6e467cf2 100644 --- a/gcloud/datastore/test_transaction.py +++ b/gcloud/datastore/test_transaction.py @@ -22,72 +22,85 @@ def _getTargetClass(self): return Transaction - def _makeOne(self, dataset=None): - return self._getTargetClass()(dataset) + def _makeOne(self, dataset_id=None, connection=None): + return self._getTargetClass()(dataset_id=dataset_id, + connection=connection) + + def test_ctor_missing_required(self): + from gcloud.datastore import _implicit_environ + + self.assertEqual(_implicit_environ.DATASET, None) + + with self.assertRaises(ValueError): + self._makeOne() + with self.assertRaises(ValueError): + self._makeOne(dataset_id=object()) + with self.assertRaises(ValueError): + self._makeOne(connection=object()) def test_ctor(self): from gcloud.datastore.datastore_v1_pb2 import Mutation _DATASET = 'DATASET' connection = _Connection() - dataset = _Dataset(_DATASET, connection) - xact = self._makeOne(dataset) - self.assertTrue(xact.dataset() is dataset) - self.assertEqual(xact.id(), None) - self.assertTrue(isinstance(xact.mutation(), Mutation)) + xact = self._makeOne(dataset_id=_DATASET, connection=connection) + self.assertEqual(xact.dataset_id, _DATASET) + self.assertEqual(xact.connection, connection) + self.assertEqual(xact.id, None) + self.assertTrue(isinstance(xact.mutation, Mutation)) self.assertEqual(len(xact._auto_id_entities), 0) - self.assertTrue(xact.connection() is connection) def test_ctor_with_env(self): - SENTINEL_VAL = object() - + from gcloud._testing import _Monkey from gcloud.datastore import _implicit_environ - _implicit_environ.DATASET = SENTINEL_VAL - transaction = self._makeOne(dataset=None) - self.assertEqual(transaction.dataset(), SENTINEL_VAL) + DATASET_ID = 'DATASET' + CONNECTION = _Connection() + + with _Monkey(_implicit_environ, DATASET_ID=DATASET_ID, + CONNECTION=CONNECTION): + transaction = self._makeOne() + + self.assertEqual(transaction.dataset_id, DATASET_ID) + self.assertEqual(transaction.connection, CONNECTION) def test_add_auto_id_entity(self): entity = _Entity() _DATASET = 'DATASET' connection = _Connection() - dataset = _Dataset(_DATASET, connection) - xact = self._makeOne(dataset) + xact = self._makeOne(dataset_id=_DATASET, connection=connection) xact.add_auto_id_entity(entity) self.assertEqual(xact._auto_id_entities, [entity]) def test_begin(self): _DATASET = 'DATASET' connection = _Connection(234) - dataset = _Dataset(_DATASET, connection) - xact = self._makeOne(dataset) + xact = self._makeOne(dataset_id=_DATASET, connection=connection) xact.begin() - self.assertEqual(xact.id(), 234) + self.assertEqual(xact.id, 234) self.assertEqual(connection._begun, _DATASET) self.assertTrue(connection._xact is xact) def test_rollback(self): _DATASET = 'DATASET' connection = _Connection(234) - dataset = _Dataset(_DATASET, connection) - xact = self._makeOne(dataset) + xact = self._makeOne(dataset_id=_DATASET, connection=connection) xact.begin() xact.rollback() - self.assertEqual(xact.id(), None) + self.assertEqual(xact.id, None) self.assertEqual(connection._rolled_back, _DATASET) self.assertEqual(connection._xact, None) def test_commit_no_auto_ids(self): _DATASET = 'DATASET' connection = _Connection(234) - dataset = _Dataset(_DATASET, connection) - xact = self._makeOne(dataset) + xact = self._makeOne(dataset_id=_DATASET, connection=connection) xact._mutation = mutation = object() xact.begin() xact.commit() self.assertEqual(connection._committed, (_DATASET, mutation)) self.assertTrue(connection._xact is None) - self.assertEqual(xact.id(), None) + self.assertEqual(xact.id, None) def test_commit_w_auto_ids(self): _DATASET = 'DATASET' @@ -96,8 +109,7 @@ def test_commit_w_auto_ids(self): connection = _Connection(234) connection._commit_result = _CommitResult( _make_key(_KIND, _ID, _DATASET)) - dataset = _Dataset(_DATASET, connection) - xact = self._makeOne(dataset) + xact = self._makeOne(dataset_id=_DATASET, connection=connection) entity = _Entity() xact.add_auto_id_entity(entity) xact._mutation = mutation = object() @@ -105,57 +117,54 @@ def test_commit_w_auto_ids(self): xact.commit() self.assertEqual(connection._committed, (_DATASET, mutation)) self.assertTrue(connection._xact is None) - self.assertEqual(xact.id(), None) - self.assertEqual(entity._key._path, [{'kind': _KIND, 'id': _ID}]) + self.assertEqual(xact.id, None) + self.assertEqual(entity.key.path, [{'kind': _KIND, 'id': _ID}]) def test_commit_w_already(self): _DATASET = 'DATASET' connection = _Connection(234) - dataset = _Dataset(_DATASET, connection) - xact = self._makeOne(dataset) + xact = self._makeOne(dataset_id=_DATASET, connection=connection) xact._mutation = object() xact.begin() connection.transaction(()) # Simulate previous commit via false-ish. xact.commit() self.assertEqual(connection._committed, None) self.assertTrue(connection._xact is None) - self.assertEqual(xact.id(), None) + self.assertEqual(xact.id, None) def test_context_manager_no_raise(self): _DATASET = 'DATASET' connection = _Connection(234) - dataset = _Dataset(_DATASET, connection) - xact = self._makeOne(dataset) + xact = self._makeOne(dataset_id=_DATASET, connection=connection) xact._mutation = mutation = object() with xact: - self.assertEqual(xact.id(), 234) + self.assertEqual(xact.id, 234) self.assertEqual(connection._begun, _DATASET) self.assertTrue(connection._xact is xact) self.assertEqual(connection._committed, (_DATASET, mutation)) self.assertTrue(connection._xact is None) - self.assertEqual(xact.id(), None) + self.assertEqual(xact.id, None) def test_context_manager_w_raise(self): class Foo(Exception): pass _DATASET = 'DATASET' connection = _Connection(234) - dataset = _Dataset(_DATASET, connection) - xact = self._makeOne(dataset) + xact = self._makeOne(dataset_id=_DATASET, connection=connection) xact._mutation = object() try: with xact: - self.assertEqual(xact.id(), 234) + self.assertEqual(xact.id, 234) self.assertEqual(connection._begun, _DATASET) self.assertTrue(connection._xact is xact) raise Foo() except Foo: - self.assertEqual(xact.id(), None) + self.assertEqual(xact.id, None) self.assertEqual(connection._rolled_back, _DATASET) self.assertEqual(connection._xact, None) self.assertEqual(connection._committed, None) self.assertTrue(connection._xact is None) - self.assertEqual(xact.id(), None) + self.assertEqual(xact.id, None) def _make_key(kind, id, dataset_id): @@ -169,19 +178,6 @@ def _make_key(kind, id, dataset_id): return key -class _Dataset(object): - - def __init__(self, id, connection=None): - self._id = id - self._connection = connection - - def id(self): - return self._id - - def connection(self): - return self._connection - - class _Connection(object): _marker = object() _begun = _rolled_back = _committed = _xact = None @@ -217,9 +213,4 @@ class _Entity(object): def __init__(self): from gcloud.datastore.key import Key - self._key = Key('KIND', dataset_id='DATASET') - - def key(self, key=None): - if key is not None: - self._key = key - return self._key + self.key = Key('KIND', dataset_id='DATASET') diff --git a/gcloud/datastore/transaction.py b/gcloud/datastore/transaction.py index 663e6acbb2bb..41e3cc575c59 100644 --- a/gcloud/datastore/transaction.py +++ b/gcloud/datastore/transaction.py @@ -18,7 +18,7 @@ from gcloud.datastore import datastore_v1_pb2 as datastore_pb -class Transaction(_implicit_environ._DatastoreBase): +class Transaction(object): """An abstraction representing datastore Transactions. Transactions can be used to build up a bulk mutuation as well as @@ -121,44 +121,56 @@ class Transaction(_implicit_environ._DatastoreBase): ... with dataset2.transaction(): ... dataset2.entity('Thing').save() - :type dataset: :class:`gcloud.datastore.dataset.Dataset` - :param dataset: The dataset to which this :class:`Transaction` belongs. + :type dataset_id: :class:`str`. + :param dataset_id: The ID of the dataset. + + :type connection: :class:`gcloud.datastore.connection.Connection` + :param connection: The connection used to connect to datastore. + + :raises: :class:`ValueError` if either a connection or dataset ID + are not set. """ - def __init__(self, dataset=None): - super(Transaction, self).__init__(dataset=dataset) - # If self._dataset is None, using this transaction will fail. + def __init__(self, dataset_id=None, connection=None): + self._connection = connection or _implicit_environ.CONNECTION + self._dataset_id = dataset_id or _implicit_environ.DATASET_ID + + if self._connection is None or self._dataset_id is None: + raise ValueError('A transaction must have a connection and ' + 'a dataset ID set.') + self._id = None self._mutation = datastore_pb.Mutation() self._auto_id_entities = [] - def connection(self): - """Getter for current connection over which the transaction will run. + @property + def dataset_id(self): + """Getter for dataset ID in which the transaction will run. - :rtype: :class:`gcloud.datastore.connection.Connection` - :returns: The connection over which the transaction will run. + :rtype: :class:`str` + :returns: The dataset ID in which the transaction will run. """ + return self._dataset_id - return self.dataset().connection() - - def dataset(self): - """Getter for the current dataset. + @property + def connection(self): + """Getter for connection over which the transaction will run. - :rtype: :class:`gcloud.datastore.dataset.Dataset` - :returns: The dataset to which the transaction belongs. + :rtype: :class:`gcloud.datastore.connection.Connection` + :returns: The connection over which the transaction will run. """ + return self._connection - return self._dataset - + @property def id(self): """Getter for the transaction ID. :rtype: string :returns: The ID of the current transaction. """ - return self._id + @property def mutation(self): """Getter for the current mutation. @@ -196,8 +208,8 @@ def begin(self): statement, however it can be called explicitly if you don't want to use a context manager. """ - self._id = self.connection().begin_transaction(self.dataset().id()) - self.connection().transaction(self) + self._id = self.connection.begin_transaction(self._dataset_id) + self.connection.transaction(self) def rollback(self): """Rolls back the current transaction. @@ -207,8 +219,8 @@ def rollback(self): - Sets the current connection's transaction reference to None. - Sets the current transaction's ID to None. """ - self.connection().rollback(self.dataset().id()) - self.connection().transaction(None) + self.connection.rollback(self._dataset_id) + self.connection.transaction(None) self._id = None def commit(self): @@ -226,18 +238,18 @@ def commit(self): """ # It's possible that they called commit() already, in which case # we shouldn't do any committing of our own. - if self.connection().transaction(): - result = self.connection().commit(self.dataset().id(), - self.mutation()) + if self.connection.transaction(): + result = self.connection.commit(self._dataset_id, + self.mutation) # For any of the auto-id entities, make sure we update their keys. for i, entity in enumerate(self._auto_id_entities): key_pb = result.insert_auto_id_key[i] new_id = key_pb.path_element[-1].id - entity.key(entity.key().completed_key(new_id)) + entity.key = entity.key.completed_key(new_id) # Tell the connection that the transaction is over. - self.connection().transaction(None) + self.connection.transaction(None) # Clear our own ID in case this gets accidentally reused. self._id = None