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

Pytest and CI #198

Closed
wants to merge 15 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.tox/
.cache/
*.egg-info/
*.pyc
10 changes: 10 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
language: python

python:
- 3.5

install:
- pip install tox

script:
- tox
2 changes: 2 additions & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
include README
include LICENSE
2 changes: 1 addition & 1 deletion dill/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
""" + __license__

from .dill import dump, dumps, load, loads, dump_session, load_session, \
Pickler, Unpickler, register, copy, pickle, pickles, check, \
Pickler, Unpickler, register, copy, pickle, pickles, \
HIGHEST_PROTOCOL, DEFAULT_PROTOCOL, PicklingError, UnpicklingError, \
HANDLE_FMODE, CONTENTS_FMODE, FILE_FMODE
from . import source, temp, detect
Expand Down
31 changes: 2 additions & 29 deletions dill/dill.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"""
__all__ = ['dump','dumps','load','loads','dump_session','load_session',
'Pickler','Unpickler','register','copy','pickle','pickles',
'check','HIGHEST_PROTOCOL','DEFAULT_PROTOCOL','PicklingError',
'HIGHEST_PROTOCOL','DEFAULT_PROTOCOL','PicklingError',
'UnpicklingError','HANDLE_FMODE','CONTENTS_FMODE','FILE_FMODE']

import logging
Expand Down Expand Up @@ -1075,7 +1075,7 @@ def _proxy_helper(obj): # a dead proxy returns a reference to None
return id(None)
if _str == _repr: return id(obj) # it's a repr
try: # either way, it's a proxy from here
address = int(_str.rstrip('>').split(' at ')[-1], base=16)
address = int(_str.rstrip('>').split(' at ')[-1], base=16)
except ValueError: # special case: proxy of a 'type'
if not IS_PYPY:
address = int(_repr.rstrip('>').split(' at ')[-1], base=16)
Expand Down Expand Up @@ -1316,33 +1316,6 @@ def pickles(obj,exact=False,safe=False,**kwds):
except exceptions:
return False

def check(obj, *args, **kwds):
"""check pickling of an object across another process"""
# == undocumented ==
# python -- the string path or executable name of the selected python
# verbose -- if True, be verbose about printing warning messages
# all other args and kwds are passed to dill.dumps
verbose = kwds.pop('verbose', False)
python = kwds.pop('python', None)
if python is None:
import sys
python = sys.executable
# type check
isinstance(python, str)
import subprocess
fail = True
try:
_obj = dumps(obj, *args, **kwds)
fail = False
finally:
if fail and verbose:
print("DUMP FAILED")
msg = "%s -c import dill; print(dill.loads(%s))" % (python, repr(_obj))
msg = "SUCCESS" if not subprocess.call(msg.split(None,2)) else "LOAD FAILED"
if verbose:
print(msg)
return

# use to protect against missing attributes
def is_dill(pickler):
"check the dill-ness of your pickler"
Expand Down
Empty file added tests/__init__.py
Empty file.
73 changes: 57 additions & 16 deletions tests/test_check.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,43 @@
# - http://trac.mystic.cacr.caltech.edu/project/pathos/browser/dill/LICENSE

from __future__ import with_statement
from dill import check
import sys

from dill import dumps
from dill.temp import capture
from dill.dill import PY3
import sys

f = lambda x:x**2

def check(obj, *args, **kwds):
"""check pickling of an object across another process"""
# == undocumented ==
# python -- the string path or executable name of the selected python
# verbose -- if True, be verbose about printing warning messages
# all other args and kwds are passed to dill.dumps
verbose = kwds.pop('verbose', False)
python = kwds.pop('python', None)
if python is None:
import sys
python = sys.executable
# type check
isinstance(python, str)
import subprocess
fail = True
try:
_obj = dumps(obj, *args, **kwds)
fail = False
finally:
if fail and verbose:
print("DUMP FAILED")
msg = "%s -c import dill; print(dill.loads(%s))" % (python, repr(_obj))
msg = "SUCCESS" if not subprocess.call(msg.split(None, 2)) else "FAILED"
if verbose:
print(msg)
return


#FIXME: this doesn't catch output... it's from the internal call
def test(func, **kwds):
def raise_check(func, **kwds):
try:
with capture('stdout') as out:
check(func, **kwds)
Expand All @@ -27,19 +55,32 @@ def test(func, **kwds):
out.close()


if __name__ == '__main__':
test(f)
test(f, recurse=True)
test(f, byref=True)
test(f, protocol=0)
#TODO: test incompatible versions
# SyntaxError: invalid syntax
f = lambda x:x**2


def test_simple():
raise_check(f)


def test_recurse():
raise_check(f, recurse=True)


def test_byref():
raise_check(f, byref=True)


def test_protocol():
raise_check(f, protocol=True)


def test_python():
if PY3:
test(f, python='python3.4')
raise_check(f, python='python3.4')
else:
test(f, python='python2.7')
#TODO: test dump failure
#TODO: test load failure
raise_check(f, python='python2.7')


# EOF
#TODO: test incompatible versions
#TODO: test dump failure
#TODO: test load failure
21 changes: 11 additions & 10 deletions tests/test_extendpickle.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,18 @@
def my_fn(x):
return x * 17

obj = lambda : my_fn(34)
assert obj() == 578
def test_extend():
obj = lambda : my_fn(34)
assert obj() == 578

obj_io = StringIO()
pickler = pickle.Pickler(obj_io)
pickler.dump(obj)
obj_io = StringIO()
pickler = pickle.Pickler(obj_io)
pickler.dump(obj)

obj_str = obj_io.getvalue()
obj_str = obj_io.getvalue()

obj2_io = StringIO(obj_str)
unpickler = pickle.Unpickler(obj2_io)
obj2 = unpickler.load()
obj2_io = StringIO(obj_str)
unpickler = pickle.Unpickler(obj2_io)
obj2 = unpickler.load()

assert obj2() == 578
assert obj2() == 578
46 changes: 26 additions & 20 deletions tests/test_file.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,16 @@
# License: 3-clause BSD. The full license text is available at:
# - http://trac.mystic.cacr.caltech.edu/project/pathos/browser/dill/LICENSE

import dill
import random
import os
import sys
import string
import random

import pytest

import dill


dill.settings['recurse'] = True

fname = "_test_file.txt"
Expand All @@ -20,6 +25,7 @@
buffer_error = ValueError("invalid buffer size")
dne_error = FileNotFoundError("[Errno 2] No such file or directory: '%s'" % fname)


def write_randomness(number=200):
f = open(fname, "w")
for i in range(number):
Expand All @@ -44,7 +50,24 @@ def throws(op, args, exc):
return False


def test(strictio, fmode):
def teardown_module():
if os.path.exists(fname):
os.remove(fname)


@pytest.mark.parametrize('strictio,fmode,skippypy', [
(False, dill.HANDLE_FMODE, False),
(False, dill.FILE_FMODE, False),
(False, dill.CONTENTS_FMODE, True),
#(True, dill.HANDLE_FMODE, False),
#(True, dill.FILE_FMODE, False),
#(True, dill.CONTENTS_FMODE, True),
])
def test_various(strictio, fmode, skippypy):
import platform
if skippypy and platform.python_implementation() == 'PyPy':
pytest.skip('Skip for PyPy...')

# file exists, with same contents
# read

Expand Down Expand Up @@ -459,20 +482,3 @@ def test(strictio, fmode):
else:
raise RuntimeError("Unknown file mode '%s'" % fmode)
f2.close()


if __name__ == '__main__':

test(strictio=False, fmode=dill.HANDLE_FMODE)
test(strictio=False, fmode=dill.FILE_FMODE)
if not dill.dill.IS_PYPY: #FIXME: fails due to pypy/issues/1233
test(strictio=False, fmode=dill.CONTENTS_FMODE)

#test(strictio=True, fmode=dill.HANDLE_FMODE)
#test(strictio=True, fmode=dill.FILE_FMODE)
#test(strictio=True, fmode=dill.CONTENTS_FMODE)

if os.path.exists(fname):
os.remove(fname)

# EOF
18 changes: 10 additions & 8 deletions tests/test_functors.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,14 @@ def g(a, b, c=2): # with keywords
def h(a=1, b=2, c=3): # without args
pass

fp = functools.partial(f, 1, 2)
gp = functools.partial(g, 1, c=2)
hp = functools.partial(h, 1, c=2)
bp = functools.partial(int, base=2)

assert dill.pickles(fp, safe=True)
assert dill.pickles(gp, safe=True)
assert dill.pickles(hp, safe=True)
assert dill.pickles(bp, safe=True)
def test_functools():
fp = functools.partial(f, 1, 2)
gp = functools.partial(g, 1, c=2)
hp = functools.partial(h, 1, c=2)
bp = functools.partial(int, base=2)

assert dill.pickles(fp, safe=True)
assert dill.pickles(gp, safe=True)
assert dill.pickles(hp, safe=True)
assert dill.pickles(bp, safe=True)
14 changes: 9 additions & 5 deletions tests/test_mixins.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import dill
dill.settings['recurse'] = True


def wtf(x,y,z):
def zzz():
return x
Expand All @@ -17,6 +18,7 @@ def xxx():
return z
return zzz,yyy


def quad(a=1, b=1, c=0):
inverted = [False]
def invert():
Expand All @@ -37,8 +39,10 @@ def func(*args, **kwds):
def double_add(*args):
return sum(args)


fx = sum([1,2,3])


### to make it interesting...
def quad_factory(a=1,b=1,c=0):
def dec(f):
Expand All @@ -48,25 +52,28 @@ def func(*args,**kwds):
return func
return dec


@quad_factory(a=0,b=4,c=0)
def quadish(x):
return x+1


quadratic = quad_factory()


def doubler(f):
def inner(*args, **kwds):
fx = f(*args, **kwds)
return 2*fx
return inner


@doubler
def quadruple(x):
return 2*x


if __name__ == '__main__':

def test_mixins():
# test mixins
assert double_add(1,2,3) == 2*fx
double_add.invert()
Expand Down Expand Up @@ -107,6 +114,3 @@ def quadruple(x):
assert result == 'def quad(a=1, b=1, c=0):\n inverted = [False]\n def invert():\n inverted[0] = not inverted[0]\n def dec(f):\n def func(*args, **kwds):\n x = f(*args, **kwds)\n if inverted[0]: x = -x\n return a*x**2 + b*x + c\n func.__wrapped__ = f\n func.invert = invert\n func.inverted = inverted\n return func\n return dec\n\n@quad(a=0,b=2)\ndef double_add(*args):\n return sum(args)\n'
assert set([a,b,c,d]) == set(['a = 0', 'c = 0', 'b = 2', 'inverted = [True]'])
#*****


# EOF
Loading