Commit f35379a8 by Calen Pennington

Update opaque_keys docs

parent 77b895cb
""" """
Defines OpaqueKey class, to be used as the base-class for Defines the :class:`OpaqueKey` class, to be used as the base-class for
implementing pluggable OpaqueKeys. implementing pluggable OpaqueKeys.
These keys are designed to provide a limited, forward-evolveable interface to
an application, while concealing the particulars of the serialization
formats, and allowing new serialization formats to be installed transparently.
""" """
from abc import ABCMeta, abstractmethod, abstractproperty from abc import ABCMeta, abstractmethod, abstractproperty
from copy import deepcopy from copy import deepcopy
...@@ -21,8 +25,8 @@ class InvalidKeyError(Exception): ...@@ -21,8 +25,8 @@ class InvalidKeyError(Exception):
class OpaqueKeyMetaclass(ABCMeta): class OpaqueKeyMetaclass(ABCMeta):
""" """
Metaclass for OpaqueKeys. Automatically derives the class from a namedtuple Metaclass for :class:`OpaqueKey`. Sets the default value for the values in ``KEY_FIELDS`` to
with a fieldset equal to the KEY_FIELDS class attribute, if KEY_FIELDS is set. ``None``.
""" """
def __new__(mcs, name, bases, attrs): def __new__(mcs, name, bases, attrs):
if '__slots__' not in attrs: if '__slots__' not in attrs:
...@@ -40,31 +44,48 @@ class OpaqueKey(object): ...@@ -40,31 +44,48 @@ class OpaqueKey(object):
There are two levels of expected subclasses: Key type definitions, and key implementations There are two levels of expected subclasses: Key type definitions, and key implementations
OpaqueKey ::
|
KeyType OpaqueKey
| |
KeyImplementation Key type
|
The KeyType base class must define the class property KEY_TYPE, which identifies Key implementation
which entry_point namespace the keys implementations should be registered with.
The key type base class must define the class property ``KEY_TYPE``, which identifies
The KeyImplementation classes must define CANONICAL_NAMESPACE and KEY_FIELDS. which ``entry_point`` namespace the keys implementations should be registered with.
CANONICAL_NAMESPACE: Identifies the key namespace for the particular
key_implementation (when serializing). KeyImplementations must be The KeyImplementation classes must define the following:
registered using the CANONICAL_NAMESPACE is their entry_point name,
but can also be registered with other names for backwards compatibility. ``CANONICAL_NAMESPACE``
KEY_FIELDS: A list of attribute names that will be used to establish object Identifies the key namespace for the particular key implementation
identity. KeyImplementation instances will compare equal iff all of (when serializing). Key implementations must be registered using the
their KEY_FIELDS match, and will not compare equal to instances ``CANONICAL_NAMESPACE`` is their entry_point name, but can also be registered
of different KeyImplementation classes (even if the KEY_FIELDS match). with other names for backwards compatibility.
These fields must be hashable.
``KEY_FIELDS``
A list of attribute names that will be used to establish object
identity. Key implementation instances will compare equal iff all of
their ``KEY_FIELDS`` match, and will not compare equal to instances
of different KeyImplementation classes (even if the ``KEY_FIELDS`` match).
These fields must be hashable.
``_to_string``
Serialize the key into a unicode object. This should not include the namespace
prefix (``CANONICAL_NAMESPACE``).
``_from_string``
Construct an instance of this :class:`OpaqueKey` from a unicode object. The namespace
will already have been parsed.
OpaqueKeys will not have optional constructor parameters (due to the implementation of OpaqueKeys will not have optional constructor parameters (due to the implementation of
KEY_FIELDS), by default. However, and implementation class can provide a default, ``KEY_FIELDS``), by default. However, and implementation class can provide a default,
as long as it passes that default to a call to super().__init__. as long as it passes that default to a call to ``super().__init__``.
:class:`OpaqueKey` objects are immutable.
OpaqueKeys are immutable. Serialization of an :class:`OpaqueKey` is performed by using the :func:`unicode` builtin.
Deserialization is performed by the :meth:`from_string` method.
""" """
__metaclass__ = OpaqueKeyMetaclass __metaclass__ = OpaqueKeyMetaclass
__slots__ = ('_initialized') __slots__ = ('_initialized')
...@@ -142,6 +163,10 @@ class OpaqueKey(object): ...@@ -142,6 +163,10 @@ class OpaqueKey(object):
self._initialized = True self._initialized = True
def replace(self, **kwargs): def replace(self, **kwargs):
"""
Return: a new :class:`OpaqueKey` with ``KEY_FIELDS`` specified in ``kwargs`` replaced
their corresponding values.
"""
existing_values = {key: getattr(self, key) for key in self.KEY_FIELDS} # pylint: disable=no-member existing_values = {key: getattr(self, key) for key in self.KEY_FIELDS} # pylint: disable=no-member
existing_values.update(kwargs) existing_values.update(kwargs)
return type(self)(**existing_values) return type(self)(**existing_values)
...@@ -156,6 +181,9 @@ class OpaqueKey(object): ...@@ -156,6 +181,9 @@ class OpaqueKey(object):
raise AttributeError("Can't delete {!r}. OpaqueKeys are immutable.".format(name)) raise AttributeError("Can't delete {!r}. OpaqueKeys are immutable.".format(name))
def __unicode__(self): def __unicode__(self):
"""
Serialize this :class:`OpaqueKey`, in the form ``<CANONICAL_NAMESPACE>:<value of _to_string>``.
"""
return self.NAMESPACE_SEPARATOR.join([self.CANONICAL_NAMESPACE, self._to_string()]) # pylint: disable=no-member return self.NAMESPACE_SEPARATOR.join([self.CANONICAL_NAMESPACE, self._to_string()]) # pylint: disable=no-member
def __copy__(self): def __copy__(self):
......
...@@ -11,4 +11,5 @@ Contents: ...@@ -11,4 +11,5 @@ Contents:
sandbox-packages.rst sandbox-packages.rst
symmath.rst symmath.rst
calc.rst calc.rst
opaque-keys.rst
...@@ -65,7 +65,7 @@ else: ...@@ -65,7 +65,7 @@ else:
extensions = [ extensions = [
'sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.intersphinx', 'sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.intersphinx',
'sphinx.ext.todo', 'sphinx.ext.coverage', 'sphinx.ext.pngmath', 'sphinx.ext.todo', 'sphinx.ext.coverage', 'sphinx.ext.pngmath',
'sphinx.ext.mathjax', 'sphinx.ext.viewcode'] 'sphinx.ext.mathjax', 'sphinx.ext.viewcode', 'sphinxcontrib.napoleon']
# List of patterns, relative to source directory, that match files and # List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files. # directories to ignore when looking for source files.
......
*******************************************
OpaqueKeys
*******************************************
.. module:: opaque_keys
OpaqueKeys
==========
.. automodule:: opaque_keys
:members:
:show-inheritance:
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment