[Python-modules-commits] [python-persistent] 02/15: Import python-persistent_4.2.2.orig.tar.gz
Barry Warsaw
barry at moszumanska.debian.org
Fri Jan 6 21:13:38 UTC 2017
This is an automated email from the git hooks/post-receive script.
barry pushed a commit to branch master
in repository python-persistent.
commit 3b72c0c67086e25ce401b6cb4f1925a8b6e07e24
Author: Julien Muchembled <jm at jmuchemb.eu>
Date: Thu Dec 1 22:16:34 2016 +0100
Import python-persistent_4.2.2.orig.tar.gz
---
.gitignore | 17 ---
.travis.yml | 54 ++++++--
CHANGES.rst | 31 +++++
PKG-INFO | 51 +++++++-
README.rst | 15 +++
bootstrap.py | 51 +++++---
ez_setup.py | 234 -----------------------------------
persistent.egg-info/PKG-INFO | 51 +++++++-
persistent.egg-info/SOURCES.txt | 3 +-
persistent/_timestamp.c | 5 +
persistent/cPersistence.c | 56 ++++++++-
persistent/persistence.py | 16 ++-
persistent/tests/test_persistence.py | 51 ++++++++
persistent/tests/test_timestamp.py | 120 +++++++++---------
persistent/tests/test_wref.py | 2 +
persistent/timestamp.py | 16 ++-
rtd.txt | 1 +
setup.py | 5 +-
tox.ini | 18 +--
19 files changed, 437 insertions(+), 360 deletions(-)
diff --git a/.gitignore b/.gitignore
deleted file mode 100644
index 28c5025..0000000
--- a/.gitignore
+++ /dev/null
@@ -1,17 +0,0 @@
-*.pyc
-*.so
-__pycache__
-build
-docs/_build
-bin
-develop-eggs
-eggs
-parts
-.tox
-.coverage
-nosetests.xml
-coverage.xml
-*.egg-info
-.installed.cfg
-.dir-locals.el
-dist
diff --git a/.travis.yml b/.travis.yml
index 0bb0ce3..24a86f9 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,16 +1,50 @@
language: python
sudo: false
-python:
- - 2.6
- - 2.7
- - 3.2
- - 3.3
- - 3.4
- - pypy
- - pypy3
+matrix:
+ include:
+ - os: linux
+ python: 2.7
+ - os: linux
+ python: 3.3
+ - os: linux
+ python: 3.4
+ - os: linux
+ python: 3.5
+ - os: linux
+ python: pypy
+ - os: linux
+ python: pypy3
+ - os: osx
+ language: generic
+ env: TERRYFY_PYTHON='homebrew 2'
+ - os: osx
+ language: generic
+ env: TERRYFY_PYTHON='macpython 3.4'
+ - os: osx
+ language: generic
+ env: TERRYFY_PYTHON='homebrew 3.5'
+before_install:
+ - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then git clone https://github.com/MacPython/terryfy; 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 [[ "$TERRYFY_PYTHON" == "homebrew 3" ]]; then alias pip=`which pip3` ; fi
install:
- - pip install . --use-mirrors
+ - pip install -e .
script:
- - python setup.py test -q
+ - python setup.py -q test -q
notifications:
email: false
+after_success:
+ - echo [distutils] > ~/.pypirc
+ - echo index-servers = pypi >> ~/.pypirc
+ - echo [pypi] >> ~/.pypirc
+ - echo repository=https://pypi.python.org/pypi >> ~/.pypirc
+ - echo username=zope.wheelbuilder >> ~/.pypirc
+ - echo password=$PYPIPASSWORD >> ~/.pypirc
+ - if [[ $TRAVIS_TAG && "$TRAVIS_OS_NAME" == "osx" ]]; then pip install twine; fi
+ - if [[ $TRAVIS_TAG && "$TRAVIS_OS_NAME" == "osx" ]]; then python setup.py bdist_wheel; fi
+ - if [[ $TRAVIS_TAG && "$TRAVIS_OS_NAME" == "osx" ]]; then twine upload dist/*; fi
+
+env:
+ global:
+ secure: "avoDyPgppusNzldim5fq35sk7HAn3B8zs2KgAe+8Yr3MDpFaxNV96rhNkTdHgsNNw4N+PVew1sFUxLY7HzACyywLFPUPT+YMRcPeqiuekkQoQxatYR0dEfHrxPpNyvXRxIV+nrKTEaIxQNyDcJcyRw6K7NSNxuu2NR6Dj+xJmKY="
diff --git a/CHANGES.rst b/CHANGES.rst
index d698a24..eae8c9d 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -1,6 +1,37 @@
``persistent`` Changelog
========================
+4.2.2 (2016-11-29)
+------------------
+
+- Drop use of ``ctypes`` for determining maximum integer size, to increase
+ pure-Python compatibility.
+
+- Ensure that ``__slots__`` attributes are cleared when a persistent
+ object is ghostified. (This excluses classes that override
+ ``__new__``. See
+ https://github.com/zopefoundation/persistent/wiki/Notes_on_state_new_and_slots
+ if you're curious.)
+
+4.2.1 (2016-05-26)
+------------------
+
+- Fix the hashcode of C ``TimeStamp`` objects on 64-bit Python 3 on
+ Windows.
+
+4.2.0 (2016-05-05)
+------------------
+
+- Fixed the Python(/PYPY) implementation ``TimeStamp.timeTime`` method
+ to have subsecond precision.
+
+- When testing ``PURE_PYTHON`` environments under ``tox``, avoid poisoning
+ the user's global wheel cache.
+
+- Add support for Python 3.5.
+
+- Drop support for Python 2.6 and 3.2.
+
4.1.1 (2015-06-02)
------------------
diff --git a/PKG-INFO b/PKG-INFO
index 3396a8d..f7fa1d0 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: persistent
-Version: 4.1.1
+Version: 4.2.2
Summary: Translucent persistent objects
Home-page: http://www.zope.org/Products/ZODB
Author: Zope Corporation
@@ -9,6 +9,21 @@ License: ZPL 2.1
Description: ``persistent``: automatic persistence for Python objects
=========================================================
+ .. image:: https://travis-ci.org/zopefoundation/persistent.png?branch=master
+ :target: https://travis-ci.org/zopefoundation/persistent
+
+ .. image:: https://readthedocs.org/projects/persistent/badge/?version=latest
+ :target: http://persistent.readthedocs.org/en/latest/
+ :alt: Documentation Status
+
+ .. image:: https://img.shields.io/pypi/v/persistent.svg
+ :target: https://pypi.python.org/pypi/persistent
+ :alt: PyPI
+
+ .. image:: https://img.shields.io/pypi/pyversions/persistent.svg
+ :target: https://pypi.python.org/pypi/persistent
+ :alt: Python versions
+
This package contains a generic persistence implementation for Python. It
forms the core protocol for making objects interact "transparently" with
a database such as the ZODB.
@@ -26,6 +41,37 @@ Description: ``persistent``: automatic persistence for Python objects
``persistent`` Changelog
========================
+ 4.2.2 (2016-11-29)
+ ------------------
+
+ - Drop use of ``ctypes`` for determining maximum integer size, to increase
+ pure-Python compatibility.
+
+ - Ensure that ``__slots__`` attributes are cleared when a persistent
+ object is ghostified. (This excluses classes that override
+ ``__new__``. See
+ https://github.com/zopefoundation/persistent/wiki/Notes_on_state_new_and_slots
+ if you're curious.)
+
+ 4.2.1 (2016-05-26)
+ ------------------
+
+ - Fix the hashcode of C ``TimeStamp`` objects on 64-bit Python 3 on
+ Windows.
+
+ 4.2.0 (2016-05-05)
+ ------------------
+
+ - Fixed the Python(/PYPY) implementation ``TimeStamp.timeTime`` method
+ to have subsecond precision.
+
+ - When testing ``PURE_PYTHON`` environments under ``tox``, avoid poisoning
+ the user's global wheel cache.
+
+ - Add support for Python 3.5.
+
+ - Drop support for Python 2.6 and 3.2.
+
4.1.1 (2015-06-02)
------------------
@@ -199,12 +245,11 @@ Classifier: Development Status :: 6 - Mature
Classifier: License :: OSI Approved :: Zope Public License
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 2
-Classifier: Programming Language :: Python :: 2.6
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3.2
Classifier: Programming Language :: Python :: 3.3
Classifier: Programming Language :: Python :: 3.4
+Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Programming Language :: Python :: Implementation :: PyPy
Classifier: Framework :: ZODB
diff --git a/README.rst b/README.rst
index 4678d0f..6b34a92 100644
--- a/README.rst
+++ b/README.rst
@@ -1,6 +1,21 @@
``persistent``: automatic persistence for Python objects
=========================================================
+.. image:: https://travis-ci.org/zopefoundation/persistent.png?branch=master
+ :target: https://travis-ci.org/zopefoundation/persistent
+
+.. image:: https://readthedocs.org/projects/persistent/badge/?version=latest
+ :target: http://persistent.readthedocs.org/en/latest/
+ :alt: Documentation Status
+
+.. image:: https://img.shields.io/pypi/v/persistent.svg
+ :target: https://pypi.python.org/pypi/persistent
+ :alt: PyPI
+
+.. image:: https://img.shields.io/pypi/pyversions/persistent.svg
+ :target: https://pypi.python.org/pypi/persistent
+ :alt: Python versions
+
This package contains a generic persistence implementation for Python. It
forms the core protocol for making objects interact "transparently" with
a database such as the ZODB.
diff --git a/bootstrap.py b/bootstrap.py
index a629566..a459921 100644
--- a/bootstrap.py
+++ b/bootstrap.py
@@ -25,7 +25,10 @@ import tempfile
from optparse import OptionParser
-tmpeggs = tempfile.mkdtemp()
+__version__ = '2015-07-01'
+# See zc.buildout's changelog if this version is up to date.
+
+tmpeggs = tempfile.mkdtemp(prefix='bootstrap-')
usage = '''\
[DESIRED PYTHON FOR BUILDOUT] bootstrap.py [options]
@@ -40,8 +43,9 @@ this script from going over the network.
'''
parser = OptionParser(usage=usage)
-parser.add_option("-v", "--version", help="use a specific zc.buildout version")
-
+parser.add_option("--version",
+ action="store_true", default=False,
+ help=("Return bootstrap.py version."))
parser.add_option("-t", "--accept-buildout-test-releases",
dest='accept_buildout_test_releases',
action="store_true", default=False,
@@ -59,25 +63,33 @@ parser.add_option("-f", "--find-links",
parser.add_option("--allow-site-packages",
action="store_true", default=False,
help=("Let bootstrap.py use existing site packages"))
+parser.add_option("--buildout-version",
+ help="Use a specific zc.buildout version")
parser.add_option("--setuptools-version",
- help="use a specific setuptools version")
-
+ help="Use a specific setuptools version")
+parser.add_option("--setuptools-to-dir",
+ help=("Allow for re-use of existing directory of "
+ "setuptools versions"))
options, args = parser.parse_args()
+if options.version:
+ print("bootstrap.py version %s" % __version__)
+ sys.exit(0)
+
######################################################################
# load/install setuptools
try:
- if options.allow_site_packages:
- import setuptools
- import pkg_resources
from urllib.request import urlopen
except ImportError:
from urllib2 import urlopen
ez = {}
-exec(urlopen('https://bootstrap.pypa.io/ez_setup.py').read(), ez)
+if os.path.exists('ez_setup.py'):
+ exec(open('ez_setup.py').read(), ez)
+else:
+ exec(urlopen('https://bootstrap.pypa.io/ez_setup.py').read(), ez)
if not options.allow_site_packages:
# ez_setup imports site, which adds site packages
@@ -88,12 +100,19 @@ if not options.allow_site_packages:
# We can't remove these reliably
if hasattr(site, 'getsitepackages'):
for sitepackage_path in site.getsitepackages():
- sys.path[:] = [x for x in sys.path if sitepackage_path not in x]
+ # Strip all site-packages directories from sys.path that
+ # are not sys.prefix; this is because on Windows
+ # sys.prefix is a site-package directory.
+ if sitepackage_path != sys.prefix:
+ sys.path[:] = [x for x in sys.path
+ if sitepackage_path not in x]
setup_args = dict(to_dir=tmpeggs, download_delay=0)
if options.setuptools_version is not None:
setup_args['version'] = options.setuptools_version
+if options.setuptools_to_dir is not None:
+ setup_args['to_dir'] = options.setuptools_to_dir
ez['use_setuptools'](**setup_args)
import setuptools
@@ -110,7 +129,12 @@ for path in sys.path:
ws = pkg_resources.working_set
+setuptools_path = ws.find(
+ pkg_resources.Requirement.parse('setuptools')).location
+
+# Fix sys.path here as easy_install.pth added before PYTHONPATH
cmd = [sys.executable, '-c',
+ 'import sys; sys.path[0:0] = [%r]; ' % setuptools_path +
'from setuptools.command.easy_install import main; main()',
'-mZqNxd', tmpeggs]
@@ -123,11 +147,8 @@ find_links = os.environ.get(
if find_links:
cmd.extend(['-f', find_links])
-setuptools_path = ws.find(
- pkg_resources.Requirement.parse('setuptools')).location
-
requirement = 'zc.buildout'
-version = options.version
+version = options.buildout_version
if version is None and not options.accept_buildout_test_releases:
# Figure out the most recent final version of zc.buildout.
import setuptools.package_index
@@ -167,7 +188,7 @@ if version:
cmd.append(requirement)
import subprocess
-if subprocess.call(cmd, env=dict(os.environ, PYTHONPATH=setuptools_path)) != 0:
+if subprocess.call(cmd) != 0:
raise Exception(
"Failed to execute command:\n%s" % repr(cmd)[1:-1])
diff --git a/ez_setup.py b/ez_setup.py
deleted file mode 100644
index 9e9b281..0000000
--- a/ez_setup.py
+++ /dev/null
@@ -1,234 +0,0 @@
-#!python
-"""Bootstrap setuptools installation
-
-If you want to use setuptools in your package's setup.py, just include this
-file in the same directory with it, and add this to the top of your setup.py::
-
- from ez_setup import use_setuptools
- use_setuptools()
-
-If you want to require a specific version of setuptools, set a download
-mirror, or use an alternate download directory, you can do so by supplying
-the appropriate options to ``use_setuptools()``.
-
-This file can also be run as a script to install or upgrade setuptools.
-"""
-import sys
-DEFAULT_VERSION = "0.6c7"
-DEFAULT_URL = "http://pypi.python.org/packages/%s/s/setuptools/" % sys.version[:3]
-
-md5_data = {
- 'setuptools-0.6b1-py2.3.egg': '8822caf901250d848b996b7f25c6e6ca',
- 'setuptools-0.6b1-py2.4.egg': 'b79a8a403e4502fbb85ee3f1941735cb',
- 'setuptools-0.6b2-py2.3.egg': '5657759d8a6d8fc44070a9d07272d99b',
- 'setuptools-0.6b2-py2.4.egg': '4996a8d169d2be661fa32a6e52e4f82a',
- 'setuptools-0.6b3-py2.3.egg': 'bb31c0fc7399a63579975cad9f5a0618',
- 'setuptools-0.6b3-py2.4.egg': '38a8c6b3d6ecd22247f179f7da669fac',
- 'setuptools-0.6b4-py2.3.egg': '62045a24ed4e1ebc77fe039aa4e6f7e5',
- 'setuptools-0.6b4-py2.4.egg': '4cb2a185d228dacffb2d17f103b3b1c4',
- 'setuptools-0.6c1-py2.3.egg': 'b3f2b5539d65cb7f74ad79127f1a908c',
- 'setuptools-0.6c1-py2.4.egg': 'b45adeda0667d2d2ffe14009364f2a4b',
- 'setuptools-0.6c2-py2.3.egg': 'f0064bf6aa2b7d0f3ba0b43f20817c27',
- 'setuptools-0.6c2-py2.4.egg': '616192eec35f47e8ea16cd6a122b7277',
- 'setuptools-0.6c3-py2.3.egg': 'f181fa125dfe85a259c9cd6f1d7b78fa',
- 'setuptools-0.6c3-py2.4.egg': 'e0ed74682c998bfb73bf803a50e7b71e',
- 'setuptools-0.6c3-py2.5.egg': 'abef16fdd61955514841c7c6bd98965e',
- 'setuptools-0.6c4-py2.3.egg': 'b0b9131acab32022bfac7f44c5d7971f',
- 'setuptools-0.6c4-py2.4.egg': '2a1f9656d4fbf3c97bf946c0a124e6e2',
- 'setuptools-0.6c4-py2.5.egg': '8f5a052e32cdb9c72bcf4b5526f28afc',
- 'setuptools-0.6c5-py2.3.egg': 'ee9fd80965da04f2f3e6b3576e9d8167',
- 'setuptools-0.6c5-py2.4.egg': 'afe2adf1c01701ee841761f5bcd8aa64',
- 'setuptools-0.6c5-py2.5.egg': 'a8d3f61494ccaa8714dfed37bccd3d5d',
- 'setuptools-0.6c6-py2.3.egg': '35686b78116a668847237b69d549ec20',
- 'setuptools-0.6c6-py2.4.egg': '3c56af57be3225019260a644430065ab',
- 'setuptools-0.6c6-py2.5.egg': 'b2f8a7520709a5b34f80946de5f02f53',
- 'setuptools-0.6c7-py2.3.egg': '209fdf9adc3a615e5115b725658e13e2',
- 'setuptools-0.6c7-py2.4.egg': '5a8f954807d46a0fb67cf1f26c55a82e',
- 'setuptools-0.6c7-py2.5.egg': '45d2ad28f9750e7434111fde831e8372',
-}
-
-import sys, os
-
-def _validate_md5(egg_name, data):
- if egg_name in md5_data:
- from md5 import md5
- digest = md5(data).hexdigest()
- if digest != md5_data[egg_name]:
- print >>sys.stderr, (
- "md5 validation of %s failed! (Possible download problem?)"
- % egg_name
- )
- sys.exit(2)
- return data
-
-
-def use_setuptools(
- version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir,
- download_delay=15
-):
- """Automatically find/download setuptools and make it available on sys.path
-
- `version` should be a valid setuptools version number that is available
- as an egg for download under the `download_base` URL (which should end with
- a '/'). `to_dir` is the directory where setuptools will be downloaded, if
- it is not already available. If `download_delay` is specified, it should
- be the number of seconds that will be paused before initiating a download,
- should one be required. If an older version of setuptools is installed,
- this routine will print a message to ``sys.stderr`` and raise SystemExit in
- an attempt to abort the calling script.
- """
- try:
- import setuptools
- if setuptools.__version__ == '0.0.1':
- print >>sys.stderr, (
- "You have an obsolete version of setuptools installed. Please\n"
- "remove it from your system entirely before rerunning this script."
- )
- sys.exit(2)
- except ImportError:
- egg = download_setuptools(version, download_base, to_dir, download_delay)
- sys.path.insert(0, egg)
- import setuptools; setuptools.bootstrap_install_from = egg
-
- import pkg_resources
- try:
- pkg_resources.require("setuptools>="+version)
-
- except pkg_resources.VersionConflict, e:
- # XXX could we install in a subprocess here?
- print >>sys.stderr, (
- "The required version of setuptools (>=%s) is not available, and\n"
- "can't be installed while this script is running. Please install\n"
- " a more recent version first.\n\n(Currently using %r)"
- ) % (version, e.args[0])
- sys.exit(2)
-
-def download_setuptools(
- version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir,
- delay = 15
-):
- """Download setuptools from a specified location and return its filename
-
- `version` should be a valid setuptools version number that is available
- as an egg for download under the `download_base` URL (which should end
- with a '/'). `to_dir` is the directory where the egg will be downloaded.
- `delay` is the number of seconds to pause before an actual download attempt.
- """
- import urllib2, shutil
- egg_name = "setuptools-%s-py%s.egg" % (version,sys.version[:3])
- url = download_base + egg_name
- saveto = os.path.join(to_dir, egg_name)
- src = dst = None
- if not os.path.exists(saveto): # Avoid repeated downloads
- try:
- from distutils import log
- if delay:
- log.warn("""
----------------------------------------------------------------------------
-This script requires setuptools version %s to run (even to display
-help). I will attempt to download it for you (from
-%s), but
-you may need to enable firewall access for this script first.
-I will start the download in %d seconds.
-
-(Note: if this machine does not have network access, please obtain the file
-
- %s
-
-and place it in this directory before rerunning this script.)
----------------------------------------------------------------------------""",
- version, download_base, delay, url
- ); from time import sleep; sleep(delay)
- log.warn("Downloading %s", url)
- src = urllib2.urlopen(url)
- # Read/write all in one block, so we don't create a corrupt file
- # if the download is interrupted.
- data = _validate_md5(egg_name, src.read())
- dst = open(saveto,"wb"); dst.write(data)
- finally:
- if src: src.close()
- if dst: dst.close()
- return os.path.realpath(saveto)
-
-def main(argv, version=DEFAULT_VERSION):
- """Install or upgrade setuptools and EasyInstall"""
-
- try:
- import setuptools
- except ImportError:
- egg = None
- try:
- egg = download_setuptools(version, delay=0)
- sys.path.insert(0,egg)
- from setuptools.command.easy_install import main
- return main(list(argv)+[egg]) # we're done here
- finally:
- if egg and os.path.exists(egg):
- os.unlink(egg)
- else:
- if setuptools.__version__ == '0.0.1':
- # tell the user to uninstall obsolete version
- use_setuptools(version)
-
- req = "setuptools>="+version
- import pkg_resources
- try:
- pkg_resources.require(req)
- except pkg_resources.VersionConflict:
- try:
- from setuptools.command.easy_install import main
- except ImportError:
- from easy_install import main
- main(list(argv)+[download_setuptools(delay=0)])
- sys.exit(0) # try to force an exit
- else:
- if argv:
- from setuptools.command.easy_install import main
- main(argv)
- else:
- print "Setuptools version",version,"or greater has been installed."
- print '(Run "ez_setup.py -U setuptools" to reinstall or upgrade.)'
-
-
-
-def update_md5(filenames):
- """Update our built-in md5 registry"""
-
- import re
- from md5 import md5
-
- for name in filenames:
- base = os.path.basename(name)
- f = open(name,'rb')
- md5_data[base] = md5(f.read()).hexdigest()
- f.close()
-
- data = [" %r: %r,\n" % it for it in md5_data.items()]
- data.sort()
- repl = "".join(data)
-
- import inspect
- srcfile = inspect.getsourcefile(sys.modules[__name__])
- f = open(srcfile, 'rb'); src = f.read(); f.close()
-
- match = re.search("\nmd5_data = {\n([^}]+)}", src)
- if not match:
- print >>sys.stderr, "Internal error!"
- sys.exit(2)
-
- src = src[:match.start(1)] + repl + src[match.end(1):]
- f = open(srcfile,'w')
- f.write(src)
- f.close()
-
-
-if __name__=='__main__':
- if len(sys.argv)>2 and sys.argv[1]=='--md5update':
- update_md5(sys.argv[2:])
- else:
- main(sys.argv[1:])
-
-
-
-
-
diff --git a/persistent.egg-info/PKG-INFO b/persistent.egg-info/PKG-INFO
index 3396a8d..f7fa1d0 100644
--- a/persistent.egg-info/PKG-INFO
+++ b/persistent.egg-info/PKG-INFO
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: persistent
-Version: 4.1.1
+Version: 4.2.2
Summary: Translucent persistent objects
Home-page: http://www.zope.org/Products/ZODB
Author: Zope Corporation
@@ -9,6 +9,21 @@ License: ZPL 2.1
Description: ``persistent``: automatic persistence for Python objects
=========================================================
+ .. image:: https://travis-ci.org/zopefoundation/persistent.png?branch=master
+ :target: https://travis-ci.org/zopefoundation/persistent
+
+ .. image:: https://readthedocs.org/projects/persistent/badge/?version=latest
+ :target: http://persistent.readthedocs.org/en/latest/
+ :alt: Documentation Status
+
+ .. image:: https://img.shields.io/pypi/v/persistent.svg
+ :target: https://pypi.python.org/pypi/persistent
+ :alt: PyPI
+
+ .. image:: https://img.shields.io/pypi/pyversions/persistent.svg
+ :target: https://pypi.python.org/pypi/persistent
+ :alt: Python versions
+
This package contains a generic persistence implementation for Python. It
forms the core protocol for making objects interact "transparently" with
a database such as the ZODB.
@@ -26,6 +41,37 @@ Description: ``persistent``: automatic persistence for Python objects
``persistent`` Changelog
========================
+ 4.2.2 (2016-11-29)
+ ------------------
+
+ - Drop use of ``ctypes`` for determining maximum integer size, to increase
+ pure-Python compatibility.
+
+ - Ensure that ``__slots__`` attributes are cleared when a persistent
+ object is ghostified. (This excluses classes that override
+ ``__new__``. See
+ https://github.com/zopefoundation/persistent/wiki/Notes_on_state_new_and_slots
+ if you're curious.)
+
+ 4.2.1 (2016-05-26)
+ ------------------
+
+ - Fix the hashcode of C ``TimeStamp`` objects on 64-bit Python 3 on
+ Windows.
+
+ 4.2.0 (2016-05-05)
+ ------------------
+
+ - Fixed the Python(/PYPY) implementation ``TimeStamp.timeTime`` method
+ to have subsecond precision.
+
+ - When testing ``PURE_PYTHON`` environments under ``tox``, avoid poisoning
+ the user's global wheel cache.
+
+ - Add support for Python 3.5.
+
+ - Drop support for Python 2.6 and 3.2.
+
4.1.1 (2015-06-02)
------------------
@@ -199,12 +245,11 @@ Classifier: Development Status :: 6 - Mature
Classifier: License :: OSI Approved :: Zope Public License
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 2
-Classifier: Programming Language :: Python :: 2.6
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3.2
Classifier: Programming Language :: Python :: 3.3
Classifier: Programming Language :: Python :: 3.4
+Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Programming Language :: Python :: Implementation :: PyPy
Classifier: Framework :: ZODB
diff --git a/persistent.egg-info/SOURCES.txt b/persistent.egg-info/SOURCES.txt
index d9a2e69..1839aec 100644
--- a/persistent.egg-info/SOURCES.txt
+++ b/persistent.egg-info/SOURCES.txt
@@ -1,5 +1,4 @@
.coveragerc
-.gitignore
.travis.yml
CHANGES.rst
COPYRIGHT.txt
@@ -8,7 +7,7 @@ MANIFEST.in
README.rst
bootstrap.py
buildout.cfg
-ez_setup.py
+rtd.txt
setup.cfg
setup.py
tox.ini
diff --git a/persistent/_timestamp.c b/persistent/_timestamp.c
index 83bcdf8..63ced30 100644
--- a/persistent/_timestamp.c
+++ b/persistent/_timestamp.c
@@ -152,7 +152,12 @@ TimeStamp_richcompare(TimeStamp *self, TimeStamp *other, int op)
return result;
}
+
+#ifdef PY3K
+static Py_hash_t
+#else
static long
+#endif
TimeStamp_hash(TimeStamp *self)
{
register unsigned char *p = (unsigned char *)self->data;
diff --git a/persistent/cPersistence.c b/persistent/cPersistence.c
index 36ce441..67cdbd2 100644
--- a/persistent/cPersistence.c
+++ b/persistent/cPersistence.c
@@ -82,6 +82,7 @@ fatal_1350(cPersistentObject *self, const char *caller, const char *detail)
#endif
static void ghostify(cPersistentObject*);
+static PyObject * pickle_slotnames(PyTypeObject *cls);
static PyObject * convert_name(PyObject *name);
@@ -150,7 +151,7 @@ accessed(cPersistentObject *self)
static void
ghostify(cPersistentObject *self)
{
- PyObject **dictptr;
+ PyObject **dictptr, *slotnames;
/* are we already a ghost? */
if (self->state == cPersistent_GHOST_STATE)
@@ -180,6 +181,8 @@ ghostify(cPersistentObject *self)
_estimated_size_in_bytes(self->estimated_size);
ring_del(&self->ring);
self->state = cPersistent_GHOST_STATE;
+
+ /* clear __dict__ */
dictptr = _PyObject_GetDictPtr((PyObject *)self);
if (dictptr && *dictptr)
{
@@ -187,6 +190,53 @@ ghostify(cPersistentObject *self)
*dictptr = NULL;
}
+ /* clear all slots besides _p_*
+ * ( for backward-compatibility reason we do this only if class does not
+ * override __new__ ) */
+ if (Py_TYPE(self)->tp_new == Pertype.tp_new)
+ {
+ slotnames = pickle_slotnames(Py_TYPE(self));
+ if (slotnames && slotnames != Py_None)
+ {
+ int i;
+
+ for (i = 0; i < PyList_GET_SIZE(slotnames); i++)
+ {
+ PyObject *name;
+ char *cname;
+ int is_special;
+
+ name = PyList_GET_ITEM(slotnames, i);
+#ifdef PY3K
+ if (PyUnicode_Check(name))
+ {
+ PyObject *converted = convert_name(name);
+ cname = PyBytes_AS_STRING(converted);
+#else
+ if (PyBytes_Check(name))
+ {
+ cname = PyBytes_AS_STRING(name);
+#endif
+ is_special = !strncmp(cname, "_p_", 3);
+#ifdef PY3K
+ Py_DECREF(converted);
+#endif
+ if (is_special) /* skip persistent */
+ {
+ continue;
+ }
+ }
+
+ /* NOTE: this skips our delattr hook */
+ if (PyObject_GenericSetAttr((PyObject *)self, name, NULL) < 0)
+ /* delattr of non-set slot will raise AttributeError - we
+ * simply ignore. */
+ PyErr_Clear();
+ }
+ }
+ Py_XDECREF(slotnames);
+ }
+
/* We remove the reference to the just ghosted object that the ring
* holds. Note that the dictionary of oids->objects has an uncounted
* reference, so if the ring's reference was the only one, this frees
@@ -270,6 +320,8 @@ Per__p_deactivate(cPersistentObject *self)
called directly. Methods that override this need to
do the same! */
ghostify(self);
+ if (PyErr_Occurred())
+ return NULL;
}
Py_INCREF(Py_None);
@@ -298,6 +350,8 @@ Per__p_invalidate(cPersistentObject *self)
if (Per_set_changed(self, NULL) < 0)
return NULL;
ghostify(self);
+ if (PyErr_Occurred())
+ return NULL;
}
Py_INCREF(Py_None);
return Py_None;
diff --git a/persistent/persistence.py b/persistent/persistence.py
index 25c1520..1388da4 100644
--- a/persistent/persistence.py
+++ b/persistent/persistence.py
@@ -303,11 +303,11 @@ class Persistent(object):
_OGA(self, '_p_register')()
object.__delattr__(self, name)
- def _slotnames(self):
+ def _slotnames(self, _v_exclude=True):
slotnames = copy_reg._slotnames(type(self))
return [x for x in slotnames
if not x.startswith('_p_') and
- not x.startswith('_v_') and
+ not (x.startswith('_v_') and _v_exclude) and
not x.startswith('_Persistent__') and
x not in Persistent.__slots__]
@@ -423,6 +423,18 @@ class Persistent(object):
idict = getattr(self, '__dict__', None)
if idict is not None:
idict.clear()
+ type_ = type(self)
+ # ( for backward-compatibility reason we release __slots__ only if
+ # class does not override __new__ )
+ if type_.__new__ is Persistent.__new__:
+ for slotname in Persistent._slotnames(self, _v_exclude=False):
+ try:
+ getattr(type_, slotname).__delete__(self)
+ except AttributeError:
+ # AttributeError means slot variable was not initialized at all -
+ # - we can simply skip its deletion.
+ pass
+
# Implementation detail: deactivating/invalidating
# updates the size of the cache (if we have one)
# by telling it this object no longer takes any bytes
diff --git a/persistent/tests/test_persistence.py b/persistent/tests/test_persistence.py
index b883a8a..09c294f 100644
--- a/persistent/tests/test_persistence.py
+++ b/persistent/tests/test_persistence.py
@@ -1319,6 +1319,57 @@ class _Persistent_Base(object):
self.assertEqual(list(jar._loaded), [])
self.assertEqual(list(jar._registered), [])
+ def test__p_invalidate_from_changed_w_slots(self):
+ class Derived(self._getTargetClass()):
+ __slots__ = ('myattr1', 'myattr2', 'unset')
+ def __init__(self):
+ self.myattr1 = 'value1'
+ self.myattr2 = 'value2'
+ inst, jar, OID = self._makeOneWithJar(Derived)
+ inst._p_activate()
+ inst._p_changed = True
+ jar._loaded = []
+ jar._registered = []
+ self.assertEqual(Derived.myattr1.__get__(inst), 'value1')
+ self.assertEqual(Derived.myattr2.__get__(inst), 'value2')
+ inst._p_invalidate()
+ self.assertEqual(inst._p_status, 'ghost')
+ self.assertEqual(list(jar._loaded), [])
+ self.assertRaises(AttributeError, lambda: Derived.myattr1.__get__(inst))
+ self.assertRaises(AttributeError, lambda: Derived.myattr2.__get__(inst))
+ self.assertEqual(list(jar._loaded), [])
+ self.assertEqual(list(jar._registered), [])
+
+ def test__p_invalidate_from_changed_w_slots_compat(self):
+ # check that (for backward-compatibility reason) slots are not released
+ # for classes where __new__ is overwritten. Attributes in __dict__
+ # should be always released.
+ class Derived(self._getTargetClass()):
+ __slots__ = ('myattr1', 'myattr2', '__dict__')
+ def __new__(cls):
+ obj = cls.__base__.__new__(cls)
+ obj.myattr1 = 'value1'
+ obj.myattr2 = 'value2'
+ obj.foo = 'foo1' # .foo & .bar are in __dict__
+ obj.bar = 'bar2'
+ return obj
+ inst, jar, OID = self._makeOneWithJar(Derived)
+ inst._p_activate()
+ inst._p_changed = True
+ jar._loaded = []
+ jar._registered = []
+ self.assertEqual(Derived.myattr1.__get__(inst), 'value1')
+ self.assertEqual(Derived.myattr2.__get__(inst), 'value2')
+ self.assertEqual(inst.__dict__, {'foo': 'foo1', 'bar': 'bar2'})
+ inst._p_invalidate()
+ self.assertEqual(inst._p_status, 'ghost')
+ self.assertEqual(list(jar._loaded), [])
+ self.assertEqual(Derived.myattr1.__get__(inst), 'value1')
+ self.assertEqual(Derived.myattr2.__get__(inst), 'value2')
+ self.assertEqual(inst.__dict__, {})
+ self.assertEqual(list(jar._loaded), [])
+ self.assertEqual(list(jar._registered), [])
+
def test__p_invalidate_from_sticky(self):
inst, jar, OID = self._makeOneWithJar()
inst._p_activate() # XXX
diff --git a/persistent/tests/test_timestamp.py b/persistent/tests/test_timestamp.py
index f83c31d..670e46b 100644
--- a/persistent/tests/test_timestamp.py
+++ b/persistent/tests/test_timestamp.py
@@ -11,13 +11,11 @@
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
-import operator
import unittest
-import platform
-py_impl = getattr(platform, 'python_implementation', lambda: None)
-_is_jython = py_impl() == 'Jython'
+MAX_32_BITS = 2 ** 31 - 1
+MAX_64_BITS = 2 ** 63 - 1
class Test__UTC(unittest.TestCase):
@@ -100,9 +98,10 @@ class pyTimeStampTests(unittest.TestCase):
self.assertEqual(ts.timeTime(), DELTA_SECS)
def test_ctor_from_string_non_zero(self):
- before = self._makeOne(2011, 2, 16, 14, 37, 22.0)
+ before = self._makeOne(2011, 2, 16, 14, 37, 22.80544)
after = self._makeOne(before.raw())
self.assertEqual(before.raw(), after.raw())
+ self.assertEqual(before.timeTime(), 1297867042.80544)
def test_ctor_from_elements(self):
from persistent.timestamp import _makeOctets
@@ -159,35 +158,37 @@ class pyTimeStampTests(unittest.TestCase):
self.assertEqual(repr(ts), repr(SERIAL))
def test_comparisons_to_non_timestamps(self):
+ import operator
from persistent._compat import PYTHON2
# Check the corner cases when comparing non-comparable types
ts = self._makeOne(2011, 2, 16, 14, 37, 22.0)
- if PYTHON2:
- def check(op, passes):
- if passes == 'neither':
... 356 lines suppressed ...
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/python-persistent.git
More information about the Python-modules-commits
mailing list