1 """The Key class, and associated utilities.
3 A Key encapsulates the following pieces of information, which together
4 uniquely designate a (possible) entity in the App Engine datastore:
6 - an application id (a string)
7 - a namespace (a string)
8 - a list of one or more (kind, id) pairs where kind is a string and id
9 is either a string or an integer.
11 The application id must always be part of the key, but since most
12 applications can only access their own entities, it defaults to the
13 current application id and you rarely need to worry about it. It must
16 The namespace designates a top-level partition of the key space for a
17 particular application. If you've never heard of namespaces, you can
18 safely ignore this feature.
20 Most of the action is in the (kind, id) pairs. A key must have at
21 least one (kind, id) pair. The last (kind, id) pair gives the kind
22 and the id of the entity that the key refers to, the others merely
23 specify a 'parent key'.
25 The kind is a string giving the name of the model class used to
26 represent the entity. (In more traditional databases this would be
27 the table name.) A model class is a Python class derived from
28 ndb.Model; see the documentation for ndb/model.py. Only the class
29 name itself is used as the kind. This means all your model classes
30 must be uniquely named within one application. You can override this
33 The id is either a string or an integer. When the id is a string, the
34 application is in control of how it assigns ids: For example, if you
35 could use an email address as the id for Account entities.
37 To use integer ids, you must let the datastore choose a unique id for
38 an entity when it is first inserted into the datastore. You can set
39 the id to None to represent the key for an entity that hasn't yet been
40 inserted into the datastore. The final key (including the assigned
41 id) will be returned after the entity is successfully inserted into
44 A key for which the id of the last (kind, id) pair is set to None is
45 called an incomplete key. Such keys can only be used to insert
46 entities into the datastore.
48 A key with exactly one (kind, id) pair is called a top level key or a
49 root key. Top level keys are also used as entity groups, which play a
50 role in transaction management.
52 If there is more than one (kind, id) pair, all but the last pair
53 represent the 'ancestor path', also known as the key of the 'parent
58 - Kinds and string ids must not be empty and must be at most 500 bytes
59 long (after UTF-8 encoding, if given as Python unicode objects).
60 NOTE: This is defined as a module level constant _MAX_KEYPART_BYTES.
62 - Integer ids must be at least 1 and less than 2**63.
64 For more info about namespaces, see
65 http://code.google.com/appengine/docs/python/multitenancy/overview.html.
66 The namespace defaults to the 'default namespace' selected by the
67 namespace manager. To explicitly select the empty namespace pass
71 __author__
= 'guido@google.com (Guido van Rossum)'
76 from .google_imports
import datastore_errors
77 from .google_imports
import datastore_types
78 from .google_imports
import namespace_manager
79 from .google_imports
import entity_pb
85 _MAX_LONG
= 2L ** 63 # Use 2L, see issue 65. http://goo.gl/ELczz
86 _MAX_KEYPART_BYTES
= 500
90 """An immutable datastore key.
92 For flexibility and convenience, multiple constructor signatures are
95 The primary way to construct a key is using positional arguments:
96 - Key(kind1, id1, kind2, id2, ...).
98 This is shorthand for either of the following two longer forms:
99 - Key(pairs=[(kind1, id1), (kind2, id2), ...])
100 - Key(flat=[kind1, id1, kind2, id2, ...])
102 Either of the above constructor forms can additionally pass in another
103 key using parent=<key>. The (kind, id) pairs of the parent key are
104 inserted before the (kind, id) pairs passed explicitly.
106 You can also construct a Key from a 'url-safe' encoded string:
107 - Key(urlsafe=<string>)
109 For esoteric purposes the following constructors exist:
110 - Key(reference=<reference>) -- passing in a low-level Reference object
111 - Key(serialized=<string>) -- passing in a serialized low-level Reference
112 - Key(<dict>) -- for unpickling, the same as Key(**<dict>)
114 The 'url-safe' string is really a websafe-base64-encoded serialized
115 Reference, but it's best to think of it as just an opaque unique
118 Additional constructor keyword arguments:
119 - app=<string> -- specify the application id
120 - namespace=<string> -- specify the namespace
122 If a Reference is passed (using one of reference, serialized or
123 urlsafe), the args and namespace keywords must match what is already
124 present in the Reference (after decoding if necessary). The parent
125 keyword cannot be combined with a Reference in any form.
128 Keys are immutable, which means that a Key object cannot be modified
129 once it has been created. This is enforced by the implementation as
130 well as Python allows.
132 For access to the contents of a key, the following methods and
133 operations are supported:
135 - repr(key), str(key) -- return a string representation resembling
136 the shortest constructor form, omitting the app and namespace
137 unless they differ from the default value.
139 - key1 == key2, key1 != key2 -- comparison for equality between Keys.
141 - hash(key) -- a hash value sufficient for storing Keys in a dict.
143 - key.pairs() -- a tuple of (kind, id) pairs.
145 - key.flat() -- a tuple of flattened kind and id values, i.e.
146 (kind1, id1, kind2, id2, ...).
148 - key.app() -- the application id.
150 - key.id() -- the string or integer id in the last (kind, id) pair,
151 or None if the key is incomplete.
153 - key.string_id() -- the string id in the last (kind, id) pair,
154 or None if the key has an integer id or is incomplete.
156 - key.integer_id() -- the integer id in the last (kind, id) pair,
157 or None if the key has a string id or is incomplete.
159 - key.namespace() -- the namespace.
161 - key.kind() -- a shortcut for key.pairs()[-1][0].
163 - key.parent() -- a Key constructed from all but the last (kind, id)
166 - key.urlsafe() -- a websafe-base64-encoded serialized Reference.
168 - key.serialized() -- a serialized Reference.
170 - key.reference() -- a Reference object. The caller promises not to
173 Keys also support interaction with the datastore; these methods are
174 the only ones that engage in any kind of I/O activity. For Future
175 objects, see the document for ndb/tasklets.py.
177 - key.get() -- return the entity for the Key.
179 - key.get_async() -- return a Future whose eventual result is
180 the entity for the Key.
182 - key.delete() -- delete the entity for the Key.
184 - key.delete_async() -- asynchronously delete the entity for the Key.
188 Subclassing Key is best avoided; it would be hard to get right.
191 __slots__
= ['__reference', '__pairs', '__app', '__namespace']
193 def __new__(cls
, *_args
, **kwargs
):
194 """Constructor. See the class docstring for arguments."""
196 if len(_args
) == 1 and isinstance(_args
[0], dict):
198 raise TypeError('Key() takes no keyword arguments when a dict is the '
199 'the first and only non-keyword argument (for '
204 raise TypeError('Key() with positional arguments '
205 'cannot accept flat as a keyword argument.')
206 kwargs
['flat'] = _args
207 self
= super(Key
, cls
).__new
__(cls
)
208 # Either __reference or (__pairs, __app, __namespace) must be set.
209 # Either one fully specifies a key; if both are set they must be
210 # consistent with each other.
211 if 'reference' in kwargs
or 'serialized' in kwargs
or 'urlsafe' in kwargs
:
212 self
.__reference
= _ConstructReference(cls
, **kwargs
)
215 self
.__namespace
= None
216 elif 'pairs' in kwargs
or 'flat' in kwargs
:
217 self
.__reference
= None
220 self
.__namespace
) = self
._parse
_from
_args
(**kwargs
)
222 raise TypeError('Key() cannot create a Key instance without arguments.')
226 def _parse_from_args(pairs
=None, flat
=None, app
=None, namespace
=None,
229 if pairs
is not None:
230 raise TypeError('Key() cannot accept both flat and pairs arguments.')
232 raise ValueError('Key() must have an even number of positional '
234 pairs
= [(flat
[i
], flat
[i
+ 1]) for i
in xrange(0, len(flat
), 2)]
238 raise TypeError('Key must consist of at least one pair.')
239 for i
, (kind
, id) in enumerate(pairs
):
240 if isinstance(id, unicode):
241 id = id.encode('utf8')
243 if i
+ 1 < len(pairs
):
244 raise datastore_errors
.BadArgumentError(
245 'Incomplete Key entry must be last')
247 if not isinstance(id, (int, long, str)):
248 raise TypeError('Key id must be a string or a number; received %r' %
250 if isinstance(kind
, type):
251 kind
= kind
._get
_kind
()
252 if isinstance(kind
, unicode):
253 kind
= kind
.encode('utf8')
254 if not isinstance(kind
, str):
255 raise TypeError('Key kind must be a string or Model class; '
256 'received %r' % kind
)
259 pairs
[i
] = (kind
, id)
260 if parent
is not None:
261 if not isinstance(parent
, Key
):
262 raise datastore_errors
.BadValueError(
263 'Expected Key instance, got %r' % parent
)
265 raise datastore_errors
.BadArgumentError(
266 'Parent cannot have incomplete key')
267 pairs
[:0] = parent
.pairs()
269 if app
!= parent
.app():
270 raise ValueError('Cannot specify a different app %r '
271 'than the parent app %r' %
275 if namespace
is not None:
276 if namespace
!= parent
.namespace():
277 raise ValueError('Cannot specify a different namespace %r '
278 'than the parent namespace %r' %
279 (namespace
, parent
.namespace()))
281 namespace
= parent
.namespace()
283 app
= _DefaultAppId()
284 if namespace
is None:
285 namespace
= _DefaultNamespace()
286 return tuple(pairs
), app
, namespace
289 """String representation, used by str() and repr().
291 We produce a short string that conveys all relevant information,
292 suppressing app and namespace when they are equal to the default.
294 # TODO: Instead of "Key('Foo', 1)" perhaps return "Key(Foo, 1)" ?
296 for item
in self
.flat():
299 elif isinstance(item
, basestring
):
300 if not isinstance(item
, str):
301 raise TypeError('Key item is not an 8-bit string %r' % item
)
302 args
.append(repr(item
))
304 args
.append(str(item
))
305 if self
.app() != _DefaultAppId():
306 args
.append('app=%r' % self
.app())
307 if self
.namespace() != _DefaultNamespace():
308 args
.append('namespace=%r' % self
.namespace())
309 return 'Key(%s)' % ', '.join(args
)
314 """Hash value, for use in dict lookups."""
315 # This ignores app and namespace, which is fine since hash()
316 # doesn't need to return a unique value -- it only needs to ensure
317 # that the hashes of equal keys are equal, not the other way
319 return hash(tuple(self
.pairs()))
321 def __eq__(self
, other
):
322 """Equality comparison operation."""
323 # This does not use __tuple() because it is usually enough to
324 # compare pairs(), and we're performance-conscious here.
325 if not isinstance(other
, Key
):
326 return NotImplemented
327 return (tuple(self
.pairs()) == tuple(other
.pairs()) and
328 self
.app() == other
.app() and
329 self
.namespace() == other
.namespace())
331 def __ne__(self
, other
):
332 """The opposite of __eq__."""
333 if not isinstance(other
, Key
):
334 return NotImplemented
335 return not self
.__eq
__(other
)
338 """Helper to return an orderable tuple."""
339 return (self
.app(), self
.namespace(), self
.pairs())
341 def __lt__(self
, other
):
342 """Less than ordering."""
343 if not isinstance(other
, Key
):
344 return NotImplemented
345 return self
.__tuple
() < other
.__tuple
()
347 def __le__(self
, other
):
348 """Less than or equal ordering."""
349 if not isinstance(other
, Key
):
350 return NotImplemented
351 return self
.__tuple
() <= other
.__tuple
()
353 def __gt__(self
, other
):
354 """Greater than ordering."""
355 if not isinstance(other
, Key
):
356 return NotImplemented
357 return self
.__tuple
() > other
.__tuple
()
359 def __ge__(self
, other
):
360 """Greater than or equal ordering."""
361 if not isinstance(other
, Key
):
362 return NotImplemented
363 return self
.__tuple
() >= other
.__tuple
()
365 def __getstate__(self
):
366 """Private API used for pickling."""
367 return ({'pairs': list(self
.pairs()),
369 'namespace': self
.namespace()},)
371 def __setstate__(self
, state
):
372 """Private API used for pickling."""
374 raise TypeError('Invalid state length, expected 1; received %i' %
377 if not isinstance(kwargs
, dict):
378 raise TypeError('Key accepts a dict of keyword arguments as state; '
379 'received %r' % kwargs
)
380 self
.__reference
= None
381 self
.__pairs
= kwargs
['pairs']
382 self
.__app
= kwargs
['app']
383 self
.__namespace
= kwargs
['namespace']
385 def __getnewargs__(self
):
386 """Private API used for pickling."""
387 return ({'pairs': tuple(self
.pairs()),
389 'namespace': self
.namespace()},)
392 """Return a Key constructed from all but the last (kind, id) pairs.
394 If there is only one (kind, id) pair, return None.
399 return Key(pairs
=pairs
[:-1], app
=self
.app(), namespace
=self
.namespace())
402 """Return the root key. This is either self or the highest parent."""
406 return Key(pairs
=pairs
[:1], app
=self
.app(), namespace
=self
.namespace())
409 """Return the namespace."""
410 if self
.__namespace
is None:
411 self
.__namespace
= self
.__reference
.name_space()
412 return self
.__namespace
415 """Return the application id."""
416 if self
.__app
is None:
417 self
.__app
= self
.__reference
.app()
421 """Return the string or integer id in the last (kind, id) pair, if any.
424 A string or integer id, or None if the key is incomplete.
427 return self
.__pairs
[-1][1]
428 elem
= self
.__reference
.path().element(-1)
429 return elem
.name() or elem
.id() or None
432 """Return the string id in the last (kind, id) pair, if any.
435 A string id, or None if the key has an integer id or is incomplete.
437 if self
.__reference
is None:
439 if not isinstance(id, basestring
):
442 elem
= self
.__reference
.path().element(-1)
443 return elem
.name() or None
445 def integer_id(self
):
446 """Return the integer id in the last (kind, id) pair, if any.
449 An integer id, or None if the key has a string id or is incomplete.
451 if self
.__reference
is None:
453 if not isinstance(id, (int, long)):
456 elem
= self
.__reference
.path().element(-1)
457 return elem
.id() or None
460 """Return a tuple of (kind, id) pairs."""
464 for elem
in self
.__reference
.path().element_list():
467 id_or_name
= elem
.id()
469 id_or_name
= elem
.name()
472 tup
= (kind
, id_or_name
)
474 self
.__pairs
= pairs
= tuple(pairs
)
478 """Return a tuple of alternating kind and id values."""
480 for kind
, id in self
.pairs():
486 """Return the kind of the entity referenced.
488 This is the kind from the last (kind, id) pair.
491 return self
.__pairs
[-1][0]
492 return self
.__reference
.path().element(-1).type()
495 """Return the Reference object for this Key.
497 This is a entity_pb.Reference instance -- a protocol buffer class
498 used by the lower-level API to the datastore.
500 NOTE: The caller should not mutate the return value.
502 if self
.__reference
is None:
503 self
.__reference
= _ConstructReference(self
.__class
__,
506 namespace
=self
.__namespace
)
507 return self
.__reference
509 def serialized(self
):
510 """Return a serialized Reference object for this Key."""
511 return self
.reference().Encode()
514 """Return a url-safe string encoding this Key's Reference.
516 This string is compatible with other APIs and languages and with
517 the strings used to represent Keys in GQL and in the App Engine
520 # This is 3-4x faster than urlsafe_b64decode()
521 urlsafe
= base64
.b64encode(self
.reference().Encode())
522 return urlsafe
.rstrip('=').replace('+', '-').replace('/', '_')
524 # Datastore API using the default context.
525 # These use local import since otherwise they'd be recursive imports.
527 def get(self
, **ctx_options
):
528 """Synchronously get the entity for this Key.
530 Return None if there is no such entity.
532 return self
.get_async(**ctx_options
).get_result()
534 def get_async(self
, **ctx_options
):
535 """Return a Future whose result is the entity for this Key.
537 If no such entity exists, a Future is still returned, and the
538 Future's eventual return result be None.
540 from . import model
, tasklets
541 ctx
= tasklets
.get_context()
542 cls
= model
.Model
._kind
_map
.get(self
.kind())
544 cls
._pre
_get
_hook
(self
)
545 fut
= ctx
.get(self
, **ctx_options
)
547 post_hook
= cls
._post
_get
_hook
548 if not cls
._is
_default
_hook
(model
.Model
._default
_post
_get
_hook
,
550 fut
.add_immediate_callback(post_hook
, self
, fut
)
553 def delete(self
, **ctx_options
):
554 """Synchronously delete the entity for this Key.
556 This is a no-op if no such entity exists.
558 return self
.delete_async(**ctx_options
).get_result()
560 def delete_async(self
, **ctx_options
):
561 """Schedule deletion of the entity for this Key.
563 This returns a Future, whose result becomes available once the
564 deletion is complete. If no such entity exists, a Future is still
565 returned. In all cases the Future's result is None (i.e. there is
566 no way to tell whether the entity existed or not).
568 from . import tasklets
, model
569 ctx
= tasklets
.get_context()
570 cls
= model
.Model
._kind
_map
.get(self
.kind())
572 cls
._pre
_delete
_hook
(self
)
573 fut
= ctx
.delete(self
, **ctx_options
)
575 post_hook
= cls
._post
_delete
_hook
576 if not cls
._is
_default
_hook
(model
.Model
._default
_post
_delete
_hook
,
578 fut
.add_immediate_callback(post_hook
, self
, fut
)
582 def from_old_key(cls
, old_key
):
583 return cls(urlsafe
=str(old_key
))
585 def to_old_key(self
):
586 return datastore_types
.Key(encoded
=self
.urlsafe())
589 # The remaining functions in this module are private.
590 # TODO: Conform to PEP 8 naming, e.g. _construct_reference() etc.
593 def _ConstructReference(cls
, pairs
=None, flat
=None,
594 reference
=None, serialized
=None, urlsafe
=None,
595 app
=None, namespace
=None, parent
=None):
596 """Construct a Reference; the signature is the same as for Key."""
598 raise TypeError('Cannot construct Key reference on non-Key class; '
600 if (bool(pairs
) + bool(flat
) + bool(reference
) + bool(serialized
) +
602 raise TypeError('Cannot construct Key reference from incompatible keyword '
607 raise TypeError('_ConstructReference() must have an even number of '
608 'positional arguments.')
609 pairs
= [(flat
[i
], flat
[i
+ 1]) for i
in xrange(0, len(flat
), 2)]
610 elif parent
is not None:
613 raise TypeError('Key references must consist of at least one pair.')
614 if parent
is not None:
615 if not isinstance(parent
, Key
):
616 raise datastore_errors
.BadValueError(
617 'Expected Key instance, got %r' % parent
)
618 pairs
[:0] = parent
.pairs()
620 if app
!= parent
.app():
621 raise ValueError('Cannot specify a different app %r '
622 'than the parent app %r' %
626 if namespace
is not None:
627 if namespace
!= parent
.namespace():
628 raise ValueError('Cannot specify a different namespace %r '
629 'than the parent namespace %r' %
630 (namespace
, parent
.namespace()))
632 namespace
= parent
.namespace()
633 reference
= _ReferenceFromPairs(pairs
, app
=app
, namespace
=namespace
)
635 if parent
is not None:
636 raise TypeError('Key reference cannot be constructed when the parent '
637 'argument is combined with either reference, serialized '
638 'or urlsafe arguments.')
640 serialized
= _DecodeUrlSafe(urlsafe
)
642 reference
= _ReferenceFromSerialized(serialized
)
643 if not reference
.path().element_size():
644 raise RuntimeError('Key reference has no path or elements (%r, %r, %r).'
645 % (urlsafe
, serialized
, str(reference
)))
646 # TODO: ensure that each element has a type and either an id or a name
648 reference
= _ReferenceFromReference(reference
)
649 # You needn't specify app= or namespace= together with reference=,
650 # serialized= or urlsafe=, but if you do, their values must match
651 # what is already in the reference.
653 if app
!= reference
.app():
654 raise RuntimeError('Key reference constructed uses a different app %r '
655 'than the one specified %r' %
656 (reference
.app(), app
))
657 if namespace
is not None:
658 if namespace
!= reference
.name_space():
659 raise RuntimeError('Key reference constructed uses a different '
660 'namespace %r than the one specified %r' %
661 (reference
.name_space(), namespace
))
665 def _ReferenceFromPairs(pairs
, reference
=None, app
=None, namespace
=None):
666 """Construct a Reference from a list of pairs.
668 If a Reference is passed in as the second argument, it is modified
669 in place. The app and namespace are set from the corresponding
670 keyword arguments, with the customary defaults.
672 if reference
is None:
673 reference
= entity_pb
.Reference()
674 path
= reference
.mutable_path()
676 for kind
, idorname
in pairs
:
678 raise datastore_errors
.BadArgumentError(
679 'Incomplete Key entry must be last')
684 kind
= kind
.encode('utf8')
686 if issubclass(t
, type):
687 # Late import to avoid cycles.
688 from .model
import Model
690 if not issubclass(modelclass
, Model
):
691 raise TypeError('Key kind must be either a string or subclass of '
692 'Model; received %r' % modelclass
)
693 kind
= modelclass
._get
_kind
()
698 kind
= kind
.encode('utf8')
699 elif issubclass(t
, str):
701 elif issubclass(t
, unicode):
702 kind
= kind
.encode('utf8')
704 raise TypeError('Key kind must be either a string or subclass of Model;'
705 ' received %r' % kind
)
706 if not (1 <= len(kind
) <= _MAX_KEYPART_BYTES
):
707 raise ValueError('Key kind string must be a non-empty string up to %i'
708 'bytes; received %s' %
709 (_MAX_KEYPART_BYTES
, kind
))
710 elem
= path
.add_element()
713 if t
is int or t
is long:
714 if not (1 <= idorname
< _MAX_LONG
):
715 raise ValueError('Key id number is too long; received %i' % idorname
)
716 elem
.set_id(idorname
)
718 if not (1 <= len(idorname
) <= _MAX_KEYPART_BYTES
):
719 raise ValueError('Key name strings must be non-empty strings up to %i '
720 'bytes; received %s' %
721 (_MAX_KEYPART_BYTES
, idorname
))
722 elem
.set_name(idorname
)
724 idorname
= idorname
.encode('utf8')
725 if not (1 <= len(idorname
) <= _MAX_KEYPART_BYTES
):
726 raise ValueError('Key name unicode strings must be non-empty strings up'
727 ' to %i bytes; received %s' %
728 (_MAX_KEYPART_BYTES
, idorname
))
729 elem
.set_name(idorname
)
730 elif idorname
is None:
732 elif issubclass(t
, (int, long)):
733 if not (1 <= idorname
< _MAX_LONG
):
734 raise ValueError('Key id number is too long; received %i' % idorname
)
735 elem
.set_id(idorname
)
736 elif issubclass(t
, basestring
):
737 if issubclass(t
, unicode):
738 idorname
= idorname
.encode('utf8')
739 if not (1 <= len(idorname
) <= _MAX_KEYPART_BYTES
):
740 raise ValueError('Key name strings must be non-empty strings up to %i '
741 'bytes; received %s' % (_MAX_KEYPART_BYTES
, idorname
))
742 elem
.set_name(idorname
)
744 raise TypeError('id must be either a numeric id or a string name; '
745 'received %r' % idorname
)
746 # An empty app id means to use the default app id.
748 app
= _DefaultAppId()
749 # Always set the app id, since it is mandatory.
750 reference
.set_app(app
)
751 # An empty namespace overrides the default namespace.
752 if namespace
is None:
753 namespace
= _DefaultNamespace()
754 # Only set the namespace if it is not empty.
756 reference
.set_name_space(namespace
)
760 def _ReferenceFromReference(reference
):
761 """Copy a Reference."""
762 new_reference
= entity_pb
.Reference()
763 new_reference
.CopyFrom(reference
)
767 def _ReferenceFromSerialized(serialized
):
768 """Construct a Reference from a serialized Reference."""
769 if not isinstance(serialized
, basestring
):
770 raise TypeError('serialized must be a string; received %r' % serialized
)
771 elif isinstance(serialized
, unicode):
772 serialized
= serialized
.encode('utf8')
773 return entity_pb
.Reference(serialized
)
776 def _DecodeUrlSafe(urlsafe
):
777 """Decode a url-safe base64-encoded string.
779 This returns the decoded string.
781 if not isinstance(urlsafe
, basestring
):
782 raise TypeError('urlsafe must be a string; received %r' % urlsafe
)
783 if isinstance(urlsafe
, unicode):
784 urlsafe
= urlsafe
.encode('utf8')
785 mod
= len(urlsafe
) % 4
787 urlsafe
+= '=' * (4 - mod
)
788 # This is 3-4x faster than urlsafe_b64decode()
789 return base64
.b64decode(urlsafe
.replace('-', '+').replace('_', '/'))
793 """Return the default application id.
795 This is taken from the APPLICATION_ID environment variable.
797 return os
.getenv('APPLICATION_ID', '_')
800 def _DefaultNamespace():
801 """Return the default namespace.
803 This is taken from the namespace manager.
805 return namespace_manager
.get_namespace()