Skip to content

Commit 36ec6a6

Browse files
committed
Merge pull request #480 from dhermes/fix-477-part3
Address third part of 477: Move Dataset.get_entity to Key.
2 parents 626adca + c8e145f commit 36ec6a6

File tree

10 files changed

+104
-96
lines changed

10 files changed

+104
-96
lines changed

gcloud/datastore/__init__.py

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -146,18 +146,6 @@ def _require_dataset():
146146
return _implicit_environ.DATASET
147147

148148

149-
def get_entity(key):
150-
"""Retrieves entity from implicit dataset, along with its attributes.
151-
152-
:type key: :class:`gcloud.datastore.key.Key`
153-
:param key: The name of the item to retrieve.
154-
155-
:rtype: :class:`gcloud.datastore.entity.Entity` or ``None``
156-
:returns: The requested entity, or ``None`` if there was no match found.
157-
"""
158-
return _require_dataset().get_entity(key)
159-
160-
161149
def get_entities(keys):
162150
"""Retrieves entities from implied dataset, along with their attributes.
163151

gcloud/datastore/dataset.py

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -72,21 +72,6 @@ def id(self):
7272

7373
return self._id
7474

75-
def get_entity(self, key):
76-
"""Retrieves entity from the dataset, along with its attributes.
77-
78-
:type key: :class:`gcloud.datastore.key.Key`
79-
:param key: The key of the entity to be retrieved.
80-
81-
:rtype: :class:`gcloud.datastore.entity.Entity` or `NoneType`
82-
:returns: The requested entity, or ``None`` if there was no
83-
match found.
84-
"""
85-
entities = self.get_entities([key])
86-
87-
if entities:
88-
return entities[0]
89-
9075
def get_entities(self, keys, missing=None, deferred=None):
9176
"""Retrieves entities from the dataset, along with their attributes.
9277

gcloud/datastore/entity.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -213,8 +213,8 @@ def reload(self):
213213
exist only locally.
214214
"""
215215
key = self._must_key
216-
dataset = self._must_dataset
217-
entity = dataset.get_entity(key.to_protobuf())
216+
connection = self._must_dataset.connection()
217+
entity = key.get(connection=connection)
218218

219219
if entity:
220220
self.update(entity)

gcloud/datastore/key.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,33 @@ def to_protobuf(self):
227227

228228
return key
229229

230+
def get(self, connection=None):
231+
"""Retrieve entity corresponding to the curretn key.
232+
233+
:type connection: :class:`gcloud.datastore.connection.Connection`
234+
:param connection: Optional connection used to connection to datastore.
235+
236+
:rtype: :class:`gcloud.datastore.entity.Entity` or `NoneType`
237+
:returns: The requested entity, or ``None`` if there was no
238+
match found.
239+
:raises: `ValueError` if the current key is partial.
240+
"""
241+
# Temporary import hack until Dataset is removed in #477.
242+
from gcloud.datastore.dataset import Dataset
243+
244+
if self.is_partial:
245+
raise ValueError('Can only retrieve complete keys.')
246+
247+
connection = connection or _implicit_environ.CONNECTION
248+
dataset = Dataset(self.dataset_id, connection=connection)
249+
entities = dataset.get_entities([self])
250+
251+
if entities:
252+
result = entities[0]
253+
# We assume that the backend has not changed the key.
254+
result.key(self)
255+
return result
256+
230257
@property
231258
def is_partial(self):
232259
"""Boolean indicating if the key has an ID (or name).

gcloud/datastore/test___init__.py

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -166,20 +166,6 @@ def test__require_dataset(self):
166166
finally:
167167
_implicit_environ.DATASET = original_dataset
168168

169-
def test_get_entity(self):
170-
import gcloud.datastore
171-
from gcloud.datastore import _implicit_environ
172-
from gcloud.datastore.test_entity import _Dataset
173-
from gcloud._testing import _Monkey
174-
175-
CUSTOM_DATASET = _Dataset()
176-
DUMMY_KEY = object()
177-
DUMMY_VAL = object()
178-
CUSTOM_DATASET[DUMMY_KEY] = DUMMY_VAL
179-
with _Monkey(_implicit_environ, DATASET=CUSTOM_DATASET):
180-
result = gcloud.datastore.get_entity(DUMMY_KEY)
181-
self.assertTrue(result is DUMMY_VAL)
182-
183169
def test_get_entities(self):
184170
import gcloud.datastore
185171
from gcloud.datastore import _implicit_environ

gcloud/datastore/test_dataset.py

Lines changed: 0 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -40,48 +40,6 @@ def test_ctor_explicit(self):
4040
self.assertEqual(dataset.id(), DATASET_ID)
4141
self.assertTrue(dataset.connection() is CONNECTION)
4242

43-
def test_get_entity_miss(self):
44-
from gcloud.datastore.key import Key
45-
DATASET_ID = 'DATASET'
46-
connection = _Connection()
47-
dataset = self._makeOne(DATASET_ID, connection)
48-
key = Key('Kind', 1234, dataset_id=DATASET_ID)
49-
self.assertEqual(dataset.get_entity(key), None)
50-
51-
def test_get_entity_hit(self):
52-
from gcloud.datastore.connection import datastore_pb
53-
from gcloud.datastore.key import Key
54-
DATASET_ID = 'DATASET'
55-
KIND = 'Kind'
56-
ID = 1234
57-
PATH = [{'kind': KIND, 'id': ID}]
58-
entity_pb = datastore_pb.Entity()
59-
entity_pb.key.partition_id.dataset_id = DATASET_ID
60-
path_element = entity_pb.key.path_element.add()
61-
path_element.kind = KIND
62-
path_element.id = ID
63-
prop = entity_pb.property.add()
64-
prop.name = 'foo'
65-
prop.value.string_value = 'Foo'
66-
connection = _Connection(entity_pb)
67-
dataset = self._makeOne(DATASET_ID, connection)
68-
key = Key(KIND, ID, dataset_id=DATASET_ID)
69-
result = dataset.get_entity(key)
70-
key = result.key()
71-
self.assertEqual(key.dataset_id, DATASET_ID)
72-
self.assertEqual(key.path, PATH)
73-
self.assertEqual(list(result), ['foo'])
74-
self.assertEqual(result['foo'], 'Foo')
75-
76-
def test_get_entity_bad_type(self):
77-
DATASET_ID = 'DATASET'
78-
connection = _Connection()
79-
dataset = self._makeOne(DATASET_ID, connection)
80-
with self.assertRaises(AttributeError):
81-
dataset.get_entity(None)
82-
with self.assertRaises(AttributeError):
83-
dataset.get_entity([])
84-
8543
def test_get_entities_miss(self):
8644
from gcloud.datastore.key import Key
8745
DATASET_ID = 'DATASET'

gcloud/datastore/test_entity.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ def test_reload_no_key(self):
118118
def test_reload_miss(self):
119119
dataset = _Dataset()
120120
key = _Key()
121+
key._stored = None # Explicit miss.
121122
entity = self._makeOne(dataset)
122123
entity.key(key)
123124
entity['foo'] = 'Foo'
@@ -127,13 +128,15 @@ def test_reload_miss(self):
127128

128129
def test_reload_hit(self):
129130
dataset = _Dataset()
130-
dataset['KEY'] = {'foo': 'Bar'}
131131
key = _Key()
132+
NEW_VAL = 'Baz'
133+
key._stored = {'foo': NEW_VAL}
132134
entity = self._makeOne(dataset)
133135
entity.key(key)
134136
entity['foo'] = 'Foo'
135137
self.assertTrue(entity.reload() is entity)
136-
self.assertEqual(entity['foo'], 'Bar')
138+
self.assertEqual(entity['foo'], NEW_VAL)
139+
self.assertEqual(entity.keys(), ['foo'])
137140

138141
def test_save_no_key(self):
139142
from gcloud.datastore.entity import NoKey
@@ -248,6 +251,7 @@ class _Key(object):
248251
_partial = False
249252
_path = None
250253
_id = None
254+
_stored = None
251255

252256
def to_protobuf(self):
253257
return self._key
@@ -260,6 +264,10 @@ def is_partial(self):
260264
def path(self):
261265
return self._path
262266

267+
def get(self, connection=None):
268+
self._connection_used = connection
269+
return self._stored
270+
263271

264272
class _Dataset(dict):
265273

@@ -280,9 +288,6 @@ def id(self):
280288
def connection(self):
281289
return self._connection
282290

283-
def get_entity(self, key):
284-
return self.get(key)
285-
286291
def get_entities(self, keys):
287292
return [self.get(key) for key in keys]
288293

gcloud/datastore/test_key.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,63 @@ def test_to_protobuf_w_no_kind(self):
195195
pb = key.to_protobuf()
196196
self.assertFalse(pb.path_element[0].HasField('kind'))
197197

198+
def test_get_explicit_connection_miss(self):
199+
from gcloud.datastore.test_dataset import _Connection
200+
201+
cnxn_lookup_result = []
202+
cnxn = _Connection(*cnxn_lookup_result)
203+
key = self._makeOne('KIND', 1234)
204+
entity = key.get(connection=cnxn)
205+
self.assertEqual(entity, None)
206+
207+
def test_get_implicit_connection_miss(self):
208+
from gcloud._testing import _Monkey
209+
from gcloud.datastore import _implicit_environ
210+
from gcloud.datastore.test_dataset import _Connection
211+
212+
cnxn_lookup_result = []
213+
cnxn = _Connection(*cnxn_lookup_result)
214+
key = self._makeOne('KIND', 1234)
215+
with _Monkey(_implicit_environ, CONNECTION=cnxn):
216+
entity = key.get()
217+
self.assertEqual(entity, None)
218+
219+
def test_get_explicit_connection_hit(self):
220+
from gcloud.datastore import datastore_v1_pb2
221+
from gcloud.datastore.test_dataset import _Connection
222+
223+
KIND = 'KIND'
224+
ID = 1234
225+
226+
# Make a bogus entity PB to be returned from fake Connection.
227+
entity_pb = datastore_v1_pb2.Entity()
228+
entity_pb.key.partition_id.dataset_id = self._DEFAULT_DATASET
229+
path_element = entity_pb.key.path_element.add()
230+
path_element.kind = KIND
231+
path_element.id = ID
232+
prop = entity_pb.property.add()
233+
prop.name = 'foo'
234+
prop.value.string_value = 'Foo'
235+
236+
# Make fake connection.
237+
cnxn_lookup_result = [entity_pb]
238+
cnxn = _Connection(*cnxn_lookup_result)
239+
240+
# Create key and look-up.
241+
key = self._makeOne(KIND, ID)
242+
entity = key.get(connection=cnxn)
243+
self.assertEqual(entity.items(), [('foo', 'Foo')])
244+
self.assertTrue(entity.key() is key)
245+
246+
def test_get_explicit_connection_partial_key(self):
247+
from gcloud.datastore.test_dataset import _Connection
248+
249+
cnxn_lookup_result = []
250+
cnxn = _Connection(*cnxn_lookup_result)
251+
key = self._makeOne('KIND')
252+
with self.assertRaises(ValueError):
253+
key.get(connection=cnxn)
254+
198255
def test_is_partial_no_name_or_id(self):
199256
key = self._makeOne('KIND')
200257
self.assertTrue(key.is_partial)

pylintrc_default

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,13 +73,16 @@ ignore =
7373
# identical implementation but different docstrings.
7474
# - star-args: standard Python idioms for varargs:
7575
# ancestor = Query().filter(*order_props)
76+
# - cyclic-import: temporary workaround to support Key.get until Dataset
77+
# is removed in #477.
7678
disable =
7779
maybe-no-member,
7880
no-member,
7981
protected-access,
8082
redefined-builtin,
8183
similarities,
8284
star-args,
85+
cyclic-import,
8386

8487

8588
[REPORTS]

regression/datastore.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929

3030
DATASET_ID = os.getenv('GCLOUD_TESTS_DATASET_ID')
3131
datastore.set_default_dataset(dataset_id=DATASET_ID)
32+
datastore.set_default_connection()
3233

3334

3435
class TestDatastore(unittest2.TestCase):
@@ -97,11 +98,9 @@ def _generic_test_post(self, name=None, key_id=None):
9798
self.assertEqual(entity.key().name, name)
9899
if key_id is not None:
99100
self.assertEqual(entity.key().id, key_id)
100-
retrieved_entity = datastore.get_entity(entity.key())
101+
retrieved_entity = entity.key().get()
101102
# Check the keys are the same.
102-
self.assertEqual(retrieved_entity.key().path, entity.key().path)
103-
self.assertEqual(retrieved_entity.key().namespace,
104-
entity.key().namespace)
103+
self.assertTrue(retrieved_entity.key() is entity.key())
105104

106105
# Check the data is the same.
107106
retrieved_dict = dict(retrieved_entity.items())
@@ -352,13 +351,13 @@ def test_transaction(self):
352351
entity['url'] = u'www.google.com'
353352

354353
with Transaction():
355-
retrieved_entity = datastore.get_entity(key)
354+
retrieved_entity = key.get()
356355
if retrieved_entity is None:
357356
entity.save()
358357
self.case_entities_to_delete.append(entity)
359358

360359
# This will always return after the transaction.
361-
retrieved_entity = datastore.get_entity(key)
360+
retrieved_entity = key.get()
362361
retrieved_dict = dict(retrieved_entity.items())
363362
entity_dict = dict(entity.items())
364363
self.assertEqual(retrieved_dict, entity_dict)

0 commit comments

Comments
 (0)