Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for PyPy, Python 2.7, and Python 3. #1

Merged
merged 27 commits into from
Aug 20, 2015
Merged

Add support for PyPy, Python 2.7, and Python 3. #1

merged 27 commits into from
Aug 20, 2015

Conversation

jamadden
Copy link
Member

@jamadden jamadden commented Apr 6, 2015

This PR adds support for versions of Python > 2.6 and PyPy by using zodbpickle when needed.

As summarized in the zodbpickle issue, noload is broken in CPython 2.7, as well as being completely missing in PyPy and Python 3. zodbpickle fixes this for CPython 2.7 and adds it back for PyPy and Python 3.

The tests were initially broken under 2.6 due to changes in the latest ZODB/persistent, so the first/fourth commit fixes those tests. Then CPython 2.7 support was added by creating a dependency on zodbpickle and using it when needed. Fixing PyPy support was a matter of ensuring that resources get closed in a timely fashion, and Python 3 support consisted of some minor syntax changes to account for the print statement and the differences between bytes and strings, plus one __bool__ alias.

A tox.ini for local use and a .travis.yml file for github use were added to ensure the tests run on all supported platforms (this required a MANIFEST.in for tox):

$ tox
.....
____________________ summary __________________________
  py26: commands succeeded
  py27: commands succeeded
  py32: commands succeeded
  py33: commands succeeded
  py34: commands succeeded
  pypy: commands succeeded

The smelliest part is that a monkey-patch against ZODB.serialize is necessary to work with older versions of ZODB that don't properly support PyPy (since it has never had a version of noload). I can submit a PR for ZODB to fix that problem going forward.

There are two changes. First, ZODB has changed the way that blob POSKeyErrors
are represented. Second, objects 3 and 4 that really are garbage from db2 are
collected during the first pass. This has a small trickle down effect.
…t) is to use the 'raw' method of the timestamp, not try to get its repr. The repr of a persistent timestamp changed sometime ago.
@jamadden jamadden mentioned this pull request Apr 6, 2015
- 3.3
- 3.4
install:
- pip install . --use-mirrors
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

--use-mirrors is deprecated and pip ignores it.

This is also an excellent opportunity to update this PR so we can see if Travis will start building it.

@mgedmin
Copy link
Member

mgedmin commented Apr 7, 2015

I tried to run the tox tests locally, and I'm seeing pypy3 failures:

Error locking file 1.fs.lock; pid=13911
Traceback (most recent call last):
  File "/home/mg/src/zopefoundation/zc.zodbdgc/.tox/pypy3/site-packages/zc/lockfile/__init__.py", line 57, in _lock_file
    fcntl.flock(file.fileno(), _flags)
IOError: [Errno 11] Resource temporarily unavailable

Full log at https://gist.github.com/mgedmin/56b7efa581fbfb206dc8

@mgedmin
Copy link
Member

mgedmin commented Apr 7, 2015

Apologies for introducing a merge conflict: I didn't want to leave Travis CI enabled without a .travis.yml in master (beause without a .travis.yml Travis defaults to Ruby builds, which are useless for us).

Would you mind rebasing?

jamadden and others added 4 commits April 7, 2015 06:49
…v qualifier, that's long released). Explicitly note all the Python 3 versions tested/supported---previously it was just a copy of Acquisition's classifiers which only list the latest.
@jamadden
Copy link
Member Author

jamadden commented Apr 7, 2015

Good point about pypy3. It wasn't on my path so tox was happily ignoring it :(

It could be a GC/del issue in zc.lockfile (or its caller?) because of the ResourceWarnings on the files that it attempts to lock. Then again, PyPy3 is a major release behind PyPy2 so there could be an issue in PyPy. For now, I think I'll comment out pypy3 from tox; it wasn't in .travis.yml anyway.

There are two changes. First, ZODB has changed the way that blob POSKeyErrors
are represented. Second, objects 3 and 4 that really are garbage from db2 are
collected during the first pass. This has a small trickle down effect.
…t) is to use the 'raw' method of the timestamp, not try to get its repr. The repr of a persistent timestamp changed sometime ago.
…v qualifier, that's long released). Explicitly note all the Python 3 versions tested/supported---previously it was just a copy of Acquisition's classifiers which only list the latest.
@jamadden
Copy link
Member Author

jamadden commented Apr 7, 2015

Rebased, and the Travis build ran clean. Thank you!

@mgedmin
Copy link
Member

mgedmin commented Apr 7, 2015

LGTM, but I'm not familiar with zc.zodbdgc (and I'm not willing to take responsibility for it ;-), so I'll wait for someone else to review and merge this.

(If the PR sits ignored for a week or two, I think it would be fine to merge it yourself -- I see you're a ZF member. You'll need to get @jimfulton's attention to push a new release to PyPI, though, he's the only one with PyPI access to zc.zodbdgc.)

@jamadden
Copy link
Member Author

@mgedmin If you have a chance, could you please try the latest code with tox -e pypy3? I'm not able to reproduce the zc.lockfile issue anymore. I tried to add it to .travis.yml, but travis isn't kicking off for some reason.

@jamadden
Copy link
Member Author

@mgedmin Whups, there went Travis. Build was green with PyPy3.

@mgedmin
Copy link
Member

mgedmin commented Apr 15, 2015

tox -e pypy3 of commit 666772f: green.

There were quite a few ResourceWarning: unclosed file ... warnings. I don't know if you care about those:

/home/mg/src/zopefoundation/zc.zodbdgc/.tox/pypy3/site-packages/BTrees/fsBTree.py:59: ResourceWarning: unclosed file <_io.BufferedRandom name=21>
  while keys and values:
/home/mg/src/zopefoundation/zc.zodbdgc/.tox/pypy3/site-packages/BTrees/fsBTree.py:59: ResourceWarning: unclosed file <_io.BufferedRandom name=22>
  while keys and values:
/home/mg/src/zopefoundation/zc.zodbdgc/src/zc/zodbdgc/__init__.py:366: ResourceWarning: unclosed file <_io.BufferedRandom name=23>
  data = self[name][oid[:6]]
/home/mg/src/zopefoundation/zc.zodbdgc/src/zc/zodbdgc/__init__.py:366: ResourceWarning: unclosed file <_io.BufferedRandom name=21>
  data = self[name][oid[:6]]
/home/mg/src/zopefoundation/zc.zodbdgc/.tox/pypy3/site-packages/zodbpickle/pickle_3.py:867: ResourceWarning: unclosed file <_io.BufferedRandom name=36>
  key = read(1)
/home/mg/src/zopefoundation/zc.zodbdgc/.tox/pypy3/site-packages/zodbpickle/pickle_3.py:867: ResourceWarning: unclosed file <_io.BufferedRandom name=34>
  key = read(1)
./home/mg/src/zopefoundation/zc.zodbdgc/.tox/pypy3/site-packages/persistent/persistence.py:246: ResourceWarning: unclosed file <_io.BufferedRandom name=20>
  if _OGA(self, '_Persistent__flags') is None:
/home/mg/src/zopefoundation/zc.zodbdgc/.tox/pypy3/site-packages/persistent/persistence.py:246: ResourceWarning: unclosed file <_io.BufferedRandom name=33>
  if _OGA(self, '_Persistent__flags') is None:
/home/mg/src/zopefoundation/zc.zodbdgc/.tox/pypy3/site-packages/persistent/persistence.py:246: ResourceWarning: unclosed file <_io.BufferedRandom name=12>
  if _OGA(self, '_Persistent__flags') is None:
/home/mg/src/zopefoundation/zc.zodbdgc/.tox/pypy3/site-packages/persistent/persistence.py:246: ResourceWarning: unclosed file <_io.BufferedReader name='/tmp/tmp_g27am/one.fs'>
  if _OGA(self, '_Persistent__flags') is None:
/home/mg/src/zopefoundation/zc.zodbdgc/.tox/pypy3/site-packages/persistent/persistence.py:246: ResourceWarning: unclosed file <_io.BufferedRandom name=14>
  if _OGA(self, '_Persistent__flags') is None:
/home/mg/src/zopefoundation/zc.zodbdgc/.tox/pypy3/site-packages/persistent/persistence.py:246: ResourceWarning: unclosed file <_io.BufferedRandom name=19>
  if _OGA(self, '_Persistent__flags') is None:

BTW python setup.py -q test is better than python setup.py test -q.

@jamadden
Copy link
Member Author

I do care about the ResourceWarnings, but I haven't been able to track them down. The lines in question are different on every run, e.g.,

//zc.zodbdgc/.tox/pypy3/lib-python/3/encodings/utf_8.py:16: ResourceWarning: unclosed file <_io.BufferedRandom name=30>
  return codecs.utf_8_decode(input, errors, True)
//zc.zodbdgc/.tox/pypy3/lib-python/3/encodings/utf_8.py:16: ResourceWarning: unclosed file <_io.BufferedRandom name=31>
  return codecs.utf_8_decode(input, errors, True)
//zc.zodbdgc/.tox/pypy3/lib-python/3/encodings/utf_8.py:16: ResourceWarning: unclosed file <_io.BufferedRandom name=32>
  return codecs.utf_8_decode(input, errors, True)
//zc.zodbdgc/.tox/pypy3/lib-python/3/encodings/utf_8.py:16: ResourceWarning: unclosed file <_io.BufferedRandom name=33>
  return codecs.utf_8_decode(input, errors, True)
//zc.zodbdgc/.tox/pypy3/site-packages/BTrees/_base.py:562: ResourceWarning: unclosed file <_io.BufferedRandom name=47>

The code in question doesn't use the io package, it just uses normal files, which under Python 3 are <_io.BufferedReader> or <_io.TextIOWrapper>, not BufferedRandom. My suspicion is that these have something to do with the doctest machinery. I'll spend some time trying to confirm that.

Thanks for the tip for tox.ini, I just copied that section from some other project without thinking.

…rceWarning/leak under Py3/PyPy. However, the bulk of the remainder are due to the use of a TemporaryFile in the return value from gc_command, which closing could potentially break semantics. Needs input.
@jamadden
Copy link
Member Author

@mgedmin I was looking in the wrong place. Under the covers, tempfile.TemporaryFile uses _io.BufferedRandom. It turns out the return value of the gc_command method returns a Bad object that has such a temporary file open.

Now, the test cases all continue to pass if that temporary file is closed (thus solving the ResourceWarning/leak): they just want to iterate over it, which is all handled in memory. However, the Bad object also supports a method iterator(name=) method which does require access to the temporary file. This is not documented or tested. Then again, neither is the return value of gc_command (other than the simple iteration case), so no users would know that they need to call close on the return value in order to avoid a ResourceWarning.

I can see a few options:

  1. Do nothing. Live with the ResourceWarnings/leaks, but don't break anybody that's using the undocumented features of Bad.
  2. Document the features of Bad, including calling close. Add test cases for this and update the existing cases to properly close the object. This is more work, but has the advantage of not breaking any callers.
  3. Make the on-disk behaviour of Bad optional, defaulting to an in-memory version only. This has the advantage of not requiring test changes or additions (to get the same level of coverage as current), plus it makes the GC process potentially faster by not requiring I/O. The disadvantage, aside from the implementation work, is that those (few?) callers that use the undocumented on-disk features will require a change.
  4. Remove the undocumented on-disk features of Bad. Solves the leaks, improves test coverage, and GC speed. Breaks callers relying on them.

Doing nothing may be the easiest way to get the PR completed and merged, although option 4 is close :) @jimfulton no doubt has the best view of the original intent and use cases, hopefully he will have some time to weigh in.

@mgedmin
Copy link
Member

mgedmin commented Apr 15, 2015

+1 for not tackling ResourceWarnings in this PR.

@jamadden
Copy link
Member Author

Bump. Unless there are objections, per the recommendation earlier of @mgemin I will probably merge this soon (my organization is about to try to move to pypy)

jamadden added a commit that referenced this pull request Aug 20, 2015
Add support for PyPy, Python 2.7, and Python 3.
@jamadden jamadden merged commit 778966c into zopefoundation:master Aug 20, 2015
@jamadden jamadden deleted the with-zodbpickle branch August 20, 2015 14:53
@jamadden jamadden mentioned this pull request Aug 25, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants