Skip to content

Commit 2eea873

Browse files
committed
FIX/ENH(TCs): Dill/Pickle various struvts
1 parent c35cec6 commit 2eea873

File tree

7 files changed

+78
-28
lines changed

7 files changed

+78
-28
lines changed

graphtik/execution.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -286,14 +286,14 @@ class _OpTask:
286286
This intermediate class is needed to solve pickling issue with process executor.
287287
"""
288288

289-
__slots__ = ("op", "sol", "result", "solid")
289+
__slots__ = ("op", "sol", "solid", "result")
290290
logname = __name__
291291

292-
def __init__(self, op, sol, solid):
292+
def __init__(self, op, sol, solid, result=UNSET):
293293
self.op = op
294294
self.sol = sol
295-
self.result = UNSET
296295
self.solid = solid
296+
self.result = result
297297

298298
def marshalled(self):
299299
import dill

test/conftest.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import pytest
2+
from .helpers import dilled, pickled
3+
24

35
# Enable pytest-sphinx fixtures
46
# See https://www.sphinx-doc.org/en/master/devguide.html#unit-testing
@@ -15,3 +17,8 @@ def debug_mode():
1517

1618
with debug_enabled(True):
1719
yield
20+
21+
22+
@pytest.fixture(params=[dilled, pickled])
23+
def ser_method(request):
24+
return request.param

test/helpers.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1+
import pickle
12
import re
23
from itertools import chain, cycle
34
from pathlib import Path
45
from typing import Union
56

7+
import dill
68
import pytest
79

810
###################################################
@@ -88,3 +90,11 @@ def get_text(node):
8890
f"{Path(fname).absolute()}:\n {check!r} {msg} node at path {path!r}: "
8991
f"{[node.text for node in nodes]}"
9092
)
93+
94+
95+
def dilled(i):
96+
return dill.loads(dill.dumps(i))
97+
98+
99+
def pickled(i):
100+
return pickle.loads(pickle.dumps(i))

test/test_base.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@
1414
from graphtik.pipeline import Pipeline
1515

1616

17+
def test_serialize_Token(ser_method):
18+
assert ser_method(base.UNSET) == base.UNSET
19+
20+
1721
@pytest.mark.parametrize("locs", [None, (), [], [0], "bad"])
1822
def test_jetsam_bad_locals(locs, caplog):
1923
caplog.set_level(logging.INFO)

test/test_graphtik.py

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import sys
99
import time
1010
import types
11+
from collections import namedtuple
1112
from functools import partial
1213
from itertools import cycle
1314
from multiprocessing import Pool, cpu_count
@@ -22,7 +23,7 @@
2223
import pytest
2324

2425
from graphtik import network
25-
from graphtik.base import AbortedException, IncompleteExecutionError
26+
from graphtik.base import AbortedException, IncompleteExecutionError, Operation
2627
from graphtik.config import (
2728
abort_run,
2829
debug_enabled,
@@ -34,8 +35,7 @@
3435
operations_reschedullled,
3536
tasks_marshalled,
3637
)
37-
from graphtik.execution import Solution, task_context
38-
from graphtik.base import Operation
38+
from graphtik.execution import Solution, _OpTask, task_context
3939
from graphtik.modifiers import dep_renamed, optional, sfx, sfxed, vararg
4040
from graphtik.op import NO_RESULT, NO_RESULT_BUT_SFX, operation
4141
from graphtik.pipeline import NULL_OP, Pipeline, compose
@@ -49,10 +49,13 @@
4949
_parallel = pytest.mark.parallel
5050
_marshal = pytest.mark.marshal
5151

52+
_ExeParams = namedtuple("_ExeParams", "parallel, proc, marshal")
53+
_exe_params = _ExeParams(None, None, None)
54+
5255

5356
@pytest.fixture(
5457
params=[
55-
# PARALLEL?, Proc/Thread?, Marshalled?
58+
# PARALLEL?, Thread/Proc?, Marshalled?
5659
(None, None, None),
5760
pytest.param((1, 0, 0), marks=(_parallel, _thread)),
5861
pytest.param((1, 0, 1), marks=(_parallel, _thread, _marshal)),
@@ -70,7 +73,10 @@
7073
)
7174
def exemethod(request):
7275
"""Returns (exemethod, marshal) combinations"""
76+
global _exe_params
7377
parallel, proc_pool, marshal = request.param
78+
_exe_params = _ExeParams(*request.param)
79+
7480
nsharks = None # number of pool swimmers....
7581

7682
with tasks_marshalled(marshal):
@@ -118,6 +124,21 @@ def abspow(a, p):
118124
return c
119125

120126

127+
def test_serialize_pipeline(samplenet, ser_method):
128+
def eq(pipe1, pipe2):
129+
return pipe1.name == pipe2.name and pipe1.ops == pipe2.ops
130+
131+
assert eq(ser_method(samplenet), samplenet)
132+
133+
134+
def test_serialize_OpTask(ser_method):
135+
def eq(o1, o2):
136+
return all(getattr(o1, a) == getattr(o2, a) for a in _OpTask.__slots__)
137+
138+
ot = _OpTask(1, 2, 3, 4)
139+
assert eq(ser_method(ot), ot)
140+
141+
121142
def test_solution_finalized():
122143
sol = Solution(MagicMock(), {})
123144

@@ -285,7 +306,7 @@ def powers_in_range(a, exponent):
285306
assert sol == exp
286307

287308

288-
def test_task_context(exemethod):
309+
def test_task_context(exemethod, request):
289310
def check_task_context():
290311
assert task_context.get().op == next(iop)
291312

@@ -296,10 +317,17 @@ def check_task_context():
296317
parallel=exemethod,
297318
)
298319
iop = iter(pipe.ops)
299-
if exemethod and is_marshal_tasks():
300-
with pytest.raises(AssertionError, match="^assert FunctionalOperation"):
320+
321+
print(_exe_params)
322+
err = None
323+
if _exe_params.parallel and _exe_params.marshal:
324+
err = AssertionError("^assert FunctionalOperation")
325+
if _exe_params.proc and _exe_params.marshal:
326+
err = Exception("^Error sending result")
327+
if err:
328+
with pytest.raises(type(err), match=str(err)):
301329
pipe.compute()
302-
raise pytest.xfail("Cannot marshal `task_context` :-(.")
330+
raise pytest.xfail("Cannot marshal parallel processes with `task_context` :-(.")
303331
else:
304332
pipe.compute()
305333
with pytest.raises(StopIteration):

test/test_modifiers.py

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import dill
1+
# Copyright 2020, Kostis Anagnostopoulos.
2+
# Licensed under the terms of the Apache License, Version 2.0. See the LICENSE file associated with the project for terms.
23
import pytest
34

45
from graphtik.modifiers import (
@@ -16,13 +17,9 @@
1617
)
1718

1819

19-
def dilled(i):
20-
return dill.loads(dill.dumps(i))
21-
22-
23-
def test_dill_modifier():
20+
def test_serialize_modifier(ser_method):
2421
s = sfxed("foo", "gg")
25-
s == dilled(s)
22+
assert repr(ser_method(s)) == repr(s)
2623

2724

2825
## construct in lambdas, not to crash pytest while modifying core _Modifier
@@ -48,7 +45,6 @@ def test_modifs_str(mod, exp):
4845
got = mod()
4946
print(got)
5047
assert str(got) == exp
51-
assert dilled(str(got)) == exp
5248

5349

5450
## construct in lambdas, not to crash pytest while modifying core _Modifier
@@ -75,11 +71,11 @@ def test_modifs_str(mod, exp):
7571
(lambda: sfxed_varargs("f", "a", "b"), "sfxed('f'(+), 'a', 'b')"),
7672
],
7773
)
78-
def test_modifs_repr(mod, exp):
74+
def test_modifs_repr(mod, exp, ser_method):
7975
got = mod()
8076
print(repr(got))
8177
assert repr(got) == exp
82-
assert dilled(repr(got)) == exp
78+
assert repr(ser_method(got)) == exp
8379

8480

8581
@pytest.mark.parametrize(
@@ -105,11 +101,11 @@ def test_modifs_repr(mod, exp):
105101
(sfxed_varargs("f", "a", "b"), "sfxed_varargs('f', 'a', 'b')"),
106102
],
107103
)
108-
def test_modifs_cmd(mod, exp):
104+
def test_modifs_cmd(mod, exp, ser_method):
109105
got = mod.cmd
110106
print(got)
111107
assert str(got) == exp
112-
assert dilled(str(got)) == exp
108+
assert str(ser_method(got)) == exp
113109

114110

115111
def test_recreation():
@@ -189,11 +185,11 @@ def test_modifs_rename_fn(mod, exp):
189185
),
190186
],
191187
)
192-
def test_modifs_rename_str(mod, exp):
188+
def test_modifs_rename_str(mod, exp, ser_method):
193189
got = dep_renamed(mod(), "D")
194190
print(repr(got))
195191
assert repr(got) == exp
196-
assert dilled(repr(got)) == exp
192+
assert repr(ser_method(got)) == exp
197193

198194

199195
@pytest.mark.parametrize(

test/test_op.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
from textwrap import dedent
99
from types import SimpleNamespace
1010

11-
import dill
1211
import pytest
1312

1413
from graphtik import (
@@ -553,8 +552,14 @@ def _opsattrs(ops, attr, value):
553552
lambda: operation(lambda: None),
554553
],
555554
)
556-
def test_dill_ops(op_fact):
557-
dill.loads(dill.dumps(op_fact()))
555+
def test_serialize_op(op_fact, ser_method):
556+
op = op_fact()
557+
if "pickle" in str(ser_method) and "lambda" in str(getattr(op, "fn", ())):
558+
with pytest.raises(AttributeError, match="^Can't pickle local object"):
559+
ser_method(op) == op
560+
raise pytest.xfail(reason="Pickling fails for locals i.e. lambas")
561+
562+
assert ser_method(op) == op
558563

559564

560565
def test_op_rename():

0 commit comments

Comments
 (0)