[Checkins] SVN: persistent/trunk/ Convert attribut hook doctests to unittests + Sphinx API docs.
Tres Seaver
cvs-admin at zope.org
Thu Jun 28 22:50:02 UTC 2012
Log message for revision 127159:
Convert attribut hook doctests to unittests + Sphinx API docs.
Changed:
_U persistent/trunk/
A persistent/trunk/docs/api/attributes.rst
U persistent/trunk/docs/api.rst
U persistent/trunk/persistent/tests/test_overriding_attrs.py
-=-
Added: persistent/trunk/docs/api/attributes.rst
===================================================================
--- persistent/trunk/docs/api/attributes.rst (rev 0)
+++ persistent/trunk/docs/api/attributes.rst 2012-06-28 22:49:58 UTC (rev 127159)
@@ -0,0 +1,311 @@
+Customizing Attribute Access
+============================
+
+Hooking :meth:`__getattr__`
+---------------------------
+The __getattr__ method works pretty much the same for persistent
+classes as it does for other classes. No special handling is
+needed. If an object is a ghost, then it will be activated before
+__getattr__ is called.
+
+In this example, our objects returns a tuple with the attribute
+name, converted to upper case and the value of _p_changed, for any
+attribute that isn't handled by the default machinery.
+
+.. doctest::
+
+ >>> from persistent.tests.test_overriding_attrs import OverridesGetattr
+ >>> o = OverridesGetattr()
+ >>> o._p_changed
+ False
+ >>> o._p_oid
+ >>> o._p_jar
+ >>> o.spam
+ ('SPAM', False)
+ >>> o.spam = 1
+ >>> o.spam
+ 1
+
+We'll save the object, so it can be deactivated:
+
+.. doctest::
+
+ >>> from persistent.tests.test_overriding_attrs import _resettingJar
+ >>> jar = _resettingJar()
+ >>> jar.add(o)
+ >>> o._p_deactivate()
+ >>> o._p_changed
+
+And now, if we ask for an attribute it doesn't have,
+
+.. doctest::
+
+ >>> o.eggs
+ ('EGGS', False)
+
+And we see that the object was activated before calling the
+:meth:`__getattr__` method.
+
+Hooking All Access
+------------------
+
+In this example, we'll provide an example that shows how to
+override the :meth:`__getattribute__`, :meth:`__setattr__`, and
+:meth:`__delattr__` methods. We'll create a class that stores it's
+attributes in a secret dictionary within the instance dictionary.
+
+The class will have the policy that variables with names starting
+with ``tmp_`` will be volatile.
+
+Our sample class takes initial values as keyword arguments to the constructor:
+
+.. doctest::
+
+ >>> from persistent.tests.test_overriding_attrs import VeryPrivate
+ >>> o = VeryPrivate(x=1)
+
+
+Hooking :meth:`__getattribute__``
+#################################
+
+The :meth:`__getattribute__` method is called for all attribute
+accesses. It overrides the attribute access support inherited
+from Persistent.
+
+.. doctest::
+
+ >>> o._p_changed
+ False
+ >>> o._p_oid
+ >>> o._p_jar
+ >>> o.x
+ 1
+ >>> o.y
+ Traceback (most recent call last):
+ ...
+ AttributeError: y
+
+Next, we'll save the object in a database so that we can deactivate it:
+
+.. doctest::
+
+ >>> from persistent.tests.test_overriding_attrs import _rememberingJar
+ >>> jar = _rememberingJar()
+ >>> jar.add(o)
+ >>> o._p_deactivate()
+ >>> o._p_changed
+
+And we'll get some data:
+
+.. doctest::
+
+ >>> o.x
+ 1
+
+which activates the object:
+
+.. doctest::
+
+ >>> o._p_changed
+ False
+
+It works for missing attribes too:
+
+.. doctest::
+
+ >>> o._p_deactivate()
+ >>> o._p_changed
+
+ >>> o.y
+ Traceback (most recent call last):
+ ...
+ AttributeError: y
+
+ >>> o._p_changed
+ False
+
+
+Hooking :meth:`__setattr__``
+############################
+
+The :meth:`__setattr__` method is called for all attribute
+assignments. It overrides the attribute assignment support
+inherited from Persistent.
+
+Implementors of :meth:`__setattr__` methods:
+
+1. Must call Persistent._p_setattr first to allow it
+ to handle some attributes and to make sure that the object
+ is activated if necessary, and
+
+2. Must set _p_changed to mark objects as changed.
+
+.. doctest::
+
+ >>> o = VeryPrivate()
+ >>> o._p_changed
+ False
+ >>> o._p_oid
+ >>> o._p_jar
+ >>> o.x
+ Traceback (most recent call last):
+ ...
+ AttributeError: x
+
+ >>> o.x = 1
+ >>> o.x
+ 1
+
+Because the implementation doesn't store attributes directly
+in the instance dictionary, we don't have a key for the attribute:
+
+.. doctest::
+
+ >>> 'x' in o.__dict__
+ False
+
+Next, we'll give the object a "remembering" jar so we can
+deactivate it:
+
+.. doctest::
+
+ >>> jar = _rememberingJar()
+ >>> jar.add(o)
+ >>> o._p_deactivate()
+ >>> o._p_changed
+
+We'll modify an attribute
+
+.. doctest::
+
+ >>> o.y = 2
+ >>> o.y
+ 2
+
+which reactivates it, and markes it as modified, because our
+implementation marked it as modified:
+
+.. doctest::
+
+ >>> o._p_changed
+ True
+
+Now, if fake a commit:
+
+.. doctest::
+
+ >>> jar.fake_commit()
+ >>> o._p_changed
+ False
+
+And deactivate the object:
+
+.. doctest::
+
+ >>> o._p_deactivate()
+ >>> o._p_changed
+
+and then set a variable with a name starting with ``tmp_``,
+The object will be activated, but not marked as modified,
+because our :meth:`__setattr__` implementation doesn't mark the
+object as changed if the name starts with ``tmp_``:
+
+.. doctest::
+
+ >>> o.tmp_foo = 3
+ >>> o._p_changed
+ False
+ >>> o.tmp_foo
+ 3
+
+
+Hooking :meth:`__delattr__``
+############################
+
+The __delattr__ method is called for all attribute
+deletions. It overrides the attribute deletion support
+inherited from Persistent.
+
+Implementors of :meth:`__delattr__` methods:
+
+1. Must call Persistent._p_delattr first to allow it
+ to handle some attributes and to make sure that the object
+ is activated if necessary, and
+
+2. Must set _p_changed to mark objects as changed.
+
+.. doctest::
+
+ >>> o = VeryPrivate(x=1, y=2, tmp_z=3)
+ >>> o._p_changed
+ False
+ >>> o._p_oid
+ >>> o._p_jar
+ >>> o.x
+ 1
+ >>> del o.x
+ >>> o.x
+ Traceback (most recent call last):
+ ...
+ AttributeError: x
+
+Next, we'll save the object in a jar so that we can
+deactivate it:
+
+.. doctest::
+
+ >>> jar = _rememberingJar()
+ >>> jar.add(o)
+ >>> o._p_deactivate()
+ >>> o._p_changed
+
+If we delete an attribute:
+
+.. doctest::
+
+ >>> del o.y
+
+The object is activated. It is also marked as changed because
+our implementation marked it as changed.
+
+.. doctest::
+
+ >>> o._p_changed
+ True
+ >>> o.y
+ Traceback (most recent call last):
+ ...
+ AttributeError: y
+
+ >>> o.tmp_z
+ 3
+
+Now, if fake a commit:
+
+.. doctest::
+
+ >>> jar.fake_commit()
+ >>> o._p_changed
+ False
+
+And deactivate the object:
+
+.. doctest::
+
+ >>> o._p_deactivate()
+ >>> o._p_changed
+
+and then delete a variable with a name starting with ``tmp_``,
+The object will be activated, but not marked as modified,
+because our :meth:`__delattr__` implementation doesn't mark the
+object as changed if the name starts with ``tmp_``:
+
+.. doctest::
+
+ >>> del o.tmp_z
+ >>> o._p_changed
+ False
+ >>> o.tmp_z
+ Traceback (most recent call last):
+ ...
+ AttributeError: tmp_z
Modified: persistent/trunk/docs/api.rst
===================================================================
--- persistent/trunk/docs/api.rst 2012-06-28 22:49:54 UTC (rev 127158)
+++ persistent/trunk/docs/api.rst 2012-06-28 22:49:58 UTC (rev 127159)
@@ -5,4 +5,5 @@
:maxdepth: 2
api/interfaces
+ api/attributes
api/pickling
Modified: persistent/trunk/persistent/tests/test_overriding_attrs.py
===================================================================
--- persistent/trunk/persistent/tests/test_overriding_attrs.py 2012-06-28 22:49:54 UTC (rev 127158)
+++ persistent/trunk/persistent/tests/test_overriding_attrs.py 2012-06-28 22:49:58 UTC (rev 127159)
@@ -13,11 +13,10 @@
##############################################################################
"""Overriding attr methods
-This module tests and documents, through example, overriding attribute
-access methods.
+Examples for overriding attribute access methods.
"""
-from persistent import Persistent # ouch!
+from persistent import Persistent
def _resettingJar():
from persistent.tests.utils import ResettingJar
@@ -27,47 +26,12 @@
from persistent.tests.utils import RememberingJar
return RememberingJar()
-class SampleOverridingGetattr(Persistent):
+
+class OverridesGetattr(Persistent):
"""Example of overriding __getattr__
"""
-
def __getattr__(self, name):
"""Get attributes that can't be gotten the usual way
-
- The __getattr__ method works pretty much the same for persistent
- classes as it does for other classes. No special handling is
- needed. If an object is a ghost, then it will be activated before
- __getattr__ is called.
-
- In this example, our objects returns a tuple with the attribute
- name, converted to upper case and the value of _p_changed, for any
- attribute that isn't handled by the default machinery.
-
- >>> o = SampleOverridingGetattr()
- >>> o._p_changed
- False
- >>> o._p_oid
- >>> o._p_jar
- >>> o.spam
- ('SPAM', False)
- >>> o.spam = 1
- >>> o.spam
- 1
-
- We'll save the object, so it can be deactivated:
-
- >>> jar = _resettingJar()
- >>> jar.add(o)
- >>> o._p_deactivate()
- >>> o._p_changed
-
- And now, if we ask for an attribute it doesn't have,
-
- >>> o.eggs
- ('EGGS', False)
-
- And we see that the object was activated before calling the
- __getattr__ method.
"""
# Don't pretend we have any special attributes.
if name.startswith("__") and name.endswrith("__"):
@@ -75,78 +39,18 @@
else:
return name.upper(), self._p_changed
-class SampleOverridingGetattributeSetattrAndDelattr(Persistent):
- """Example of overriding __getattribute__, __setattr__, and __delattr__
- In this example, we'll provide an example that shows how to
- override the __getattribute__, __setattr__, and __delattr__
- methods. We'll create a class that stores it's attributes in a
- secret dictionary within it's instance dictionary.
-
- The class will have the policy that variables with names starting
- with 'tmp_' will be volatile.
-
+class VeryPrivate(Persistent):
+ """Example of overriding __getattribute__, __setattr__, and __delattr__
"""
-
def __init__(self, **kw):
self.__dict__['__secret__'] = kw.copy()
def __getattribute__(self, name):
"""Get an attribute value
- The __getattribute__ method is called for all attribute
- accesses. It overrides the attribute access support inherited
- from Persistent.
-
- Our sample class let's us provide initial values as keyword
- arguments to the constructor:
-
- >>> o = SampleOverridingGetattributeSetattrAndDelattr(x=1)
- >>> o._p_changed
- 0
- >>> o._p_oid
- >>> o._p_jar
- >>> o.x
- 1
- >>> o.y
- Traceback (most recent call last):
- ...
- AttributeError: y
-
- Next, we'll save the object in a database so that we can
- deactivate it:
-
- >>> jar = _rememberingJar()
- >>> jar.add(o)
- >>> o._p_deactivate()
- >>> o._p_changed
-
- And we'll get some data:
-
- >>> o.x
- 1
-
- which activates the object:
-
- >>> o._p_changed
- 0
-
- It works for missing attribes too:
-
- >>> o._p_deactivate()
- >>> o._p_changed
-
- >>> o.y
- Traceback (most recent call last):
- ...
- AttributeError: y
-
- >>> o._p_changed
- 0
-
See the very important note in the comment below!
"""
-
#################################################################
# IMPORTANT! READ THIS! 8->
#
@@ -177,84 +81,7 @@
def __setattr__(self, name, value):
"""Set an attribute value
-
- The __setattr__ method is called for all attribute
- assignments. It overrides the attribute assignment support
- inherited from Persistent.
-
- Implementors of __setattr__ methods:
-
- 1. Must call Persistent._p_setattr first to allow it
- to handle some attributes and to make sure that the object
- is activated if necessary, and
-
- 2. Must set _p_changed to mark objects as changed.
-
- See the comments in the source below.
-
- >>> o = SampleOverridingGetattributeSetattrAndDelattr()
- >>> o._p_changed
- 0
- >>> o._p_oid
- >>> o._p_jar
- >>> o.x
- Traceback (most recent call last):
- ...
- AttributeError: x
-
- >>> o.x = 1
- >>> o.x
- 1
-
- Because the implementation doesn't store attributes directly
- in the instance dictionary, we don't have a key for the attribute:
-
- >>> 'x' in o.__dict__
- False
-
- Next, we'll give the object a "remembering" jar so we can
- deactivate it:
-
- >>> jar = _rememberingJar()
- >>> jar.add(o)
- >>> o._p_deactivate()
- >>> o._p_changed
-
- We'll modify an attribute
-
- >>> o.y = 2
- >>> o.y
- 2
-
- which reactivates it, and markes it as modified, because our
- implementation marked it as modified:
-
- >>> o._p_changed
- 1
-
- Now, if fake a commit:
-
- >>> jar.fake_commit()
- >>> o._p_changed
- 0
-
- And deactivate the object:
-
- >>> o._p_deactivate()
- >>> o._p_changed
-
- and then set a variable with a name starting with 'tmp_',
- The object will be activated, but not marked as modified,
- because our __setattr__ implementation doesn't mark the
- object as changed if the name starts with 'tmp_':
-
- >>> o.tmp_foo = 3
- >>> o._p_changed
- 0
- >>> o.tmp_foo
- 3
"""
-
#################################################################
# IMPORTANT! READ THIS! 8->
#
@@ -276,86 +103,7 @@
def __delattr__(self, name):
"""Delete an attribute value
-
- The __delattr__ method is called for all attribute
- deletions. It overrides the attribute deletion support
- inherited from Persistent.
-
- Implementors of __delattr__ methods:
-
- 1. Must call Persistent._p_delattr first to allow it
- to handle some attributes and to make sure that the object
- is activated if necessary, and
-
- 2. Must set _p_changed to mark objects as changed.
-
- See the comments in the source below.
-
- >>> o = SampleOverridingGetattributeSetattrAndDelattr(
- ... x=1, y=2, tmp_z=3)
- >>> o._p_changed
- 0
- >>> o._p_oid
- >>> o._p_jar
- >>> o.x
- 1
- >>> del o.x
- >>> o.x
- Traceback (most recent call last):
- ...
- AttributeError: x
-
- Next, we'll save the object in a jar so that we can
- deactivate it:
-
- >>> jar = _rememberingJar()
- >>> jar.add(o)
- >>> o._p_deactivate()
- >>> o._p_changed
-
- If we delete an attribute:
-
- >>> del o.y
-
- The object is activated. It is also marked as changed because
- our implementation marked it as changed.
-
- >>> o._p_changed
- 1
- >>> o.y
- Traceback (most recent call last):
- ...
- AttributeError: y
-
- >>> o.tmp_z
- 3
-
- Now, if fake a commit:
-
- >>> jar.fake_commit()
- >>> o._p_changed
- 0
-
- And deactivate the object:
-
- >>> o._p_deactivate()
- >>> o._p_changed
-
- and then delete a variable with a name starting with 'tmp_',
- The object will be activated, but not marked as modified,
- because our __delattr__ implementation doesn't mark the
- object as changed if the name starts with 'tmp_':
-
- >>> del o.tmp_z
- >>> o._p_changed
- 0
- >>> o.tmp_z
- Traceback (most recent call last):
- ...
- AttributeError: tmp_z
-
"""
-
#################################################################
# IMPORTANT! READ THIS! 8->
#
More information about the checkins
mailing list