Skip to content

Commit 04d67f7

Browse files
author
Chris Rossi
authored
fix: make sure key.Key uses namespace from client when not specified (#339)
Fixes #337
1 parent 973361b commit 04d67f7

File tree

3 files changed

+46
-7
lines changed

3 files changed

+46
-7
lines changed

packages/google-cloud-ndb/google/cloud/ndb/key.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@
100100
from google.cloud.ndb import utils
101101

102102

103-
__all__ = ["Key"]
103+
__all__ = ["Key", "UNDEFINED"]
104104
_APP_ID_ENVIRONMENT = "APPLICATION_ID"
105105
_APP_ID_DEFAULT = "_"
106106
_WRONG_TYPE = "Cannot construct Key reference on non-Key class; received {!r}"
@@ -126,6 +126,14 @@
126126
"Key name strings must be non-empty strings up to {:d} bytes; received {}"
127127
)
128128

129+
UNDEFINED = object()
130+
"""Sentinel value.
131+
132+
Used to indicate a namespace hasn't been explicitly set in key construction.
133+
Used to distinguish between not passing a value and passing `None`, which
134+
indicates the default namespace.
135+
"""
136+
129137

130138
class Key(object):
131139
"""An immutable datastore key.
@@ -278,11 +286,15 @@ def __new__(cls, *path_args, **kwargs):
278286

279287
_constructor_handle_positional(path_args, kwargs)
280288
instance = super(Key, cls).__new__(cls)
289+
281290
# Make sure to pass in the namespace if it's not explicitly set.
282-
if "namespace" not in kwargs:
291+
if kwargs.get("namespace", UNDEFINED) is UNDEFINED:
283292
client = context_module.get_context().client
284293
if client.namespace:
285294
kwargs["namespace"] = client.namespace
295+
else:
296+
kwargs["namespace"] = None # default namespace
297+
286298
if (
287299
"reference" in kwargs
288300
or "serialized" in kwargs

packages/google-cloud-ndb/google/cloud/ndb/model.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4526,7 +4526,7 @@ def __init__(_self, **kwargs):
45264526
id_ = self._get_arg(kwargs, "id")
45274527
project = self._get_arg(kwargs, "project")
45284528
app = self._get_arg(kwargs, "app")
4529-
namespace = self._get_arg(kwargs, "namespace")
4529+
namespace = self._get_arg(kwargs, "namespace", key_module.UNDEFINED)
45304530
parent = self._get_arg(kwargs, "parent")
45314531
projection = self._get_arg(kwargs, "projection")
45324532

@@ -4542,7 +4542,7 @@ def __init__(_self, **kwargs):
45424542
id_ is None
45434543
and parent is None
45444544
and project is None
4545-
and namespace is None
4545+
and namespace is key_module.UNDEFINED
45464546
)
45474547
if key is not None:
45484548
if not key_parts_unspecified:
@@ -4567,7 +4567,7 @@ def __init__(_self, **kwargs):
45674567
self._set_projection(projection)
45684568

45694569
@classmethod
4570-
def _get_arg(cls, kwargs, keyword):
4570+
def _get_arg(cls, kwargs, keyword, default=None):
45714571
"""Parse keywords for fields that aren't user-defined properties.
45724572
45734573
This is used to re-map special keyword arguments in the presence
@@ -4581,9 +4581,11 @@ def _get_arg(cls, kwargs, keyword):
45814581
Args:
45824582
kwargs (Dict[str, Any]): A keyword arguments dictionary.
45834583
keyword (str): A keyword to be converted.
4584+
default (Any): Returned if argument isn't found.
45844585
45854586
Returns:
4586-
Optional[Any]: The ``keyword`` argument, if found.
4587+
Optional[Any]: The ``keyword`` argument, if found, otherwise
4588+
``default``.
45874589
"""
45884590
alt_keyword = "_" + keyword
45894591
if alt_keyword in kwargs:
@@ -4594,7 +4596,7 @@ def _get_arg(cls, kwargs, keyword):
45944596
if not isinstance(obj, Property) or isinstance(obj, ModelKey):
45954597
return kwargs.pop(keyword)
45964598

4597-
return None
4599+
return default
45984600

45994601
def _set_attributes(self, kwargs):
46004602
"""Set attributes from keyword arguments.

packages/google-cloud-ndb/tests/system/test_query.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,31 @@ class SomeKind(ndb.Model):
301301
assert results[0].key.namespace() == other_namespace
302302

303303

304+
def test_namespace_set_on_client_with_id(dispose_of, other_namespace):
305+
"""Regression test for #337
306+
307+
https://github.com/googleapis/python-ndb/issues/337
308+
"""
309+
310+
class SomeKind(ndb.Model):
311+
foo = ndb.IntegerProperty()
312+
bar = ndb.StringProperty()
313+
314+
client = ndb.Client(namespace=other_namespace)
315+
with client.context(cache_policy=False):
316+
id = test_utils.system.unique_resource_id()
317+
entity1 = SomeKind(id=id, foo=1, bar="a")
318+
key = entity1.put()
319+
dispose_of(key._key)
320+
assert key.namespace() == other_namespace
321+
322+
results = eventually(SomeKind.query().fetch, _length_equals(1))
323+
324+
assert results[0].foo == 1
325+
assert results[0].bar == "a"
326+
assert results[0].key.namespace() == other_namespace
327+
328+
304329
@pytest.mark.usefixtures("client_context")
305330
def test_filter_equal(ds_entity):
306331
for i in range(5):

0 commit comments

Comments
 (0)