Commit de8680be authored by Jason Madden's avatar Jason Madden Committed by GitHub

Merge pull request #80 from zopefoundation/coverage

Reach 100% coverage
parents 889b615c 349e9e2f
[run] [run]
source = persistent source = persistent
omit =
persistent/_ring_build.py
[report] [report]
exclude_lines = exclude_lines =
# pragma: no cover pragma: no cover
class I[A-Z]\w+\((Interface|I[A-Z].*)\): class I[A-Z]\w+\((Interface|I[A-Z].*)\):
raise NotImplementedError raise NotImplementedError
raise AssertionError raise AssertionError
if __name__ == '__main__':
...@@ -56,14 +56,18 @@ before_install: ...@@ -56,14 +56,18 @@ before_install:
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then source terryfy/travis_tools.sh; fi - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then source terryfy/travis_tools.sh; fi
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then get_python_environment $TERRYFY_PYTHON venv; fi - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then get_python_environment $TERRYFY_PYTHON venv; fi
install: install:
- pip install -U pip setuptools cffi wheel - pip install -U pip setuptools cffi wheel coverage coveralls
- pip install -U -e .[test] - pip install -U -e .[test]
script: script:
- python --version - python --version
- zope-testrunner --test-path=. --auto-color --auto-progress # coverage makes PyPy run about 3x slower, but the tests only take
# .4s to begin with (the whole process takes about 1.5), so that's
# still only 4.5s, which is maneagable.
- coverage run -m zope.testrunner --test-path=. --auto-color --auto-progress
notifications: notifications:
email: false email: false
after_success: after_success:
- coveralls
- echo [distutils] > ~/.pypirc - echo [distutils] > ~/.pypirc
- echo index-servers = pypi >> ~/.pypirc - echo index-servers = pypi >> ~/.pypirc
- echo [pypi] >> ~/.pypirc - echo [pypi] >> ~/.pypirc
......
...@@ -4,6 +4,11 @@ ...@@ -4,6 +4,11 @@
4.3.1 (unreleased) 4.3.1 (unreleased)
------------------ ------------------
- Reach and maintain 100% test coverage.
- Simplify ``__init__.py``, including removal of an attempted legacy
import of ``persistent.TimeStamp``.
- Add support for Python 3.7 and drop support for Python 3.3. - Add support for Python 3.7 and drop support for Python 3.3.
- Build the CFFI modules (used on PyPy or when PURE_PYTHON is set) `at - Build the CFFI modules (used on PyPy or when PURE_PYTHON is set) `at
...@@ -16,6 +21,12 @@ ...@@ -16,6 +21,12 @@
See `issue 75 See `issue 75
<https://github.com/zopefoundation/persistent/issues/75>`_. <https://github.com/zopefoundation/persistent/issues/75>`_.
- Fix deleting the ``_p_oid`` of a pure-Python persistent object when
it is in a cache.
- Fix deleting special (``_p``) attributes of a pure-Python persistent
object that overrides ``__delattr__`` and correctly calls ``_p_delattr``.
4.3.0 (2018-07-30) 4.3.0 (2018-07-30)
------------------ ------------------
......
...@@ -4,16 +4,19 @@ ...@@ -4,16 +4,19 @@
.. image:: https://travis-ci.org/zopefoundation/persistent.svg?branch=master .. image:: https://travis-ci.org/zopefoundation/persistent.svg?branch=master
:target: https://travis-ci.org/zopefoundation/persistent :target: https://travis-ci.org/zopefoundation/persistent
.. image:: https://coveralls.io/repos/github/zopefoundation/persistent/badge.svg?branch=master
:target: https://coveralls.io/github/zopefoundation/persistent?branch=master
.. image:: https://readthedocs.org/projects/persistent/badge/?version=latest .. image:: https://readthedocs.org/projects/persistent/badge/?version=latest
:target: http://persistent.readthedocs.org/en/latest/ :target: http://persistent.readthedocs.org/en/latest/
:alt: Documentation Status :alt: Documentation Status
.. image:: https://img.shields.io/pypi/v/persistent.svg .. image:: https://img.shields.io/pypi/v/persistent.svg
:target: https://pypi.python.org/pypi/persistent :target: https://pypi.org/project/persistent
:alt: PyPI :alt: Latest release
.. image:: https://img.shields.io/pypi/pyversions/persistent.svg .. image:: https://img.shields.io/pypi/pyversions/persistent.svg
:target: https://pypi.python.org/pypi/persistent :target: https://pypi.org/project/persistent
:alt: Python versions :alt: Python versions
This package contains a generic persistence implementation for Python. It This package contains a generic persistence implementation for Python. It
...@@ -22,7 +25,7 @@ a database such as the ZODB. ...@@ -22,7 +25,7 @@ a database such as the ZODB.
Please see the Sphinx documentation (``docs/index.rst``) for further Please see the Sphinx documentation (``docs/index.rst``) for further
information, or view the documentation at Read The Docs, for either information, or view the documentation at Read The Docs, for either
the latest (``http://persistent.readthedocs.io/en/latest/) or stable the latest (``http://persistent.readthedocs.io/en/latest/``) or stable
release (``http://persistent.readthedocs.io/en/stable/``). release (``http://persistent.readthedocs.io/en/stable/``).
.. note:: .. note::
......
...@@ -309,3 +309,21 @@ object as changed if the name starts with ``tmp_``: ...@@ -309,3 +309,21 @@ object as changed if the name starts with ``tmp_``:
Traceback (most recent call last): Traceback (most recent call last):
... ...
AttributeError: tmp_z AttributeError: tmp_z
If we attempt to delete ``_p_oid``, we find that we can't, and the
object is also not activated or changed:
.. doctest::
>>> del o._p_oid
Traceback (most recent call last):
...
ValueError: can't delete _p_oid of cached object
>>> o._p_changed
False
We are allowed to delete ``_p_changed``, which sets it to ``None``:
>>> del o._p_changed
>>> o._p_changed is None
True
...@@ -47,13 +47,13 @@ Caches have a :meth:`new_ghost` method that: ...@@ -47,13 +47,13 @@ Caches have a :meth:`new_ghost` method that:
>>> jar = ResettingJar() >>> jar = ResettingJar()
>>> cache = persistent.PickleCache(jar, 10, 100) >>> cache = persistent.PickleCache(jar, 10, 100)
>>> ob = C.__new__(C) >>> ob = C.__new__(C)
>>> cache.new_ghost('1', ob) >>> cache.new_ghost(b'1', ob)
>>> ob._p_changed >>> ob._p_changed
>>> ob._p_jar is jar >>> ob._p_jar is jar
True True
>>> ob._p_oid >>> ob._p_oid == b'1'
'1' True
>>> cache.cache_non_ghost_count >>> cache.cache_non_ghost_count
0 0
...@@ -18,8 +18,8 @@ machinery happy: ...@@ -18,8 +18,8 @@ machinery happy:
>>> f, (c,), state = x.__reduce__() >>> f, (c,), state = x.__reduce__()
>>> f.__name__ >>> f.__name__
'__newobj__' '__newobj__'
>>> f.__module__ >>> f.__module__.replace('_', '') # Normalize Python2/3
'copy_reg' 'copyreg'
>>> c.__name__ >>> c.__name__
'Simple' 'Simple'
...@@ -57,8 +57,8 @@ by overriding :meth:`__getnewargs__`, :meth:`__getstate__` and ...@@ -57,8 +57,8 @@ by overriding :meth:`__getnewargs__`, :meth:`__getstate__` and
>>> (f, (c, ax, ay), a) = x.__reduce__() >>> (f, (c, ax, ay), a) = x.__reduce__()
>>> f.__name__ >>> f.__name__
'__newobj__' '__newobj__'
>>> f.__module__ >>> f.__module__.replace('_', '') # Normalize Python2/3
'copy_reg' 'copyreg'
>>> c.__name__ >>> c.__name__
'Custom' 'Custom'
>>> ax, ay, a >>> ax, ay, a
...@@ -79,7 +79,6 @@ ignores any slots which map onto the "persistent" namespace (prefixed with ...@@ -79,7 +79,6 @@ ignores any slots which map onto the "persistent" namespace (prefixed with
.. doctest:: .. doctest::
>>> import copy_reg
>>> from persistent.tests.cucumbers import SubSlotted >>> from persistent.tests.cucumbers import SubSlotted
>>> x = SubSlotted('x', 'y', 'z') >>> x = SubSlotted('x', 'y', 'z')
......
...@@ -15,55 +15,49 @@ ...@@ -15,55 +15,49 @@
Fall back to pure Python implementations. Fall back to pure Python implementations.
""" """
import os
PURE_PYTHON = os.environ.get('PURE_PYTHON') import sys
if not PURE_PYTHON:
try: __all__ = [
from persistent.cPersistence import Persistent 'IPersistent',
from persistent.cPersistence import GHOST 'Persistent',
from persistent.cPersistence import UPTODATE 'GHOST',
from persistent.cPersistence import CHANGED 'UPTODATE',
from persistent.cPersistence import STICKY 'CHANGED',
from persistent.cPersistence import simple_new 'STICKY',
except ImportError: #pragma NO COVER 'PickleCache',
from persistent.persistence import Persistent 'TimeStamp',
from persistent.persistence import GHOST ]
from persistent.persistence import UPTODATE from persistent._compat import PURE_PYTHON
from persistent.persistence import CHANGED from persistent.interfaces import IPersistent
from persistent.persistence import STICKY
else: import persistent.timestamp as TimeStamp
from persistent._compat import copy_reg
copy_reg.constructor(simple_new) from persistent import persistence as pyPersistence
# Make an interface declaration for Persistent, if zope.interface from persistent import picklecache as pyPickleCache
# is available. Note that the Python version already does this.
try: try:
# Be careful not to shadow the modules
from persistent import cPersistence as _cPersistence
from persistent import cPickleCache as _cPickleCache
except ImportError: # pragma: no cover
_cPersistence = None
_cPickleCache = None
else:
# Make an interface declaration for Persistent
# Note that the Python version already does this.
from zope.interface import classImplements from zope.interface import classImplements
except ImportError: #pragma NO COVER classImplements(_cPersistence.Persistent, IPersistent)
pass
else:
from persistent.interfaces import IPersistent _persistence = pyPersistence if PURE_PYTHON or _cPersistence is None else _cPersistence
classImplements(Persistent, IPersistent) _picklecache = pyPickleCache if PURE_PYTHON or _cPickleCache is None else _cPickleCache
try: Persistent = _persistence.Persistent
from persistent.cPickleCache import PickleCache GHOST = _persistence.GHOST
except ImportError: #pragma NO COVER UPTODATE = _persistence.UPTODATE
from persistent.picklecache import PickleCache CHANGED = _persistence.CHANGED
STICKY = _persistence.STICKY
PickleCache = _picklecache.PickleCache
try: sys.modules['persistent.TimeStamp'] = sys.modules['persistent.timestamp']
import persistent.TimeStamp
except ImportError: #pragma NO COVER
import persistent.timestamp as TimeStamp
import sys
sys.modules['persistent.TimeStamp'
] = sys.modules['persistent.timestamp']
else: #pragma NO COVER
from persistent.persistence import Persistent
from persistent.persistence import GHOST
from persistent.persistence import UPTODATE
from persistent.persistence import CHANGED
from persistent.persistence import STICKY
from persistent.picklecache import PickleCache
import persistent.timestamp as TimeStamp
import sys
sys.modules['persistent.TimeStamp'] = sys.modules['persistent.timestamp']
...@@ -13,8 +13,11 @@ ...@@ -13,8 +13,11 @@
############################################################################## ##############################################################################
import sys import sys
import os
if sys.version_info[0] > 2: #pragma NO COVER PURE_PYTHON = os.environ.get('PURE_PYTHON')
if sys.version_info[0] > 2: # pragma: no cover
import copyreg as copy_reg import copyreg as copy_reg
from collections import UserDict as IterableUserDict from collections import UserDict as IterableUserDict
from collections import UserList from collections import UserList
...@@ -36,7 +39,7 @@ if sys.version_info[0] > 2: #pragma NO COVER ...@@ -36,7 +39,7 @@ if sys.version_info[0] > 2: #pragma NO COVER
PYTHON3 = True PYTHON3 = True
PYTHON2 = False PYTHON2 = False
else: #pragma NO COVER else: # pragma: no cover
import copy_reg import copy_reg
from UserDict import IterableUserDict from UserDict import IterableUserDict
from UserList import UserList from UserList import UserList
......
...@@ -23,7 +23,7 @@ try: ...@@ -23,7 +23,7 @@ try:
from persistent.cPersistence import UPTODATE from persistent.cPersistence import UPTODATE
from persistent.cPersistence import CHANGED from persistent.cPersistence import CHANGED
from persistent.cPersistence import STICKY from persistent.cPersistence import STICKY
except ImportError: #pragma NO COVER except ImportError: # pragma: no cover
GHOST = -1 GHOST = -1
UPTODATE = 0 UPTODATE = 0
CHANGED = 1 CHANGED = 1
......
...@@ -28,9 +28,6 @@ class PersistentList(UserList, persistent.Persistent): ...@@ -28,9 +28,6 @@ class PersistentList(UserList, persistent.Persistent):
""" """
__super_setitem = UserList.__setitem__ __super_setitem = UserList.__setitem__
__super_delitem = UserList.__delitem__ __super_delitem = UserList.__delitem__
if PYTHON2: # pragma: no cover
__super_setslice = UserList.__setslice__
__super_delslice = UserList.__delslice__
__super_iadd = UserList.__iadd__ __super_iadd = UserList.__iadd__
__super_imul = UserList.__imul__ __super_imul = UserList.__imul__
__super_append = UserList.append __super_append = UserList.append
...@@ -49,6 +46,10 @@ class PersistentList(UserList, persistent.Persistent): ...@@ -49,6 +46,10 @@ class PersistentList(UserList, persistent.Persistent):
self.__super_delitem(i) self.__super_delitem(i)
self._p_changed = 1 self._p_changed = 1
if PYTHON2: # pragma: no cover
__super_setslice = UserList.__setslice__
__super_delslice = UserList.__delslice__
def __setslice__(self, i, j, other): def __setslice__(self, i, j, other):
self.__super_setslice(i, j, other) self.__super_setslice(i, j, other)
self._p_changed = 1 self._p_changed = 1
...@@ -95,9 +96,3 @@ class PersistentList(UserList, persistent.Persistent): ...@@ -95,9 +96,3 @@ class PersistentList(UserList, persistent.Persistent):
def extend(self, other): def extend(self, other):
self.__super_extend(other) self.__super_extend(other)
self._p_changed = 1 self._p_changed = 1
# This works around a bug in Python 2.1.x (up to 2.1.2 at least) where the
# __cmp__ bogusly raises a RuntimeError, and because this is an extension
# class, none of the rich comparison stuff works anyway.
def __cmp__(self, other):
return cmp(self.data, self._UserList__cast(other))
...@@ -38,6 +38,7 @@ _STICKY = 0x0002 ...@@ -38,6 +38,7 @@ _STICKY = 0x0002
_OGA = object.__getattribute__ _OGA = object.__getattribute__
_OSA = object.__setattr__ _OSA = object.__setattr__
_ODA = object.__delattr__
# These names can be used from a ghost without causing it to be # These names can be used from a ghost without causing it to be
# activated. These are standardized with the C implementation # activated. These are standardized with the C implementation
...@@ -301,7 +302,7 @@ class Persistent(object): ...@@ -301,7 +302,7 @@ class Persistent(object):
if (_OGA(self, '_Persistent__jar') is not None and if (_OGA(self, '_Persistent__jar') is not None and
_OGA(self, '_Persistent__oid') is not None): _OGA(self, '_Persistent__oid') is not None):
_OGA(self, '_p_register')() _OGA(self, '_p_register')()
object.__delattr__(self, name) _ODA(self, name)
def _slotnames(self, _v_exclude=True): def _slotnames(self, _v_exclude=True):
slotnames = copy_reg._slotnames(type(self)) slotnames = copy_reg._slotnames(type(self))
...@@ -467,7 +468,7 @@ class Persistent(object): ...@@ -467,7 +468,7 @@ class Persistent(object):
""" See IPersistent. """ See IPersistent.
""" """
if name.startswith('_p_'): if name.startswith('_p_'):
setattr(self, name, value) _OSA(self, name, value)
return True return True
self._p_activate() self._p_activate()
self._p_accessed() self._p_accessed()
...@@ -477,7 +478,12 @@ class Persistent(object): ...@@ -477,7 +478,12 @@ class Persistent(object):
""" See IPersistent. """ See IPersistent.
""" """
if name.startswith('_p_'): if name.startswith('_p_'):
delattr(self, name) if name == '_p_oid' and self._p_is_in_cache(_OGA(self, '_Persistent__jar')):
# The C implementation forbids deleting the oid
# if we're already in a cache. Match its error message
raise ValueError('can not change _p_jar of cached object')
_ODA(self, name)
return True return True
self._p_activate() self._p_activate()
self._p_accessed() self._p_accessed()
......
...@@ -35,8 +35,7 @@ class OverridesGetattr(Persistent): ...@@ -35,8 +35,7 @@ class OverridesGetattr(Persistent):
""" """
# Don't pretend we have any special attributes. # Don't pretend we have any special attributes.
if name.startswith("__") and name.endswrith("__"): if name.startswith("__") and name.endswrith("__"):
raise AttributeError(name) raise AttributeError(name) # pragma: no cover
else:
return name.upper(), self._p_changed return name.upper(), self._p_changed
......
...@@ -14,29 +14,22 @@ ...@@ -14,29 +14,22 @@
# Example objects for pickling. # Example objects for pickling.
from persistent import Persistent from persistent import Persistent
from persistent._compat import PYTHON2
def print_dict(d): def print_dict(d):
d = d.items() d = sorted(d.items())
d.sort()
print('{%s}' % (', '.join( print('{%s}' % (', '.join(
[('%r: %r' % (k, v)) for (k, v) in d] [('%r: %r' % (k, v)) for (k, v) in d]
))) )))
def cmpattrs(self, other, *attrs): def cmpattrs(self, other, *attrs):
result = 0
for attr in attrs: for attr in attrs:
if attr[:3] in ('_v_', '_p_'): if attr[:3] in ('_v_', '_p_'):
continue raise AssertionError("_v_ and _p_ attrs not allowed")
lhs, rhs = getattr(self, attr, None), getattr(other, attr, None) lhs = getattr(self, attr, None)
if PYTHON2: rhs = getattr(other, attr, None)
c = cmp(lhs, rhs) result += lhs != rhs
if c: return result
return c
else:
if lhs != rhs:
return 1
return 0
class Simple(Persistent): class Simple(Persistent):
def __init__(self, name, **kw): def __init__(self, name, **kw):
...@@ -84,7 +77,7 @@ class Slotted(Persistent): ...@@ -84,7 +77,7 @@ class Slotted(Persistent):
@property @property
def _attrs(self): def _attrs(self):
return list(self.__dict__.keys()) raise NotImplementedError()
def __eq__(self, other): def __eq__(self, other):
return cmpattrs(self, other, '__class__', *self._attrs) == 0 return cmpattrs(self, other, '__class__', *self._attrs) == 0
......
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Foundation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""
Tests for the documentation.
"""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
# disable: accessing protected members, too many methods
# pylint: disable=W0212,R0904
import os.path
import unittest
import doctest
import manuel.capture
import manuel.codeblock
import manuel.doctest
import manuel.ignore
import manuel.testing
def test_suite():
here = os.path.dirname(__file__)
while not os.path.exists(os.path.join(here, 'setup.py')):
here = os.path.join(here, '..')
here = os.path.abspath(here)
docs = os.path.join(here, 'docs', 'api')
files_to_test = (
'cache.rst',
'attributes.rst',
'pickling.rst',
)
paths = [os.path.join(docs, f) for f in files_to_test]
m = manuel.ignore.Manuel()
m += manuel.doctest.Manuel(optionflags=(
doctest.NORMALIZE_WHITESPACE
| doctest.ELLIPSIS
| doctest.IGNORE_EXCEPTION_DETAIL
))
m += manuel.codeblock.Manuel()
m += manuel.capture.Manuel()
suite = unittest.TestSuite()
suite.addTest(
manuel.testing.TestSuite(
m,
*paths
)
)
return suite
...@@ -20,6 +20,8 @@ l0 = [] ...@@ -20,6 +20,8 @@ l0 = []
l1 = [0] l1 = [0]
l2 = [0, 1] l2 = [0, 1]
# pylint:disable=protected-access
class OtherList: class OtherList:
def __init__(self, initlist): def __init__(self, initlist):
self.__data = initlist self.__data = initlist
...@@ -34,6 +36,17 @@ class TestPList(unittest.TestCase): ...@@ -34,6 +36,17 @@ class TestPList(unittest.TestCase):
from persistent.list import PersistentList from persistent.list import PersistentList
return PersistentList return PersistentList
def _makeJar(self):
class Jar(object):
def register(self, obj):
"no-op"
return Jar()
def _makeOne(self, *args):
inst = self._getTargetClass()(*args)
inst._p_jar = self._makeJar()
return inst
def test_volatile_attributes_not_persisted(self): def test_volatile_attributes_not_persisted(self):
# http://www.zope.org/Collectors/Zope/2052 # http://www.zope.org/Collectors/Zope/2052
m = self._getTargetClass()() m = self._getTargetClass()()
...@@ -57,9 +70,9 @@ class TestPList(unittest.TestCase): ...@@ -57,9 +70,9 @@ class TestPList(unittest.TestCase):
uu1 = pl(u1) uu1 = pl(u1)
uu2 = pl(u2) uu2 = pl(u2)
v = pl(tuple(u)) pl(tuple(u))
v0 = pl(OtherList(u0)) pl(OtherList(u0))
vv = pl("this is also a sequence") pl("this is also a sequence")
# Test __repr__ # Test __repr__
eq = self.assertEqual eq = self.assertEqual
...@@ -68,46 +81,48 @@ class TestPList(unittest.TestCase): ...@@ -68,46 +81,48 @@ class TestPList(unittest.TestCase):
eq(repr(u1), repr(l1), "repr(u1) == repr(l1)") eq(repr(u1), repr(l1), "repr(u1) == repr(l1)")
# Test __cmp__ and __len__ # Test __cmp__ and __len__
try:
cmp
except NameError:
def cmp(a, b):
if a == b:
return 0
if a < b:
return -1
return 1
if PYTHON2:
def mycmp(a, b): def mycmp(a, b):
r = cmp(a, b) r = cmp(a, b)
if r < 0: return -1 if r < 0:
if r > 0: return 1 return -1
if r > 0:
return 1
return r return r
all = [l0, l1, l2, u, u0, u1, u2, uu, uu0, uu1, uu2] to_test = [l0, l1, l2, u, u0, u1, u2, uu, uu0, uu1, uu2]
for a in all: for a in to_test:
for b in all: for b in to_test:
eq(mycmp(a, b), mycmp(len(a), len(b)), eq(mycmp(a, b), mycmp(len(a), len(b)),
"mycmp(a, b) == mycmp(len(a), len(b))") "mycmp(a, b) == mycmp(len(a), len(b))")
# Test __getitem__ # Test __getitem__
for i in range(len(u2)): for i, val in enumerate(u2):
eq(u2[i], i, "u2[i] == i") eq(val, i, "u2[i] == i")
# Test __setitem__ # Test __setitem__
uu2[0] = 0 uu2[0] = 0
uu2[1] = 100 uu2[1] = 100
try: with self.assertRaises(IndexError):
uu2[2] = 200 uu2[2] = 200
except IndexError:
pass
else:
raise TestFailed("uu2[2] shouldn't be assignable")
# Test __delitem__ # Test __delitem__
del uu2[1] del uu2[1]
del uu2[0] del uu2[0]
try: with self.assertRaises(IndexError):
del uu2[0] del uu2[0]
except IndexError:
pass
else:
raise TestFailed("uu2[0] shouldn't be deletable")
# Test __getslice__ # Test __getslice__
...@@ -198,12 +213,8 @@ class TestPList(unittest.TestCase): ...@@ -198,12 +213,8 @@ class TestPList(unittest.TestCase):
eq(u2.index(0), 0, "u2.index(0) == 0") eq(u2.index(0), 0, "u2.index(0) == 0")
eq(u2.index(1), 1, "u2.index(1) == 1") eq(u2.index(1), 1, "u2.index(1) == 1")
try: with self.assertRaises(ValueError):
u2.index(2) u2.index(2)
except ValueError:
pass
else:
raise TestFailed("expected ValueError")
# Test reverse # Test reverse
...@@ -220,23 +231,19 @@ class TestPList(unittest.TestCase): ...@@ -220,23 +231,19 @@ class TestPList(unittest.TestCase):
eq(u, u2, "u == u2") eq(u, u2, "u == u2")
# Test keyword arguments to sort # Test keyword arguments to sort
if PYTHON2: if PYTHON2: # pragma: no cover
u.sort(cmp=lambda x,y: cmp(y, x)) u.sort(cmp=lambda x, y: cmp(y, x))
eq(u, [1, 0], "u == [1, 0]") eq(u, [1, 0], "u == [1, 0]")
u.sort(key=lambda x:-x) u.sort(key=lambda x: -x)
eq(u, [1, 0], "u == [1, 0]") eq(u, [1, 0], "u == [1, 0]")
u.sort(reverse=True) u.sort(reverse=True)
eq(u, [1, 0], "u == [1, 0]") eq(u, [1, 0], "u == [1, 0]")
# Passing any other keyword arguments results in a TypeError # Passing any other keyword arguments results in a TypeError
try: with self.assertRaises(TypeError):
u.sort(blah=True) u.sort(blah=True)
except TypeError:
pass
else:
raise TestFailed("expected TypeError")
# Test extend # Test extend
...@@ -254,10 +261,72 @@ class TestPList(unittest.TestCase): ...@@ -254,10 +261,72 @@ class TestPList(unittest.TestCase):
u *= 3 u *= 3
eq(u, u1 + u1 + u1, "u == u1 + u1 + u1") eq(u, u1 + u1 + u1, "u == u1 + u1 + u1")
def test_setslice(self):
inst = self._makeOne()
self.assertFalse(inst._p_changed)
inst[:] = [1, 2, 3]
self.assertEqual(inst, [1, 2, 3])
self.assertTrue(inst._p_changed)
def test_delslice(self):
inst = self._makeOne([1, 2, 3])
self.assertFalse(inst._p_changed)
self.assertEqual(inst, [1, 2, 3])
del inst[:]
self.assertTrue(inst._p_changed)
def test_iadd(self):
inst = self._makeOne()
self.assertFalse(inst._p_changed)
inst += [1, 2, 3]
self.assertEqual(inst, [1, 2, 3])
self.assertTrue(inst._p_changed)
def test_extend(self):
inst = self._makeOne()
self.assertFalse(inst._p_changed)
inst.extend([1, 2, 3])
self.assertEqual(inst, [1, 2, 3])
self.assertTrue(inst._p_changed)
def test_imul(self):
inst = self._makeOne([1])
self.assertFalse(inst._p_changed)
inst *= 2
self.assertEqual(inst, [1, 1])
self.assertTrue(inst._p_changed)
def test_append(self):
inst = self._makeOne()
self.assertFalse(inst._p_changed)
inst.append(1)
self.assertEqual(inst, [1])
self.assertTrue(inst._p_changed)
def test_insert(self):
inst = self._makeOne()
self.assertFalse(inst._p_changed)
inst.insert(0, 1)
self.assertEqual(inst, [1])
self.assertTrue(inst._p_changed)
def test_remove(self):
inst = self._makeOne([1])
self.assertFalse(inst._p_changed)
inst.remove(1)
self.assertEqual(inst, [])
self.assertTrue(inst._p_changed)
def test_reverse(self):
inst = self._makeOne([2, 1])
self.assertFalse(inst._p_changed)
inst.reverse()
self.assertEqual(inst, [1, 2])
self.assertTrue(inst._p_changed)
def test_suite(): def test_suite():
return unittest.makeSuite(TestPList) return unittest.defaultTestLoader.loadTestsFromName(__name__)
if __name__ == "__main__": if __name__ == '__main__':
loader = unittest.TestLoader() unittest.main()
unittest.main(testLoader=loader)
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
############################################################################## ##############################################################################
import unittest import unittest
# pylint:disable=blacklisted-name, protected-access
class Test_default(unittest.TestCase): class Test_default(unittest.TestCase):
...@@ -25,15 +25,14 @@ class Test_default(unittest.TestCase): ...@@ -25,15 +25,14 @@ class Test_default(unittest.TestCase):
return self._getTargetClass()(func) return self._getTargetClass()(func)
def test___get___from_class(self): def test___get___from_class(self):
_called_with = []
def _test(inst): def _test(inst):
_called_with.append(inst) raise AssertionError("Must not be caled")
return '_test'
descr = self._makeOne(_test) descr = self._makeOne(_test)
class Foo(object): class Foo(object):
testing = descr testing = descr
self.assertTrue(Foo.testing is descr) self.assertIs(Foo.testing, descr)
self.assertEqual(_called_with, [])
def test___get___from_instance(self): def test___get___from_instance(self):
_called_with = [] _called_with = []
...@@ -86,9 +85,9 @@ class PersistentMappingTests(unittest.TestCase): ...@@ -86,9 +85,9 @@ class PersistentMappingTests(unittest.TestCase):
def __init__(self, initmapping): def __init__(self, initmapping):
self.__data = initmapping self.__data = initmapping
def items(self): def items(self):
return self.__data.items() raise AssertionError("Not called")
v0 = self._makeOne(OtherMapping(u0)) self._makeOne(OtherMapping(u0))
vv = self._makeOne([(0, 0), (1, 1)]) self._makeOne([(0, 0), (1, 1)])
# Test __repr__ # Test __repr__
eq = self.assertEqual eq = self.assertEqual
...@@ -97,24 +96,37 @@ class PersistentMappingTests(unittest.TestCase): ...@@ -97,24 +96,37 @@ class PersistentMappingTests(unittest.TestCase):
eq(repr(u1), repr(l1), "repr(u1) == repr(l1)") eq(repr(u1), repr(l1), "repr(u1) == repr(l1)")
# Test __cmp__ and __len__ # Test __cmp__ and __len__
try:
cmp
except NameError:
def cmp(a, b):
if a == b:
return 0
if hasattr(a, 'items'):
a = sorted(a.items())
b = sorted(b.items())
if a < b:
return -1
return 1
if PYTHON2:
def mycmp(a, b): def mycmp(a, b):
r = cmp(a, b) r = cmp(a, b)
if r < 0: return -1 if r < 0:
if r > 0: return 1 return -1
if r > 0:
return 1
return r return r
all = [l0, l1, l2, u, u0, u1, u2, uu, uu0, uu1, uu2] to_test = [l0, l1, l2, u, u0, u1, u2, uu, uu0, uu1, uu2]
for a in all: for a in to_test:
for b in all: for b in to_test:
eq(mycmp(a, b), mycmp(len(a), len(b)), eq(mycmp(a, b), mycmp(len(a), len(b)),
"mycmp(a, b) == mycmp(len(a), len(b))") "mycmp(a, b) == mycmp(len(a), len(b))")
# Test __getitem__ # Test __getitem__
for i in range(len(u2)): for i, val in enumerate(u2):
eq(u2[i], i, "u2[i] == i") eq(val, i, "u2[i] == i")
# Test get # Test get
...@@ -136,12 +148,8 @@ class PersistentMappingTests(unittest.TestCase): ...@@ -136,12 +148,8 @@ class PersistentMappingTests(unittest.TestCase):
del uu2[1] del uu2[1]
del uu2[0] del uu2[0]
try: with self.assertRaises(KeyError):
del uu2[0] del uu2[0]
except KeyError:
pass
else:
raise TestFailed("uu2[0] shouldn't be deletable")
# Test __contains__ # Test __contains__
for i in u2: for i in u2:
...@@ -176,12 +184,8 @@ class PersistentMappingTests(unittest.TestCase): ...@@ -176,12 +184,8 @@ class PersistentMappingTests(unittest.TestCase):
eq(x, 1, "u2.pop(1) == 1") eq(x, 1, "u2.pop(1) == 1")
self.assertTrue(1 not in u2, "1 not in u2") self.assertTrue(1 not in u2, "1 not in u2")
try: with self.assertRaises(KeyError):
u2.pop(1) u2.pop(1)
except KeyError:
pass
else:
self.fail("1 should not be poppable from u2")
x = u2.pop(1, 7) x = u2.pop(1, 7)
eq(x, 7, "u2.pop(1, 7) == 7") eq(x, 7, "u2.pop(1, 7) == 7")
...@@ -230,8 +234,4 @@ class Test_legacy_PersistentDict(unittest.TestCase): ...@@ -230,8 +234,4 @@ class Test_legacy_PersistentDict(unittest.TestCase):
def test_suite(): def test_suite():
return unittest.TestSuite(( return unittest.defaultTestLoader.loadTestsFromName(__name__)
unittest.makeSuite(Test_default),
unittest.makeSuite(PersistentMappingTests),
unittest.makeSuite(Test_legacy_PersistentDict),
))
...@@ -24,9 +24,18 @@ _is_pypy3 = py_impl() == 'PyPy' and sys.version_info[0] > 2 ...@@ -24,9 +24,18 @@ _is_pypy3 = py_impl() == 'PyPy' and sys.version_info[0] > 2
_is_jython = py_impl() == 'Jython' _is_jython = py_impl() == 'Jython'
#pylint: disable=R0904,W0212,E1101 #pylint: disable=R0904,W0212,E1101
# pylint:disable=attribute-defined-outside-init,too-many-lines
# pylint:disable=blacklisted-name
# Hundreds of unused jar and OID vars make this useless
# pylint:disable=unused-variable
class _Persistent_Base(object): class _Persistent_Base(object):
# py2/3 compat
assertRaisesRegex = getattr(unittest.TestCase,
'assertRaisesRegex',
unittest.TestCase.assertRaisesRegexp)
def _getTargetClass(self): def _getTargetClass(self):
# concrete testcase classes must override # concrete testcase classes must override
raise NotImplementedError() raise NotImplementedError()
...@@ -79,10 +88,10 @@ class _Persistent_Base(object): ...@@ -79,10 +88,10 @@ class _Persistent_Base(object):
class _BrokenJar(object): class _BrokenJar(object):
def __init__(self): def __init__(self):
self.called = 0 self.called = 0
def register(self,ob): def register(self, ob):
self.called += 1 self.called += 1
raise NotImplementedError() raise NotImplementedError()
def setstate(self,ob): def setstate(self, ob):
raise NotImplementedError() raise NotImplementedError()
jar = _BrokenJar() jar = _BrokenJar()
...@@ -90,8 +99,7 @@ class _Persistent_Base(object): ...@@ -90,8 +99,7 @@ class _Persistent_Base(object):
return jar return jar
def _makeOneWithJar(self, klass=None, broken_jar=False): def _makeOneWithJar(self, klass=None, broken_jar=False):
from persistent.timestamp import _makeOctets OID = b'\x01' * 8
OID = _makeOctets('\x01' * 8)
if klass is not None: if klass is not None:
inst = klass() inst = klass()
else: else:
...@@ -162,12 +170,10 @@ class _Persistent_Base(object): ...@@ -162,12 +170,10 @@ class _Persistent_Base(object):
def test_assign_p_jar_w_new_jar(self): def test_assign_p_jar_w_new_jar(self):
inst, jar, OID = self._makeOneWithJar() inst, jar, OID = self._makeOneWithJar()
new_jar = self._makeJar() new_jar = self._makeJar()
try:
with self.assertRaisesRegex(ValueError,
"can not change _p_jar of cached object"):
inst._p_jar = new_jar inst._p_jar = new_jar
except ValueError as e:
self.assertEqual(str(e), "can not change _p_jar of cached object")
else:
self.fail("Should raise ValueError")
def test_assign_p_jar_w_valid_jar(self): def test_assign_p_jar_w_valid_jar(self):
jar = self._makeJar() jar = self._makeJar()
...@@ -189,43 +195,35 @@ class _Persistent_Base(object): ...@@ -189,43 +195,35 @@ class _Persistent_Base(object):
def test_assign_p_oid_w_invalid_oid(self): def test_assign_p_oid_w_invalid_oid(self):
inst, jar, OID = self._makeOneWithJar() inst, jar, OID = self._makeOneWithJar()
try: with self.assertRaisesRegex(ValueError,
'can not change _p_oid of cached object'):
inst._p_oid = object() inst._p_oid = object()
except ValueError as e:
self.assertEqual(str(e), 'can not change _p_oid of cached object')
else:
self.fail("Should raise value error")
def test_assign_p_oid_w_valid_oid(self): def test_assign_p_oid_w_valid_oid(self):
from persistent.timestamp import _makeOctets OID = b'\x01' * 8
OID = _makeOctets('\x01' * 8)
inst = self._makeOne() inst = self._makeOne()
inst._p_oid = OID inst._p_oid = OID
self.assertEqual(inst._p_oid, OID) self.assertEqual(inst._p_oid, OID)
inst._p_oid = OID # reassign only same OID inst._p_oid = OID # reassign only same OID
def test_assign_p_oid_w_new_oid_wo_jar(self): def test_assign_p_oid_w_new_oid_wo_jar(self):
from persistent.timestamp import _makeOctets OID1 = b'\x01' * 8
OID1 = _makeOctets('\x01' * 8) OID2 = b'\x02' * 8
OID2 = _makeOctets('\x02' * 8)
inst = self._makeOne() inst = self._makeOne()
inst._p_oid = OID1 inst._p_oid = OID1
inst._p_oid = OID2 inst._p_oid = OID2
self.assertEqual(inst._p_oid, OID2) self.assertEqual(inst._p_oid, OID2)
def test_assign_p_oid_w_None_wo_jar(self): def test_assign_p_oid_w_None_wo_jar(self):
from persistent.timestamp import _makeOctets OID1 = b'\x01' * 8
OID1 = _makeOctets('\x01' * 8)
inst = self._makeOne() inst = self._makeOne()
inst._p_oid = OID1 inst._p_oid = OID1
inst._p_oid = None inst._p_oid = None
self.assertEqual(inst._p_oid, None) self.assertEqual(inst._p_oid, None)
def test_assign_p_oid_w_new_oid_w_jar(self): def test_assign_p_oid_w_new_oid_w_jar(self):
from persistent.timestamp import _makeOctets
inst, jar, OID = self._makeOneWithJar() inst, jar, OID = self._makeOneWithJar()
new_OID = _makeOctets('\x02' * 8) new_OID = b'\x02' * 8
def _test(): def _test():
inst._p_oid = new_OID inst._p_oid = new_OID
self.assertRaises(ValueError, _test) self.assertRaises(ValueError, _test)
...@@ -239,8 +237,7 @@ class _Persistent_Base(object): ...@@ -239,8 +237,7 @@ class _Persistent_Base(object):
self.assertEqual(inst._p_oid, 42) self.assertEqual(inst._p_oid, 42)
def test_delete_p_oid_wo_jar(self): def test_delete_p_oid_wo_jar(self):
from persistent.timestamp import _makeOctets OID = b'\x01' * 8
OID = _makeOctets('\x01' * 8)
inst = self._makeOne() inst = self._makeOne()
inst._p_oid = OID inst._p_oid = OID
del inst._p_oid del inst._p_oid
...@@ -248,9 +245,18 @@ class _Persistent_Base(object): ...@@ -248,9 +245,18 @@ class _Persistent_Base(object):
def test_delete_p_oid_w_jar(self): def test_delete_p_oid_w_jar(self):
inst, jar, OID = self._makeOneWithJar() inst, jar, OID = self._makeOneWithJar()
def _test(): with self.assertRaises(ValueError):
del inst._p_oid
def test_delete_p_oid_of_subclass_calling_p_delattr(self):
class P(self._getTargetClass()):
def __delattr__(self, name):
super(P, self)._p_delattr(name)
raise AssertionError("Should not get here")
inst, _jar, _oid = self._makeOneWithJar(klass=P)
with self.assertRaises(ValueError):
del inst._p_oid del inst._p_oid
self.assertRaises(ValueError, _test)
def test_del_oid_like_ZODB_abort(self): def test_del_oid_like_ZODB_abort(self):
# When a ZODB connection aborts, it removes registered objects from # When a ZODB connection aborts, it removes registered objects from
...@@ -276,30 +282,28 @@ class _Persistent_Base(object): ...@@ -276,30 +282,28 @@ class _Persistent_Base(object):
def test_assign_p_serial_too_short(self): def test_assign_p_serial_too_short(self):
inst = self._makeOne() inst = self._makeOne()
def _test(): def _test():
inst._p_serial = '\x01\x02\x03' inst._p_serial = b'\x01\x02\x03'
self.assertRaises(ValueError, _test) self.assertRaises(ValueError, _test)
def test_assign_p_serial_too_long(self): def test_assign_p_serial_too_long(self):
inst = self._makeOne() inst = self._makeOne()
def _test(): def _test():
inst._p_serial = '\x01\x02\x03' * 3 inst._p_serial = b'\x01\x02\x03' * 3
self.assertRaises(ValueError, _test) self.assertRaises(ValueError, _test)
def test_assign_p_serial_w_valid_serial(self): def test_assign_p_serial_w_valid_serial(self):
from persistent.timestamp import _makeOctets SERIAL = b'\x01' * 8
SERIAL = _makeOctets('\x01' * 8)
inst = self._makeOne() inst = self._makeOne()
inst._p_serial = SERIAL inst._p_serial = SERIAL
self.assertEqual(inst._p_serial, SERIAL) self.assertEqual(inst._p_serial, SERIAL)
def test_delete_p_serial(self): def test_delete_p_serial(self):
from persistent.timestamp import _makeOctets
from persistent.persistence import _INITIAL_SERIAL from persistent.persistence import _INITIAL_SERIAL
SERIAL = _makeOctets('\x01' * 8) SERIAL = b'\x01' * 8
inst = self._makeOne() inst = self._makeOne()
inst._p_serial = SERIAL inst._p_serial = SERIAL
self.assertEqual(inst._p_serial, SERIAL) self.assertEqual(inst._p_serial, SERIAL)
del(inst._p_serial) del inst._p_serial
self.assertEqual(inst._p_serial, _INITIAL_SERIAL) self.assertEqual(inst._p_serial, _INITIAL_SERIAL)
def test_query_p_changed_unsaved(self): def test_query_p_changed_unsaved(self):
...@@ -623,15 +627,17 @@ class _Persistent_Base(object): ...@@ -623,15 +627,17 @@ class _Persistent_Base(object):
def test_assign_p_estimated_size_wrong_type(self): def test_assign_p_estimated_size_wrong_type(self):
inst = self._makeOne() inst = self._makeOne()
self.assertRaises(TypeError,
lambda : setattr(inst, '_p_estimated_size', None)) with self.assertRaises(TypeError):
inst._p_estimated_size = None
try: try:
long constructor = long
except NameError: except NameError:
pass constructor = str
else:
self.assertRaises(TypeError, with self.assertRaises(TypeError):
lambda : setattr(inst, '_p_estimated_size', long(1))) inst._p_estimated_size = constructor(1)
def test_assign_p_estimated_size_negative(self): def test_assign_p_estimated_size_negative(self):
inst = self._makeOne() inst = self._makeOne()
...@@ -723,7 +729,7 @@ class _Persistent_Base(object): ...@@ -723,7 +729,7 @@ class _Persistent_Base(object):
def __getattribute__(self, name): def __getattribute__(self, name):
if name == 'magic': if name == 'magic':
return 42 return 42
return super(Base,self).__getattribute__(name) return super(Base, self).__getattribute__(name) # pragma: no cover
self.assertEqual(getattr(Base(), 'magic'), 42) self.assertEqual(getattr(Base(), 'magic'), 42)
...@@ -733,8 +739,7 @@ class _Persistent_Base(object): ...@@ -733,8 +739,7 @@ class _Persistent_Base(object):
self.assertRaises(AttributeError, getattr, Derived(), 'magic') self.assertRaises(AttributeError, getattr, Derived(), 'magic')
def test___setattr___p__names(self): def test___setattr___p__names(self):
from persistent.timestamp import _makeOctets SERIAL = b'\x01' * 8
SERIAL = _makeOctets('\x01' * 8)
inst, jar, OID = self._makeOneWithJar() inst, jar, OID = self._makeOneWithJar()
inst._p_activate() inst._p_activate()
NAMES = [('_p_jar', jar), NAMES = [('_p_jar', jar),
...@@ -1030,7 +1035,6 @@ class _Persistent_Base(object): ...@@ -1030,7 +1035,6 @@ class _Persistent_Base(object):
self.assertTrue(hasattr(inst1, 'foobar')) self.assertTrue(hasattr(inst1, 'foobar'))
def test___reduce__(self): def test___reduce__(self):
from persistent._compat import copy_reg
inst = self._makeOne() inst = self._makeOne()
first, second, third = inst.__reduce__() first, second, third = inst.__reduce__()
self.assertTrue(first is copy_reg.__newobj__) self.assertTrue(first is copy_reg.__newobj__)
...@@ -1038,7 +1042,6 @@ class _Persistent_Base(object): ...@@ -1038,7 +1042,6 @@ class _Persistent_Base(object):
self.assertEqual(third, None) self.assertEqual(third, None)
def test___reduce__w_subclass_having_getnewargs(self): def test___reduce__w_subclass_having_getnewargs(self):
from persistent._compat import copy_reg
class Derived(self._getTargetClass()): class Derived(self._getTargetClass()):
def __getnewargs__(self): def __getnewargs__(self):
return ('a', 'b') return ('a', 'b')
...@@ -1049,7 +1052,6 @@ class _Persistent_Base(object): ...@@ -1049,7 +1052,6 @@ class _Persistent_Base(object):
self.assertEqual(third, {}) self.assertEqual(third, {})
def test___reduce__w_subclass_having_getstate(self): def test___reduce__w_subclass_having_getstate(self):
from persistent._compat import copy_reg
class Derived(self._getTargetClass()): class Derived(self._getTargetClass()):
def __getstate__(self): def __getstate__(self):
return {} return {}
...@@ -1060,7 +1062,6 @@ class _Persistent_Base(object): ...@@ -1060,7 +1062,6 @@ class _Persistent_Base(object):
self.assertEqual(third, {}) self.assertEqual(third, {})
def test___reduce__w_subclass_having_getnewargs_and_getstate(self): def test___reduce__w_subclass_having_getnewargs_and_getstate(self):
from persistent._compat import copy_reg
class Derived(self._getTargetClass()): class Derived(self._getTargetClass()):
def __getnewargs__(self): def __getnewargs__(self):
return ('a', 'b') return ('a', 'b')
...@@ -1487,8 +1488,7 @@ class _Persistent_Base(object): ...@@ -1487,8 +1488,7 @@ class _Persistent_Base(object):
self._checkMRU(jar, [OID]) self._checkMRU(jar, [OID])
def test__p_setattr_w__p__name(self): def test__p_setattr_w__p__name(self):
from persistent.timestamp import _makeOctets SERIAL = b'\x01' * 8
SERIAL = _makeOctets('\x01' * 8)
inst, jar, OID = self._makeOneWithJar() inst, jar, OID = self._makeOneWithJar()
inst._p_deactivate() inst._p_deactivate()
self.assertTrue(inst._p_setattr('_p_serial', SERIAL)) self.assertTrue(inst._p_setattr('_p_serial', SERIAL))
...@@ -1537,14 +1537,12 @@ class _Persistent_Base(object): ...@@ -1537,14 +1537,12 @@ class _Persistent_Base(object):
# object stays in the up-to-date state. # object stays in the up-to-date state.
# It shouldn't change to the modified state, because it won't # It shouldn't change to the modified state, because it won't
# be saved when the transaction commits. # be saved when the transaction commits.
from persistent._compat import _b
class P(self._getTargetClass()): class P(self._getTargetClass()):
def __init__(self): def __init__(self):
self.x = 0 self.x = 0
def inc(self):
self.x += 1
p = P() p = P()
p._p_oid = _b('1') p._p_oid = b'1'
p._p_jar = self._makeBrokenJar() p._p_jar = self._makeBrokenJar()
self.assertEqual(p._p_state, 0) self.assertEqual(p._p_state, 0)
self.assertEqual(p._p_jar.called, 0) self.assertEqual(p._p_jar.called, 0)
...@@ -1557,14 +1555,11 @@ class _Persistent_Base(object): ...@@ -1557,14 +1555,11 @@ class _Persistent_Base(object):
def test__p_activate_w_broken_jar(self): def test__p_activate_w_broken_jar(self):
# Make sure that exceptions that occur inside the data manager's # Make sure that exceptions that occur inside the data manager's
# ``setstate()`` method propagate out to the caller. # ``setstate()`` method propagate out to the caller.
from persistent._compat import _b
class P(self._getTargetClass()): class P(self._getTargetClass()):
def __init__(self): def __init__(self):
self.x = 0 self.x = 0
def inc(self):
self.x += 1
p = P() p = P()
p._p_oid = _b('1') p._p_oid = b'1'
p._p_jar = self._makeBrokenJar() p._p_jar = self._makeBrokenJar()
p._p_deactivate() p._p_deactivate()
self.assertEqual(p._p_state, -1) self.assertEqual(p._p_state, -1)
...@@ -1618,23 +1613,21 @@ class _Persistent_Base(object): ...@@ -1618,23 +1613,21 @@ class _Persistent_Base(object):
class subclass(self._getTargetClass()): class subclass(self._getTargetClass()):
_v_setattr_called = False _v_setattr_called = False
def __setattr__(self, name, value): def __setattr__(self, name, value):
object.__setattr__(self, '_v_setattr_called', True) raise AssertionError("Should not be called")
super(subclass,self).__setattr__(name, value)
inst = subclass() inst = subclass()
self.assertEqual(object.__getattribute__(inst,'_v_setattr_called'), False) self.assertEqual(object.__getattribute__(inst,'_v_setattr_called'), False)
def test_can_set__p_attrs_if_subclass_denies_setattr(self): def test_can_set__p_attrs_if_subclass_denies_setattr(self):
from persistent._compat import _b
# ZODB defines a PersistentBroken subclass that only lets us # ZODB defines a PersistentBroken subclass that only lets us
# set things that start with _p, so make sure we can do that # set things that start with _p, so make sure we can do that
class Broken(self._getTargetClass()): class Broken(self._getTargetClass()):
def __setattr__(self, name, value): def __setattr__(self, name, value):
if name.startswith('_p_'): if name.startswith('_p_'):
super(Broken,self).__setattr__(name, value) super(Broken, self).__setattr__(name, value)
else: else:
raise TypeError("Can't change broken objects") raise AssertionError("Can't change broken objects")
KEY = _b('123') KEY = b'123'
jar = self._makeJar() jar = self._makeJar()
broken = Broken() broken = Broken()
...@@ -1743,17 +1736,17 @@ class PyPersistentTests(unittest.TestCase, _Persistent_Base): ...@@ -1743,17 +1736,17 @@ class PyPersistentTests(unittest.TestCase, _Persistent_Base):
# pickle cache yet. # pickle cache yet.
# Nothing should blow up when this happens # Nothing should blow up when this happens
from persistent._compat import _b from persistent._compat import _b
KEY = _b('123') KEY = b'123'
jar = self._makeJar() jar = self._makeJar()
c1 = self._makeOne() c1 = self._makeOne()
c1._p_oid = KEY c1._p_oid = KEY
c1._p_jar = jar c1._p_jar = jar
orig_mru = jar._cache.mru
def mru(oid): def mru(oid):
# Mimic what the real cache does # Mimic what the real cache does
if oid not in jar._cache._mru: if oid not in jar._cache._mru:
raise KeyError(oid) raise KeyError(oid)
orig_mru(oid) raise AssertionError("Should never get here")
jar._cache.mru = mru jar._cache.mru = mru
c1._p_accessed() c1._p_accessed()
self._checkMRU(jar, []) self._checkMRU(jar, [])
...@@ -1815,7 +1808,7 @@ _add_to_suite = [PyPersistentTests] ...@@ -1815,7 +1808,7 @@ _add_to_suite = [PyPersistentTests]
if not os.environ.get('PURE_PYTHON'): if not os.environ.get('PURE_PYTHON'):
try: try:
from persistent import cPersistence from persistent import cPersistence
except ImportError: except ImportError: # pragma: no cover
pass pass
else: else:
class CPersistentTests(unittest.TestCase, _Persistent_Base): class CPersistentTests(unittest.TestCase, _Persistent_Base):
...@@ -1846,12 +1839,7 @@ if not os.environ.get('PURE_PYTHON'): ...@@ -1846,12 +1839,7 @@ if not os.environ.get('PURE_PYTHON'):
self.assertRaises(TypeError, self._callFUT, '') self.assertRaises(TypeError, self._callFUT, '')
def test_w_type(self): def test_w_type(self):
import sys TO_CREATE = [type, list, tuple, object, dict]
TO_CREATE = [type, list, tuple, object]
# Python 3.3 segfaults when destroying a dict created via
# PyType_GenericNew. See http://bugs.python.org/issue16676
if sys.version_info < (3, 3):
TO_CREATE.append(dict)
for typ in TO_CREATE: for typ in TO_CREATE:
self.assertTrue(isinstance(self._callFUT(typ), typ)) self.assertTrue(isinstance(self._callFUT(typ), typ))
......
...@@ -24,6 +24,12 @@ _marker = object() ...@@ -24,6 +24,12 @@ _marker = object()
class PickleCacheTests(unittest.TestCase): class PickleCacheTests(unittest.TestCase):
# py2/3 compat
assertRaisesRegex = getattr(unittest.TestCase,
'assertRaisesRegex',
unittest.TestCase.assertRaisesRegexp)
def setUp(self): def setUp(self):
import persistent.picklecache import persistent.picklecache
self.orig_types = persistent.picklecache._CACHEABLE_TYPES self.orig_types = persistent.picklecache._CACHEABLE_TYPES
...@@ -98,12 +104,8 @@ class PickleCacheTests(unittest.TestCase): ...@@ -98,12 +104,8 @@ class PickleCacheTests(unittest.TestCase):
def test___setitem___non_string_oid_raises_TypeError(self): def test___setitem___non_string_oid_raises_TypeError(self):
cache = self._makeOne() cache = self._makeOne()
try: with self.assertRaises(TypeError):
cache[object()] = self._makePersist() cache[object()] = self._makePersist()
except TypeError:
pass
else:
self.fail("Didn't raise ValueError with non-string OID.")
def test___setitem___duplicate_oid_same_obj(self): def test___setitem___duplicate_oid_same_obj(self):
from persistent._compat import _b from persistent._compat import _b
...@@ -121,12 +123,8 @@ class PickleCacheTests(unittest.TestCase): ...@@ -121,12 +123,8 @@ class PickleCacheTests(unittest.TestCase):
cache[KEY] = original cache[KEY] = original
duplicate = self._makePersist(oid=KEY) duplicate = self._makePersist(oid=KEY)
try: with self.assertRaises(ValueError):
cache[KEY] = duplicate cache[KEY] = duplicate
except ValueError:
pass
else:
self.fail("Didn't raise KeyError with duplicate OID.")
def test___setitem___ghost(self): def test___setitem___ghost(self):
from persistent.interfaces import GHOST from persistent.interfaces import GHOST
...@@ -153,12 +151,8 @@ class PickleCacheTests(unittest.TestCase): ...@@ -153,12 +151,8 @@ class PickleCacheTests(unittest.TestCase):
cache = self._makeOne() cache = self._makeOne()
uptodate = self._makePersist(state=UPTODATE) uptodate = self._makePersist(state=UPTODATE)
try: with self.assertRaises(ValueError):
cache[KEY] = uptodate cache[KEY] = uptodate
except ValueError:
pass
else:
self.fail("Didn't raise ValueError when the key didn't match the OID")
def test___setitem___non_ghost(self): def test___setitem___non_ghost(self):
...@@ -201,24 +195,16 @@ class PickleCacheTests(unittest.TestCase): ...@@ -201,24 +195,16 @@ class PickleCacheTests(unittest.TestCase):
def test___delitem___non_string_oid_raises_TypeError(self): def test___delitem___non_string_oid_raises_TypeError(self):
cache = self._makeOne() cache = self._makeOne()
try: with self.assertRaises(TypeError):
del cache[object()] del cache[object()]
except TypeError:
pass
else:
self.fail("Didn't raise ValueError with non-string OID.")
def test___delitem___nonesuch_raises_KeyError(self): def test___delitem___nonesuch_raises_KeyError(self):
from persistent._compat import _b from persistent._compat import _b
cache = self._makeOne() cache = self._makeOne()
original = self._makePersist() original = self._makePersist()
try: with self.assertRaises(KeyError):
del cache[_b('nonesuch')] del cache[_b('nonesuch')]
except KeyError:
pass
else:
self.fail("Didn't raise KeyError with nonesuch OID.")
def test___delitem___w_persistent_class(self): def test___delitem___w_persistent_class(self):
from persistent._compat import _b from persistent._compat import _b
...@@ -878,22 +864,16 @@ class PickleCacheTests(unittest.TestCase): ...@@ -878,22 +864,16 @@ class PickleCacheTests(unittest.TestCase):
def test_setting_non_persistent_item(self): def test_setting_non_persistent_item(self):
cache = self._makeOne() cache = self._makeOne()
try: with self.assertRaisesRegex(TypeError,
"Cache values must be persistent objects."):
cache[None] = object() cache[None] = object()
except TypeError as e:
self.assertEqual(str(e), "Cache values must be persistent objects.")
else:
self.fail("Should raise TypeError")
def test_setting_without_jar(self): def test_setting_without_jar(self):
cache = self._makeOne() cache = self._makeOne()
p = self._makePersist(jar=None) p = self._makePersist(jar=None)
try: with self.assertRaisesRegex(ValueError,
"Cached object jar missing"):
cache[p._p_oid] = p cache[p._p_oid] = p
except ValueError as e:
self.assertEqual(str(e), "Cached object jar missing")
else:
self.fail("Should raise ValueError")
def test_setting_already_cached(self): def test_setting_already_cached(self):
cache1 = self._makeOne() cache1 = self._makeOne()
...@@ -902,12 +882,9 @@ class PickleCacheTests(unittest.TestCase): ...@@ -902,12 +882,9 @@ class PickleCacheTests(unittest.TestCase):
cache1[p._p_oid] = p cache1[p._p_oid] = p
cache2 = self._makeOne() cache2 = self._makeOne()
try: with self.assertRaisesRegex(ValueError,
"Object already in another cache"):
cache2[p._p_oid] = p cache2[p._p_oid] = p
except ValueError as e:
self.assertEqual(str(e), "Object already in another cache")
else:
self.fail("Should raise value error")
def test_cannot_update_mru_while_already_locked(self): def test_cannot_update_mru_while_already_locked(self):
cache = self._makeOne() cache = self._makeOne()
...@@ -972,7 +949,7 @@ class PickleCacheTests(unittest.TestCase): ...@@ -972,7 +949,7 @@ class PickleCacheTests(unittest.TestCase):
del p._p_deactivate del p._p_deactivate
self.assertEqual(cache.full_sweep(), 1) self.assertEqual(cache.full_sweep(), 1)
if _is_jython: if _is_jython: # pragma: no cover
def with_deterministic_gc(f): def with_deterministic_gc(f):
def test(self): def test(self):
old_flags = gc.getMonitorGlobal() old_flags = gc.getMonitorGlobal()
...@@ -1027,7 +1004,7 @@ class PickleCacheTests(unittest.TestCase): ...@@ -1027,7 +1004,7 @@ class PickleCacheTests(unittest.TestCase):
# It also shrank the measured size of the cache; # It also shrank the measured size of the cache;
# this would fail under PyPy if _SWEEP_NEEDS_GC was False # this would fail under PyPy if _SWEEP_NEEDS_GC was False
if force_collect: if force_collect: # pragma: no cover
gc.collect() gc.collect()
self.assertEqual(len(cache), 1) self.assertEqual(len(cache), 1)
...@@ -1053,12 +1030,11 @@ class PickleCacheTests(unittest.TestCase): ...@@ -1053,12 +1030,11 @@ class PickleCacheTests(unittest.TestCase):
def test_ring_impl(self): def test_ring_impl(self):
from .. import ring from .. import ring
if _is_pypy: expected = (ring._CFFIRing
self.assertIs(ring.Ring, ring._CFFIRing) if _is_pypy or ring._CFFIRing is not None or os.environ.get('USING_CFFI')
elif ring._CFFIRing is not None or os.environ.get('USING_CFFI'): else ring._DequeRing)
self.assertIs(ring.Ring, ring._CFFIRing) self.assertIs(ring.Ring, expected)
else:
self.assertIs(ring.Ring, ring._DequeRing)
class DummyPersistent(object): class DummyPersistent(object):
......
...@@ -31,7 +31,7 @@ class DummyPersistent(object): ...@@ -31,7 +31,7 @@ class DummyPersistent(object):
if oid is None: if oid is None:
self._p_oid = self._next_oid() self._p_oid = self._next_oid()
def __repr__(self): def __repr__(self): # pragma: no cover
return "<Dummy %r>" % self._p_oid return "<Dummy %r>" % self._p_oid
class _Ring_Base(object): class _Ring_Base(object):
......
...@@ -63,9 +63,11 @@ class pyTimeStampTests(unittest.TestCase): ...@@ -63,9 +63,11 @@ class pyTimeStampTests(unittest.TestCase):
(1, 2, 3, 4, 5), (1, 2, 3, 4, 5),
('1', '2', '3', '4', '5', '6'), ('1', '2', '3', '4', '5', '6'),
(1, 2, 3, 4, 5, 6, 7), (1, 2, 3, 4, 5, 6, 7),
(b'123',),
] ]
for args in BAD_ARGS: for args in BAD_ARGS:
self.assertRaises((TypeError, ValueError), self._makeOne, *args) with self.assertRaises((TypeError, ValueError)):
self._makeOne(*args)
def test_ctor_from_invalid_strings(self): def test_ctor_from_invalid_strings(self):
BAD_ARGS = ['' BAD_ARGS = [''
...@@ -80,13 +82,12 @@ class pyTimeStampTests(unittest.TestCase): ...@@ -80,13 +82,12 @@ class pyTimeStampTests(unittest.TestCase):
self.assertRaises((TypeError, ValueError), self._makeOne, *args) self.assertRaises((TypeError, ValueError), self._makeOne, *args)
def test_ctor_from_string(self): def test_ctor_from_string(self):
from persistent.timestamp import _makeOctets
from persistent.timestamp import _makeUTC from persistent.timestamp import _makeUTC
ZERO = _makeUTC(1900, 1, 1, 0, 0, 0) ZERO = _makeUTC(1900, 1, 1, 0, 0, 0)
EPOCH = _makeUTC(1970, 1, 1, 0, 0, 0) EPOCH = _makeUTC(1970, 1, 1, 0, 0, 0)
DELTA = ZERO - EPOCH DELTA = ZERO - EPOCH
DELTA_SECS = DELTA.days * 86400 + DELTA.seconds DELTA_SECS = DELTA.days * 86400 + DELTA.seconds
SERIAL = _makeOctets('\x00' * 8) SERIAL = b'\x00' * 8
ts = self._makeOne(SERIAL) ts = self._makeOne(SERIAL)
self.assertEqual(ts.raw(), SERIAL) self.assertEqual(ts.raw(), SERIAL)
self.assertEqual(ts.year(), 1900) self.assertEqual(ts.year(), 1900)
...@@ -104,13 +105,12 @@ class pyTimeStampTests(unittest.TestCase): ...@@ -104,13 +105,12 @@ class pyTimeStampTests(unittest.TestCase):
self.assertEqual(before.timeTime(), 1297867042.80544) self.assertEqual(before.timeTime(), 1297867042.80544)
def test_ctor_from_elements(self): def test_ctor_from_elements(self):
from persistent.timestamp import _makeOctets
from persistent.timestamp import _makeUTC from persistent.timestamp import _makeUTC
ZERO = _makeUTC(1900, 1, 1, 0, 0, 0) ZERO = _makeUTC(1900, 1, 1, 0, 0, 0)
EPOCH = _makeUTC(1970, 1, 1, 0, 0, 0) EPOCH = _makeUTC(1970, 1, 1, 0, 0, 0)
DELTA = ZERO - EPOCH DELTA = ZERO - EPOCH
DELTA_SECS = DELTA.days * 86400 + DELTA.seconds DELTA_SECS = DELTA.days * 86400 + DELTA.seconds
SERIAL = _makeOctets('\x00' * 8) SERIAL = b'\x00' * 8
ts = self._makeOne(1900, 1, 1, 0, 0, 0.0) ts = self._makeOne(1900, 1, 1, 0, 0, 0.0)
self.assertEqual(ts.raw(), SERIAL) self.assertEqual(ts.raw(), SERIAL)
self.assertEqual(ts.year(), 1900) self.assertEqual(ts.year(), 1900)
...@@ -122,9 +122,8 @@ class pyTimeStampTests(unittest.TestCase): ...@@ -122,9 +122,8 @@ class pyTimeStampTests(unittest.TestCase):
self.assertEqual(ts.timeTime(), DELTA_SECS) self.assertEqual(ts.timeTime(), DELTA_SECS)
def test_laterThan_invalid(self): def test_laterThan_invalid(self):
from persistent.timestamp import _makeOctets
ERRORS = (ValueError, TypeError) ERRORS = (ValueError, TypeError)
SERIAL = _makeOctets('\x01' * 8) SERIAL = b'\x01' * 8
ts = self._makeOne(SERIAL) ts = self._makeOne(SERIAL)
self.assertRaises(ERRORS, ts.laterThan, None) self.assertRaises(ERRORS, ts.laterThan, None)
self.assertRaises(ERRORS, ts.laterThan, '') self.assertRaises(ERRORS, ts.laterThan, '')
...@@ -134,26 +133,23 @@ class pyTimeStampTests(unittest.TestCase): ...@@ -134,26 +133,23 @@ class pyTimeStampTests(unittest.TestCase):
self.assertRaises(ERRORS, ts.laterThan, object()) self.assertRaises(ERRORS, ts.laterThan, object())
def test_laterThan_self_is_earlier(self): def test_laterThan_self_is_earlier(self):
from persistent.timestamp import _makeOctets SERIAL1 = b'\x01' * 8
SERIAL1 = _makeOctets('\x01' * 8) SERIAL2 = b'\x02' * 8
SERIAL2 = _makeOctets('\x02' * 8)
ts1 = self._makeOne(SERIAL1) ts1 = self._makeOne(SERIAL1)
ts2 = self._makeOne(SERIAL2) ts2 = self._makeOne(SERIAL2)
later = ts1.laterThan(ts2) later = ts1.laterThan(ts2)
self.assertEqual(later.raw(), _makeOctets('\x02' * 7 + '\x03')) self.assertEqual(later.raw(), b'\x02' * 7 + b'\x03')
def test_laterThan_self_is_later(self): def test_laterThan_self_is_later(self):
from persistent.timestamp import _makeOctets SERIAL1 = b'\x01' * 8
SERIAL1 = _makeOctets('\x01' * 8) SERIAL2 = b'\x02' * 8
SERIAL2 = _makeOctets('\x02' * 8)
ts1 = self._makeOne(SERIAL1) ts1 = self._makeOne(SERIAL1)
ts2 = self._makeOne(SERIAL2) ts2 = self._makeOne(SERIAL2)
later = ts2.laterThan(ts1) later = ts2.laterThan(ts1)
self.assertTrue(later is ts2) self.assertTrue(later is ts2)
def test_repr(self): def test_repr(self):
from persistent.timestamp import _makeOctets SERIAL = b'\x01' * 8
SERIAL = _makeOctets('\x01' * 8)
ts = self._makeOne(SERIAL) ts = self._makeOne(SERIAL)
self.assertEqual(repr(ts), repr(SERIAL)) self.assertEqual(repr(ts), repr(SERIAL))
...@@ -163,14 +159,20 @@ class pyTimeStampTests(unittest.TestCase): ...@@ -163,14 +159,20 @@ class pyTimeStampTests(unittest.TestCase):
# Check the corner cases when comparing non-comparable types # Check the corner cases when comparing non-comparable types
ts = self._makeOne(2011, 2, 16, 14, 37, 22.0) ts = self._makeOne(2011, 2, 16, 14, 37, 22.0)
def check_py2(op, passes): def check_common(op, passes):
if passes == 'neither': if passes == 'neither':
self.assertFalse(op(ts, None)) self.assertFalse(op(ts, None))
self.assertFalse(op(None, ts)) self.assertFalse(op(None, ts))
elif passes == 'both': return True
if passes == 'both':
self.assertTrue(op(ts, None)) self.assertTrue(op(ts, None))
self.assertTrue(op(None, ts)) self.assertTrue(op(None, ts))
elif passes == 'first': return True
return False
def check_py2(op, passes): # pragma: no cover
if passes == 'first':
self.assertTrue(op(ts, None)) self.assertTrue(op(ts, None))
self.assertFalse(op(None, ts)) self.assertFalse(op(None, ts))
else: else:
...@@ -178,13 +180,6 @@ class pyTimeStampTests(unittest.TestCase): ...@@ -178,13 +180,6 @@ class pyTimeStampTests(unittest.TestCase):
self.assertTrue(op(None, ts)) self.assertTrue(op(None, ts))
def check_py3(op, passes): def check_py3(op, passes):
if passes == 'neither':
self.assertFalse(op(ts, None))
self.assertFalse(op(None, ts))
elif passes == 'both':
self.assertTrue(op(ts, None))
self.assertTrue(op(None, ts))
else:
self.assertRaises(TypeError, op, ts, None) self.assertRaises(TypeError, op, ts, None)
self.assertRaises(TypeError, op, None, ts) self.assertRaises(TypeError, op, None, ts)
...@@ -197,6 +192,7 @@ class pyTimeStampTests(unittest.TestCase): ...@@ -197,6 +192,7 @@ class pyTimeStampTests(unittest.TestCase):
('eq', 'neither'), ('eq', 'neither'),
('ne', 'both')): ('ne', 'both')):
op = getattr(operator, op_name) op = getattr(operator, op_name)
if not check_common(op, passes):
check(op, passes) check(op, passes)
...@@ -223,7 +219,7 @@ class PyAndCComparisonTests(unittest.TestCase): ...@@ -223,7 +219,7 @@ class PyAndCComparisonTests(unittest.TestCase):
# it to test matching # it to test matching
yield self.now_ts_args yield self.now_ts_args
for i in range(2000): for i in range(2000):
yield self.now_ts_args[:-1] + (self.now_ts_args[-1] + (i % 60.0)/100.0 , ) yield self.now_ts_args[:-1] + (self.now_ts_args[-1] + (i % 60.0)/100.0, )
def _makeC(self, *args, **kwargs): def _makeC(self, *args, **kwargs):
from persistent.timestamp import TimeStamp from persistent.timestamp import TimeStamp
...@@ -304,7 +300,7 @@ class PyAndCComparisonTests(unittest.TestCase): ...@@ -304,7 +300,7 @@ class PyAndCComparisonTests(unittest.TestCase):
# in hash() on 32-bit platforms # in hash() on 32-bit platforms
if not self._is_jython: if not self._is_jython:
self.assertEqual(py.__hash__(), bit_64_hash) self.assertEqual(py.__hash__(), bit_64_hash)
else: else: # pragma: no cover
# Jython 2.7's ctypes module doesn't properly # Jython 2.7's ctypes module doesn't properly
# implement the 'value' attribute by truncating. # implement the 'value' attribute by truncating.
# (It does for native calls, but not visibly to Python). # (It does for native calls, but not visibly to Python).
...@@ -318,15 +314,13 @@ class PyAndCComparisonTests(unittest.TestCase): ...@@ -318,15 +314,13 @@ class PyAndCComparisonTests(unittest.TestCase):
MUT._MAXINT = orig_maxint MUT._MAXINT = orig_maxint
if orig_c_long is not None: if orig_c_long is not None:
MUT.c_long = orig_c_long MUT.c_long = orig_c_long
else: else: # pragma: no cover
del MUT.c_long del MUT.c_long
# These are *usually* aliases, but aren't required # These are *usually* aliases, but aren't required
# to be (and aren't under Jython 2.7). # to be (and aren't under Jython 2.7).
if is_32_bit_hash: expected_hash = bit_32_hash if is_32_bit_hash else bit_64_hash
self.assertEqual(py.__hash__(), bit_32_hash) self.assertEqual(py.__hash__(), expected_hash)
else:
self.assertEqual(py.__hash__(), bit_64_hash)
def test_hash_equal_constants(self): def test_hash_equal_constants(self):
# The simple constants make it easier to diagnose # The simple constants make it easier to diagnose
...@@ -350,46 +344,36 @@ class PyAndCComparisonTests(unittest.TestCase): ...@@ -350,46 +344,36 @@ class PyAndCComparisonTests(unittest.TestCase):
# overflow kicks in here on 32-bit platforms # overflow kicks in here on 32-bit platforms
c, py = self._make_C_and_Py(b'\x00\x00\x00\x00\x00\x01\x00\x00') c, py = self._make_C_and_Py(b'\x00\x00\x00\x00\x00\x01\x00\x00')
if is_32_bit: expected = -721379967 if is_32_bit else 1000006000001
self.assertEqual(hash(c), -721379967) self.assertEqual(hash(c), expected)
else:
self.assertEqual(hash(c), 1000006000001)
self.assertEqual(hash(c), hash(py)) self.assertEqual(hash(c), hash(py))
c, py = self._make_C_and_Py(b'\x00\x00\x00\x00\x01\x00\x00\x00') c, py = self._make_C_and_Py(b'\x00\x00\x00\x00\x01\x00\x00\x00')
if is_32_bit: expected = 583896275 if is_32_bit else 1000009000027000019
self.assertEqual(hash(c), 583896275) self.assertEqual(hash(c), expected)
else:
self.assertEqual(hash(c), 1000009000027000019)
self.assertEqual(hash(c), hash(py)) self.assertEqual(hash(c), hash(py))
# Overflow kicks in at this point on 64-bit platforms # Overflow kicks in at this point on 64-bit platforms
c, py = self._make_C_and_Py(b'\x00\x00\x00\x01\x00\x00\x00\x00') c, py = self._make_C_and_Py(b'\x00\x00\x00\x01\x00\x00\x00\x00')
if is_32_bit: expected = 1525764953 if is_32_bit else -4442925868394654887
self.assertEqual(hash(c), 1525764953) self.assertEqual(hash(c), expected)
else:
self.assertEqual(hash(c), -4442925868394654887)
self.assertEqual(hash(c), hash(py)) self.assertEqual(hash(c), hash(py))
c, py = self._make_C_and_Py(b'\x00\x00\x01\x00\x00\x00\x00\x00') c, py = self._make_C_and_Py(b'\x00\x00\x01\x00\x00\x00\x00\x00')
if is_32_bit: expected = -429739973 if is_32_bit else -3993531167153147845
self.assertEqual(hash(c), -429739973) self.assertEqual(hash(c), expected)
else:
self.assertEqual(hash(c), -3993531167153147845)
self.assertEqual(hash(c), hash(py)) self.assertEqual(hash(c), hash(py))
c, py = self._make_C_and_Py(b'\x01\x00\x00\x00\x00\x00\x00\x00') c, py = self._make_C_and_Py(b'\x01\x00\x00\x00\x00\x00\x00\x00')
if is_32_bit: expected = 263152323 if is_32_bit else -3099646879006235965
self.assertEqual(hash(c), 263152323) self.assertEqual(hash(c), expected)
else:
self.assertEqual(hash(c), -3099646879006235965)
self.assertEqual(hash(c), hash(py)) self.assertEqual(hash(c), hash(py))
def test_ordering(self): def test_ordering(self):
small_c = self._makeC(b'\x00\x00\x00\x00\x00\x00\x00\x01') small_c = self._makeC(b'\x00\x00\x00\x00\x00\x00\x00\x01')
big_c = self._makeC(b'\x01\x00\x00\x00\x00\x00\x00\x00')
small_py = self._makePy(b'\x00\x00\x00\x00\x00\x00\x00\x01') small_py = self._makePy(b'\x00\x00\x00\x00\x00\x00\x00\x01')
big_c = self._makeC(b'\x01\x00\x00\x00\x00\x00\x00\x00')
big_py = self._makePy(b'\x01\x00\x00\x00\x00\x00\x00\x00') big_py = self._makePy(b'\x01\x00\x00\x00\x00\x00\x00\x00')
self.assertTrue(small_py < big_py) self.assertTrue(small_py < big_py)
...@@ -423,7 +407,7 @@ def test_suite(): ...@@ -423,7 +407,7 @@ def test_suite():
try: try:
from persistent.timestamp import pyTimeStamp from persistent.timestamp import pyTimeStamp
from persistent.timestamp import TimeStamp from persistent.timestamp import TimeStamp
except ImportError: except ImportError: # pragma: no cover
pass pass
else: else:
if pyTimeStamp != TimeStamp: if pyTimeStamp != TimeStamp:
......
...@@ -317,7 +317,7 @@ class PersistentWeakKeyDictionaryTests(unittest.TestCase): ...@@ -317,7 +317,7 @@ class PersistentWeakKeyDictionaryTests(unittest.TestCase):
self.assertTrue(target[key] is value) self.assertTrue(target[key] is value)
def _makeTarget(oid='OID', **kw): def _makeTarget(oid='OID'):
from persistent import Persistent from persistent import Persistent
from persistent._compat import _b from persistent._compat import _b
class Derived(Persistent): class Derived(Persistent):
...@@ -325,11 +325,9 @@ def _makeTarget(oid='OID', **kw): ...@@ -325,11 +325,9 @@ def _makeTarget(oid='OID', **kw):
return hash(self._p_oid) return hash(self._p_oid)
def __eq__(self, other): def __eq__(self, other):
return self._p_oid == other._p_oid return self._p_oid == other._p_oid
def __repr__(self): def __repr__(self): # pragma: no cover
return 'Derived: %s' % self._p_oid return 'Derived: %s' % self._p_oid
derived = Derived() derived = Derived()
for k, v in kw.items():
setattr(derived, k, v)
derived._p_oid = _b(oid) derived._p_oid = _b(oid)
return derived return derived
...@@ -341,7 +339,4 @@ def _makeJar(): ...@@ -341,7 +339,4 @@ def _makeJar():
return _Jar() return _Jar()
def test_suite(): def test_suite():
return unittest.TestSuite(( return unittest.defaultTestLoader.loadTestsFromName(__name__)
unittest.makeSuite(WeakRefTests),
unittest.makeSuite(PersistentWeakKeyDictionaryTests),
))
...@@ -18,19 +18,9 @@ class ResettingJar(object): ...@@ -18,19 +18,9 @@ class ResettingJar(object):
obj._p_jar = self obj._p_jar = self
self.cache[obj._p_oid] = obj self.cache[obj._p_oid] = obj
def close(self):
pass
# the following methods must be implemented to be a jar # the following methods must be implemented to be a jar
def setklassstate(self):
# I don't know what this method does, but the pickle cache
# constructor calls it.
pass
def register(self, obj):
self.registered[obj] = 1
def setstate(self, obj): def setstate(self, obj):
# Trivial setstate() implementation that just re-initializes # Trivial setstate() implementation that just re-initializes
# the object. This isn't what setstate() is supposed to do, # the object. This isn't what setstate() is supposed to do,
...@@ -56,8 +46,6 @@ class RememberingJar(object): ...@@ -56,8 +46,6 @@ class RememberingJar(object):
self.obj = obj self.obj = obj
self.remembered = obj.__getstate__() self.remembered = obj.__getstate__()
def close(self):
pass
def fake_commit(self): def fake_commit(self):
self.remembered = self.obj.__getstate__() self.remembered = self.obj.__getstate__()
...@@ -65,11 +53,6 @@ class RememberingJar(object): ...@@ -65,11 +53,6 @@ class RememberingJar(object):
# the following methods must be implemented to be a jar # the following methods must be implemented to be a jar
def setklassstate(self):
# I don't know what this method does, but the pickle cache
# constructor calls it.
pass
def register(self, obj): def register(self, obj):
self.registered[obj] = 1 self.registered[obj] = 1
...@@ -79,4 +62,3 @@ class RememberingJar(object): ...@@ -79,4 +62,3 @@ class RememberingJar(object):
# This isn't what setstate() is supposed to do, # This isn't what setstate() is supposed to do,
# but it suffices for the tests. # but it suffices for the tests.
obj.__setstate__(self.remembered) obj.__setstate__(self.remembered)
...@@ -18,16 +18,12 @@ import math ...@@ -18,16 +18,12 @@ import math
import struct import struct
import sys import sys
from persistent._compat import PURE_PYTHON
_RAWTYPE = bytes _RAWTYPE = bytes
_MAXINT = sys.maxsize _MAXINT = sys.maxsize
def _makeOctets(s): _ZERO = b'\x00' * 8
if sys.version_info < (3,):
return bytes(s)
return bytes(s, 'ascii') #pragma NO COVERAGE
_ZERO = _makeOctets('\x00' * 8)
try: try:
# Make sure to overflow and wraparound just # Make sure to overflow and wraparound just
...@@ -175,7 +171,7 @@ class pyTimeStamp(object): ...@@ -175,7 +171,7 @@ class pyTimeStamp(object):
x = _wraparound(x) x = _wraparound(x)
if x == -1: #pragma: no cover if x == -1: # pragma: no cover
# The C version has this condition, but it's not clear # The C version has this condition, but it's not clear
# why; it's also not immediately obvious what bytestring # why; it's also not immediately obvious what bytestring
# would generate this---hence the no-cover # would generate this---hence the no-cover
...@@ -211,6 +207,8 @@ class pyTimeStamp(object): ...@@ -211,6 +207,8 @@ class pyTimeStamp(object):
try: try:
from persistent._timestamp import TimeStamp from persistent._timestamp import TimeStamp as CTimeStamp
except ImportError: #pragma NO COVER except ImportError: # pragma: no cover
TimeStamp = pyTimeStamp CTimeStamp = None
TimeStamp = pyTimeStamp if PURE_PYTHON or CTimeStamp is None else CTimeStamp
...@@ -83,7 +83,7 @@ class PersistentWeakKeyDictionary(Persistent): ...@@ -83,7 +83,7 @@ class PersistentWeakKeyDictionary(Persistent):
self.update(adict) self.update(adict)
# XXX 'kwargs' is pointless, because keys must be strings, but we # XXX 'kwargs' is pointless, because keys must be strings, but we
# are going to try (and fail) to wrap a WeakRef around them. # are going to try (and fail) to wrap a WeakRef around them.
if kwargs: #pragma NO COVER if kwargs: # pragma: no cover
self.update(kwargs) self.update(kwargs)
def __getstate__(self): def __getstate__(self):
......
...@@ -116,6 +116,7 @@ setup(name='persistent', ...@@ -116,6 +116,7 @@ setup(name='persistent',
'test': [ 'test': [
'zope.testrunner', 'zope.testrunner',
"cffi ; platform_python_implementation == 'CPython'", "cffi ; platform_python_implementation == 'CPython'",
'manuel',
], ],
'testing': (), 'testing': (),
'docs': [ 'docs': [
......
...@@ -36,7 +36,6 @@ deps = ...@@ -36,7 +36,6 @@ deps =
{[testenv]deps} {[testenv]deps}
coverage coverage
setenv = setenv =
PURE_PYTHON = 1
USING_CFFI = 1 USING_CFFI = 1
[testenv:docs] [testenv:docs]
......
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