Skip to content

Commit a02a73e

Browse files
committed
Merge pull request #483 from dhermes/fix-477-part6
Address sixth part of 477: Moves Dataset.get_entities to __init__ module.
2 parents ced11fb + d2a1446 commit a02a73e

File tree

9 files changed

+271
-211
lines changed

9 files changed

+271
-211
lines changed

gcloud/datastore/__init__.py

Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@
4949
from gcloud import credentials
5050
from gcloud.datastore import _implicit_environ
5151
from gcloud.datastore.connection import Connection
52+
from gcloud.datastore.dataset import Dataset
53+
from gcloud.datastore import helpers
5254

5355

5456
SCOPE = ('https://www.googleapis.com/auth/datastore ',
@@ -158,16 +160,57 @@ def _require_connection():
158160
return _implicit_environ.CONNECTION
159161

160162

161-
def get_entities(keys):
163+
def get_entities(keys, missing=None, deferred=None,
164+
connection=None, dataset_id=None):
162165
"""Retrieves entities from implied dataset, along with their attributes.
163166
164167
:type keys: list of :class:`gcloud.datastore.key.Key`
165168
:param keys: The name of the item to retrieve.
166169
170+
:type missing: an empty list or None.
171+
:param missing: If a list is passed, the key-only entities returned
172+
by the backend as "missing" will be copied into it.
173+
Use only as a keyword param.
174+
175+
:type deferred: an empty list or None.
176+
:param deferred: If a list is passed, the keys returned
177+
by the backend as "deferred" will be copied into it.
178+
Use only as a keyword param.
179+
180+
:type connection: :class:`gcloud.datastore.connection.Connection`
181+
:param connection: Optional. The connection used to connect to datastore.
182+
183+
:type dataset_id: :class:`str`.
184+
:param dataset_id: Optional. The ID of the dataset.
185+
167186
:rtype: list of :class:`gcloud.datastore.entity.Entity`
168187
:returns: The requested entities.
169188
"""
170-
return _require_dataset().get_entities(keys)
189+
connection = connection or _require_connection()
190+
dataset_id = dataset_id or _require_dataset().id()
191+
192+
entity_pbs = connection.lookup(
193+
dataset_id=dataset_id,
194+
key_pbs=[k.to_protobuf() for k in keys],
195+
missing=missing, deferred=deferred,
196+
)
197+
198+
new_dataset = Dataset(dataset_id, connection=connection)
199+
if missing is not None:
200+
missing[:] = [
201+
helpers.entity_from_protobuf(missed_pb, dataset=new_dataset)
202+
for missed_pb in missing]
203+
204+
if deferred is not None:
205+
deferred[:] = [
206+
helpers.key_from_protobuf(deferred_pb)
207+
for deferred_pb in deferred]
208+
209+
entities = []
210+
for entity_pb in entity_pbs:
211+
entities.append(helpers.entity_from_protobuf(
212+
entity_pb, dataset=new_dataset))
213+
return entities
171214

172215

173216
def allocate_ids(incomplete_key, num_ids, connection=None, dataset_id=None):
@@ -180,10 +223,10 @@ def allocate_ids(incomplete_key, num_ids, connection=None, dataset_id=None):
180223
:param num_ids: The number of IDs to allocate.
181224
182225
:type connection: :class:`gcloud.datastore.connection.Connection`
183-
:param connection: Optional. The connection used to allocate IDs.
226+
:param connection: Optional. The connection used to connect to datastore.
184227
185228
:type dataset_id: :class:`str`.
186-
:param dataset_id: Optional. The ID of the dataset used to allocate.
229+
:param dataset_id: Optional. The ID of the dataset.
187230
188231
:rtype: list of :class:`gcloud.datastore.key.Key`
189232
:returns: The (complete) keys allocated with `incomplete_key` as root.

gcloud/datastore/connection.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,13 @@
1414

1515
"""Connections to gcloud datastore API servers."""
1616

17-
from gcloud import connection as base_connection
17+
from gcloud import connection
1818
from gcloud.datastore import datastore_v1_pb2 as datastore_pb
1919
from gcloud.datastore import helpers
2020
from gcloud.datastore.dataset import Dataset
2121

2222

23-
class Connection(base_connection.Connection):
23+
class Connection(connection.Connection):
2424
"""A connection to the Google Cloud Datastore via the Protobuf API.
2525
2626
This class should understand only the basic types (and protobufs)
@@ -125,7 +125,7 @@ def build_api_url(cls, dataset_id, method, base_url=None,
125125
api_version=(api_version or cls.API_VERSION),
126126
dataset_id=dataset_id, method=method)
127127

128-
def transaction(self, transaction=base_connection.Connection._EMPTY):
128+
def transaction(self, transaction=connection.Connection._EMPTY):
129129
"""Getter/setter for the connection's transaction object.
130130
131131
:type transaction: :class:`gcloud.datastore.transaction.Transaction`,

gcloud/datastore/dataset.py

Lines changed: 0 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@
1414

1515
"""Create / interact with gcloud datastore datasets."""
1616

17-
from gcloud.datastore import helpers
18-
1917

2018
class Dataset(object):
2119
"""A dataset in the Cloud Datastore.
@@ -71,44 +69,3 @@ def id(self):
7169
"""
7270

7371
return self._id
74-
75-
def get_entities(self, keys, missing=None, deferred=None):
76-
"""Retrieves entities from the dataset, along with their attributes.
77-
78-
:type keys: list of :class:`gcloud.datastore.key.Key`
79-
:param keys: List of keys to be retrieved.
80-
81-
:type missing: an empty list or None.
82-
:param missing: If a list is passed, the key-only entities returned
83-
by the backend as "missing" will be copied into it.
84-
Use only as a keyword param.
85-
86-
:type deferred: an empty list or None.
87-
:param deferred: If a list is passed, the keys returned
88-
by the backend as "deferred" will be copied into it.
89-
Use only as a keyword param.
90-
91-
:rtype: list of :class:`gcloud.datastore.entity.Entity`
92-
:returns: The requested entities.
93-
"""
94-
entity_pbs = self.connection().lookup(
95-
dataset_id=self.id(),
96-
key_pbs=[k.to_protobuf() for k in keys],
97-
missing=missing, deferred=deferred,
98-
)
99-
100-
if missing is not None:
101-
missing[:] = [
102-
helpers.entity_from_protobuf(missed_pb, dataset=self)
103-
for missed_pb in missing]
104-
105-
if deferred is not None:
106-
deferred[:] = [
107-
helpers.key_from_protobuf(deferred_pb)
108-
for deferred_pb in deferred]
109-
110-
entities = []
111-
for entity_pb in entity_pbs:
112-
entities.append(helpers.entity_from_protobuf(
113-
entity_pb, dataset=self))
114-
return entities

gcloud/datastore/key.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -238,12 +238,12 @@ def get(self, connection=None):
238238
match found.
239239
"""
240240
# Temporary import hack until Dataset is removed in #477.
241-
from gcloud.datastore.dataset import Dataset
241+
from gcloud import datastore
242242

243243
# We allow partial keys to attempt a get, the backend will fail.
244244
connection = connection or _implicit_environ.CONNECTION
245-
dataset = Dataset(self.dataset_id, connection=connection)
246-
entities = dataset.get_entities([self])
245+
entities = datastore.get_entities(
246+
[self], connection=connection, dataset_id=self.dataset_id)
247247

248248
if entities:
249249
result = entities[0]

gcloud/datastore/test___init__.py

Lines changed: 143 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -189,21 +189,152 @@ def test__require_connection_value_set(self):
189189
stored_connection = gcloud.datastore._require_connection()
190190
self.assertTrue(stored_connection is FAKE_CONNECTION)
191191

192-
def test_get_entities(self):
193-
import gcloud.datastore
192+
193+
class Test_get_entities_function(unittest2.TestCase):
194+
195+
def _callFUT(self, keys, missing=None, deferred=None,
196+
connection=None, dataset_id=None):
197+
from gcloud.datastore import get_entities
198+
return get_entities(keys, missing=missing, deferred=deferred,
199+
connection=connection, dataset_id=dataset_id)
200+
201+
def test_get_entities_miss(self):
202+
from gcloud.datastore.key import Key
203+
from gcloud.datastore.test_connection import _Connection
204+
205+
DATASET_ID = 'DATASET'
206+
connection = _Connection()
207+
key = Key('Kind', 1234, dataset_id=DATASET_ID)
208+
results = self._callFUT([key], connection=connection,
209+
dataset_id=DATASET_ID)
210+
self.assertEqual(results, [])
211+
212+
def test_get_entities_miss_w_missing(self):
213+
from gcloud.datastore import datastore_v1_pb2 as datastore_pb
214+
from gcloud.datastore.key import Key
215+
from gcloud.datastore.test_connection import _Connection
216+
217+
DATASET_ID = 'DATASET'
218+
KIND = 'Kind'
219+
ID = 1234
220+
221+
# Make a missing entity pb to be returned from mock backend.
222+
missed = datastore_pb.Entity()
223+
missed.key.partition_id.dataset_id = DATASET_ID
224+
path_element = missed.key.path_element.add()
225+
path_element.kind = KIND
226+
path_element.id = ID
227+
228+
# Set missing entity on mock connection.
229+
connection = _Connection()
230+
connection._missing = [missed]
231+
232+
key = Key(KIND, ID, dataset_id=DATASET_ID)
233+
missing = []
234+
entities = self._callFUT([key], connection=connection,
235+
dataset_id=DATASET_ID, missing=missing)
236+
self.assertEqual(entities, [])
237+
self.assertEqual([missed.key().to_protobuf() for missed in missing],
238+
[key.to_protobuf()])
239+
240+
def test_get_entities_miss_w_deferred(self):
241+
from gcloud.datastore.key import Key
242+
from gcloud.datastore.test_connection import _Connection
243+
244+
DATASET_ID = 'DATASET'
245+
key = Key('Kind', 1234, dataset_id=DATASET_ID)
246+
247+
# Set deferred entity on mock connection.
248+
connection = _Connection()
249+
connection._deferred = [key.to_protobuf()]
250+
251+
deferred = []
252+
entities = self._callFUT([key], connection=connection,
253+
dataset_id=DATASET_ID, deferred=deferred)
254+
self.assertEqual(entities, [])
255+
self.assertEqual([def_key.to_protobuf() for def_key in deferred],
256+
[key.to_protobuf()])
257+
258+
def _make_entity_pb(self, dataset_id, kind, integer_id, name, str_val):
259+
from gcloud.datastore import datastore_v1_pb2 as datastore_pb
260+
261+
entity_pb = datastore_pb.Entity()
262+
entity_pb.key.partition_id.dataset_id = dataset_id
263+
path_element = entity_pb.key.path_element.add()
264+
path_element.kind = kind
265+
path_element.id = integer_id
266+
prop = entity_pb.property.add()
267+
prop.name = name
268+
prop.value.string_value = str_val
269+
270+
return entity_pb
271+
272+
def test_get_entities_hit(self):
273+
from gcloud.datastore.key import Key
274+
from gcloud.datastore.test_connection import _Connection
275+
276+
DATASET_ID = 'DATASET'
277+
KIND = 'Kind'
278+
ID = 1234
279+
PATH = [{'kind': KIND, 'id': ID}]
280+
281+
# Make a found entity pb to be returned from mock backend.
282+
entity_pb = self._make_entity_pb(DATASET_ID, KIND, ID,
283+
'foo', 'Foo')
284+
285+
# Make a connection to return the entity pb.
286+
connection = _Connection(entity_pb)
287+
288+
key = Key(KIND, ID, dataset_id=DATASET_ID)
289+
result, = self._callFUT([key], connection=connection,
290+
dataset_id=DATASET_ID)
291+
new_key = result.key()
292+
293+
# Check the returned value is as expected.
294+
self.assertFalse(new_key is key)
295+
self.assertEqual(new_key.dataset_id, DATASET_ID)
296+
self.assertEqual(new_key.path, PATH)
297+
self.assertEqual(list(result), ['foo'])
298+
self.assertEqual(result['foo'], 'Foo')
299+
300+
def test_get_entities_implicit(self):
194301
from gcloud.datastore import _implicit_environ
302+
from gcloud.datastore.key import Key
303+
from gcloud.datastore.test_connection import _Connection
195304
from gcloud.datastore.test_entity import _Dataset
196305
from gcloud._testing import _Monkey
197306

307+
DATASET_ID = 'DATASET'
308+
KIND = 'Kind'
309+
ID = 1234
310+
PATH = [{'kind': KIND, 'id': ID}]
311+
312+
# Make a found entity pb to be returned from mock backend.
313+
entity_pb = self._make_entity_pb(DATASET_ID, KIND, ID,
314+
'foo', 'Foo')
315+
316+
# Make a connection to return the entity pb.
317+
CUSTOM_CONNECTION = _Connection(entity_pb)
198318
CUSTOM_DATASET = _Dataset()
199-
DUMMY_KEYS = [object(), object()]
200-
DUMMY_VALS = [object(), object()]
201-
for key, val in zip(DUMMY_KEYS, DUMMY_VALS):
202-
CUSTOM_DATASET[key] = val
203319

204-
with _Monkey(_implicit_environ, DATASET=CUSTOM_DATASET):
205-
result = gcloud.datastore.get_entities(DUMMY_KEYS)
206-
self.assertTrue(result == DUMMY_VALS)
320+
key = Key(KIND, ID, dataset_id=DATASET_ID)
321+
with _Monkey(_implicit_environ, DATASET=CUSTOM_DATASET,
322+
CONNECTION=CUSTOM_CONNECTION):
323+
result, = self._callFUT([key])
324+
325+
expected_called_with = {
326+
'dataset_id': DATASET_ID,
327+
'key_pbs': [key.to_protobuf()],
328+
}
329+
self.assertEqual(CUSTOM_CONNECTION._called_with, expected_called_with)
330+
331+
new_key = result.key()
332+
# Check the returned value is as expected.
333+
self.assertFalse(new_key is key)
334+
self.assertEqual(new_key.dataset_id, DATASET_ID)
335+
self.assertEqual(new_key.path, PATH)
336+
self.assertEqual(list(result), ['foo'])
337+
self.assertEqual(result['foo'], 'Foo')
207338

208339

209340
class Test_allocate_ids_function(unittest2.TestCase):
@@ -216,7 +347,7 @@ def _callFUT(self, incomplete_key, num_ids,
216347

217348
def test_allocate_ids(self):
218349
from gcloud.datastore.key import Key
219-
from gcloud.datastore.test_dataset import _Connection
350+
from gcloud.datastore.test_connection import _Connection
220351

221352
DATASET_ID = 'DATASET'
222353
INCOMPLETE_KEY = Key('KIND', dataset_id=DATASET_ID)
@@ -235,7 +366,7 @@ def test_allocate_ids(self):
235366
def test_allocate_ids_implicit(self):
236367
from gcloud.datastore import _implicit_environ
237368
from gcloud.datastore.key import Key
238-
from gcloud.datastore.test_dataset import _Connection
369+
from gcloud.datastore.test_connection import _Connection
239370
from gcloud.datastore.test_entity import _Dataset
240371
from gcloud._testing import _Monkey
241372

@@ -253,7 +384,7 @@ def test_allocate_ids_implicit(self):
253384
def test_allocate_ids_with_complete(self):
254385
from gcloud.datastore import _implicit_environ
255386
from gcloud.datastore.key import Key
256-
from gcloud.datastore.test_dataset import _Connection
387+
from gcloud.datastore.test_connection import _Connection
257388
from gcloud.datastore.test_entity import _Dataset
258389
from gcloud._testing import _Monkey
259390

0 commit comments

Comments
 (0)