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:
from persistent.cPersistence import Persistent
from persistent.cPersistence import GHOST
from persistent.cPersistence import UPTODATE
from persistent.cPersistence import CHANGED
from persistent.cPersistence import STICKY
from persistent.cPersistence import simple_new
except ImportError: #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
else:
from persistent._compat import copy_reg
copy_reg.constructor(simple_new)
# Make an interface declaration for Persistent, if zope.interface
# is available. Note that the Python version already does this.
try:
from zope.interface import classImplements
except ImportError: #pragma NO COVER
pass
else:
from persistent.interfaces import IPersistent
classImplements(Persistent, IPersistent)
try: __all__ = [
from persistent.cPickleCache import PickleCache 'IPersistent',
except ImportError: #pragma NO COVER 'Persistent',
from persistent.picklecache import PickleCache 'GHOST',
'UPTODATE',
'CHANGED',
'STICKY',
'PickleCache',
'TimeStamp',
]
from persistent._compat import PURE_PYTHON
from persistent.interfaces import IPersistent
try: import persistent.timestamp as TimeStamp
import persistent.TimeStamp
except ImportError: #pragma NO COVER from persistent import persistence as pyPersistence
import persistent.timestamp as TimeStamp from persistent import picklecache as pyPickleCache
import sys
sys.modules['persistent.TimeStamp' try:
] = sys.modules['persistent.timestamp'] # Be careful not to shadow the modules
else: #pragma NO COVER from persistent import cPersistence as _cPersistence
from persistent.persistence import Persistent from persistent import cPickleCache as _cPickleCache
from persistent.persistence import GHOST except ImportError: # pragma: no cover
from persistent.persistence import UPTODATE _cPersistence = None
from persistent.persistence import CHANGED _cPickleCache = None
from persistent.persistence import STICKY else:
from persistent.picklecache import PickleCache # Make an interface declaration for Persistent
import persistent.timestamp as TimeStamp # Note that the Python version already does this.
import sys from zope.interface import classImplements
sys.modules['persistent.TimeStamp'] = sys.modules['persistent.timestamp'] classImplements(_cPersistence.Persistent, IPersistent)
_persistence = pyPersistence if PURE_PYTHON or _cPersistence is None else _cPersistence
_picklecache = pyPickleCache if PURE_PYTHON or _cPickleCache is None else _cPickleCache
Persistent = _persistence.Persistent
GHOST = _persistence.GHOST
UPTODATE = _persistence.UPTODATE
CHANGED = _persistence.CHANGED
STICKY = _persistence.STICKY
PickleCache = _picklecache.PickleCache
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,13 +46,17 @@ class PersistentList(UserList, persistent.Persistent): ...@@ -49,13 +46,17 @@ class PersistentList(UserList, persistent.Persistent):
self.__super_delitem(i) self.__super_delitem(i)
self._p_changed = 1 self._p_changed = 1
def __setslice__(self, i, j, other): if PYTHON2: # pragma: no cover
self.__super_setslice(i, j, other) __super_setslice = UserList.__setslice__
self._p_changed = 1 __super_delslice = UserList.__delslice__
def __delslice__(self, i, j): def __setslice__(self, i, j, other):
self.__super_delslice(i, j) self.__super_setslice(i, j, other)
self._p_changed = 1 self._p_changed = 1
def __delslice__(self, i, j):
self.__super_delslice(i, j)
self._p_changed = 1
def __iadd__(self, other): def __iadd__(self, other):
L = self.__super_iadd(other) L = self.__super_iadd(other)
...@@ -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,9 +35,8 @@ class OverridesGetattr(Persistent): ...@@ -35,9 +35,8 @@ 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
class VeryPrivate(Persistent): class VeryPrivate(Persistent):
......
...@@ -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:
if PYTHON2: cmp
def mycmp(a, b): except NameError:
r = cmp(a, b) def cmp(a, b):
if r < 0: return -1 if a == b:
if r > 0: return 1 return 0
return r if a < b:
return -1
all = [l0, l1, l2, u, u0, u1, u2, uu, uu0, uu1, uu2] return 1
for a in all:
for b in all: def mycmp(a, b):
eq(mycmp(a, b), mycmp(len(a), len(b)), r = cmp(a, b)
"mycmp(a, b) == mycmp(len(a), len(b))") if r < 0:
return -1
if r > 0:
return 1
return r
to_test = [l0, l1, l2, u, u0, u1, u2, uu, uu0, uu1, uu2]
for a in to_test:
for b in to_test:
eq(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:
if PYTHON2: cmp
def mycmp(a, b): except NameError:
r = cmp(a, b) def cmp(a, b):
if r < 0: return -1 if a == b:
if r > 0: return 1 return 0
return r if hasattr(a, 'items'):
a = sorted(a.items())
all = [l0, l1, l2, u, u0, u1, u2, uu, uu0, uu1, uu2] b = sorted(b.items())
for a in all: if a < b:
for b in all: return -1
eq(mycmp(a, b), mycmp(len(a), len(b)), return 1
"mycmp(a, b) == mycmp(len(a), len(b))")
def mycmp(a, b):
r = cmp(a, b)
if r < 0:
return -1
if r > 0:
return 1
return r
to_test = [l0, l1, l2, u, u0, u1, u2, uu, uu0, uu1, uu2]
for a in to_test:
for b in to_test:
eq(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),
...@@ -921,7 +926,7 @@ class _Persistent_Base(object): ...@@ -921,7 +926,7 @@ class _Persistent_Base(object):
from persistent.persistence import _INITIAL_SERIAL from persistent.persistence import _INITIAL_SERIAL
inst = self._makeOne() inst = self._makeOne()
self.assertRaises((ValueError, TypeError), self.assertRaises((ValueError, TypeError),
inst.__setstate__, {'bogus': 1}) inst.__setstate__, {'bogus': 1})
self.assertEqual(inst._p_jar, None) self.assertEqual(inst._p_jar, None)
self.assertEqual(inst._p_oid, None) self.assertEqual(inst._p_oid, None)
self.assertEqual(inst._p_serial, _INITIAL_SERIAL) self.assertEqual(inst._p_serial, _INITIAL_SERIAL)
...@@ -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,15 +180,8 @@ class pyTimeStampTests(unittest.TestCase): ...@@ -178,15 +180,8 @@ 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.assertRaises(TypeError, op, ts, None)
self.assertFalse(op(ts, None)) self.assertRaises(TypeError, op, None, ts)
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, None, ts)
check = check_py2 if PYTHON2 else check_py3 check = check_py2 if PYTHON2 else check_py3
...@@ -197,7 +192,8 @@ class pyTimeStampTests(unittest.TestCase): ...@@ -197,7 +192,8 @@ class pyTimeStampTests(unittest.TestCase):
('eq', 'neither'), ('eq', 'neither'),
('ne', 'both')): ('ne', 'both')):
op = getattr(operator, op_name) op = getattr(operator, op_name)
check(op, passes) if not check_common(op, passes):
check(op, passes)
class TimeStampTests(pyTimeStampTests): class TimeStampTests(pyTimeStampTests):
...@@ -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:
......
...@@ -315,9 +315,9 @@ class PersistentWeakKeyDictionaryTests(unittest.TestCase): ...@@ -315,9 +315,9 @@ class PersistentWeakKeyDictionaryTests(unittest.TestCase):
target = self._makeOne(None) target = self._makeOne(None)
target.update(source) target.update(source)
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