Skip to content

Commit b9f69d1

Browse files
committed
Getting closer on pickling
* Now run subset and clean the eval_env after removing bare funcalls * Had some straggling tuples * Altered test so that stateful_transforms won't be saved in eval_env * Removed the clean method on EvalEnvironment
1 parent 019094d commit b9f69d1

21 files changed

+26
-76
lines changed

patsy/contrasts.py

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -49,20 +49,13 @@ def _repr_pretty_(self, p, cycle):
4949

5050

5151
def __getstate__(self):
52-
return (0, self.matrix, self.column_suffixes)
52+
return {'version': 0, 'matrix': self.matrix,
53+
'column_suffixes': self.column_suffixes}
5354

5455
def __setstate__(self, pickle):
55-
version, matrix, column_suffixes = pickle
56-
check_pickle_version(version, 0, name=self.__class__.__name__)
57-
self.matrix = matrix
58-
self.column_suffixes = column_suffixes
59-
60-
def __eq__(self, other):
61-
if self.column_suffixes != other.column_suffixes:
62-
return False
63-
if not np.array_equal(self.matrix, other.matrix):
64-
return False
65-
return True
56+
check_pickle_version(pickle['version'], 0, name=self.__class__.__name__)
57+
self.matrix = pickle['matrix']
58+
self.column_suffixes = pickle['column_suffixes']
6659

6760

6861
def test_ContrastMatrix():

patsy/design_info.py

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -737,12 +737,6 @@ def __init__(self, name):
737737
def name(self):
738738
return self._name
739739

740-
def __eq__(self, other):
741-
return self.__dict__ == other.__dict__
742-
743-
def __hash__(self):
744-
return hash((_MockFactor, str(self._name)))
745-
746740

747741
def test_DesignInfo():
748742
from nose.tools import assert_raises

patsy/eval.py

Lines changed: 20 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
from patsy.tokens import (pretty_untokenize, normalize_token_spacing,
2626
python_tokenize)
2727
from patsy.compat import call_and_wrap_exc
28+
from nose.tools import assert_raises
2829

2930
def _all_future_flags():
3031
flags = 0
@@ -71,13 +72,8 @@ def get(self, key, default=None):
7172
def __repr__(self):
7273
return "%s(%r)" % (self.__class__.__name__, self._dicts)
7374

74-
def __getstate__(self):
75-
return (0, self._dicts)
75+
__getstate__ = no_pickling
7676

77-
def __setstate__(self, pickle):
78-
version, dicts = pickle
79-
check_pickle_version(version, 0, name=self.__class__.__name__)
80-
self._dicts = dicts
8177

8278
def test_VarLookupDict():
8379
d1 = {"a": 1}
@@ -262,27 +258,15 @@ def __hash__(self):
262258
tuple(self._namespace_ids())))
263259

264260
def __getstate__(self):
265-
self.clean()
261+
# self.clean()
266262
namespaces = self._namespaces
267263
namespaces = _replace_un_pickleable(namespaces)
268-
return (0, namespaces, self.flags)
264+
return {'version': 0, 'namespaces': namespaces, 'flags': self.flags}
269265

270266
def __setstate__(self, pickle):
271-
version, namespaces, flags = pickle
272-
check_pickle_version(version, 0, self.__class__.__name__)
273-
self.flags = flags
274-
self._namespaces = _return_un_pickleable(namespaces)
275-
276-
def clean(self):
277-
"""The EvalEnvironment doesn't need the stateful transformation
278-
functions once the design matrix has been built. This will delete
279-
it. Called by __getstate__ to prepare for pickling."""
280-
namespaces = []
281-
for namespace in self._namespaces:
282-
ns = {key: namespace[key] for key in six.iterkeys(namespace) if not
283-
hasattr(namespace[key], '__patsy_stateful_transform__')}
284-
namespaces.append(ns)
285-
self._namespaces = namespaces
267+
check_pickle_version(pickle['version'], 0, self.__class__.__name__)
268+
self.flags = pickle['flags']
269+
self._namespaces = _return_un_pickleable(pickle['namespaces'])
286270

287271

288272
class ObjectHolder(object):
@@ -504,21 +488,6 @@ def test_EvalEnvironment_eq():
504488
assert env3 != env4
505489

506490

507-
def test_EvalEnvironment_clean():
508-
from patsy.state import center, standardize
509-
from patsy.splines import bs
510-
511-
env1 = EvalEnvironment([{'center': center}])
512-
env2 = EvalEnvironment([{'standardize': standardize}])
513-
env3 = EvalEnvironment([{'bs': bs}])
514-
env1.clean()
515-
env2.clean()
516-
env3.clean()
517-
518-
env1._namespaces == [{}]
519-
env2._namespaces == [{}]
520-
env3._namespaces == [{}]
521-
522491
_builtins_dict = {}
523492
six.exec_("from patsy.builtins import *", {}, _builtins_dict)
524493
# This is purely to make the existence of patsy.builtins visible to systems
@@ -576,10 +545,6 @@ def memorize_passes_needed(self, state, eval_env):
576545

577546
eval_env = eval_env.with_outer_namespace(_builtins_dict)
578547
env_namespace = eval_env.namespace
579-
subset_names = [name for name in ast_names(self.code)
580-
if name in env_namespace]
581-
eval_env = eval_env.subset(subset_names)
582-
state["eval_env"] = eval_env
583548

584549
# example code: == "2 * center(x)"
585550
i = [0]
@@ -596,6 +561,12 @@ def new_name_maker(token):
596561
# example eval_code: == "2 * _patsy_stobj0__center__.transform(x)"
597562
eval_code = replace_bare_funcalls(self.code, new_name_maker)
598563
state["eval_code"] = eval_code
564+
565+
subset_names = [name for name in ast_names(eval_code)
566+
if name in env_namespace]
567+
eval_env = eval_env.subset(subset_names)
568+
state["eval_env"] = eval_env
569+
599570
# paranoia: verify that none of our new names appeared anywhere in the
600571
# original code
601572
if has_bare_variable_reference(state["transforms"], self.code):
@@ -716,7 +687,10 @@ def test_EvalFactor_memorize_passes_needed():
716687
print(state)
717688
assert passes == 2
718689
for name in ["foo", "bar", "quux"]:
719-
assert state["eval_env"].namespace[name] is locals()[name]
690+
# name should be locally defined, but since its a stateful_transform,
691+
# its unnecessary to keep it in eval_env
692+
assert name in locals()
693+
assert_raises(KeyError, state["eval_env"].namespace.__getitem__, name)
720694
for name in ["w", "x", "y", "z", "e", "state"]:
721695
assert name not in state["eval_env"].namespace
722696
assert state["transforms"] == {"_patsy_stobj0__foo__": "FOO-OBJ",
@@ -772,7 +746,9 @@ def test_EvalFactor_end_to_end():
772746
print(passes)
773747
print(state)
774748
assert passes == 2
775-
assert state["eval_env"].namespace["foo"] is foo
749+
# We don't want to save the stateful transforms in the eval_env, actually.
750+
# Just
751+
assert_raises(KeyError, state["eval_env"].namespace.__getitem__, 'foo')
776752
for name in ["x", "y", "e", "state"]:
777753
assert name not in state["eval_env"].namespace
778754
import numpy as np

patsy/test_pickling.py

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -42,19 +42,6 @@ def _unwrap_stateful_function(function, *args, **kwargs):
4242

4343
pickling_testcases = {
4444
"evalfactor_simple": EvalFactor("a+b"),
45-
"varlookupdict_simple": VarLookupDict([{"a": 1}, {"a": 2, "b": 3}]),
46-
"evalenv_simple": EvalEnvironment([{"a": 1}]),
47-
"evalenv_transform_center": EvalEnvironment([{'center': center}]),
48-
"evalenv_transform_scale": EvalEnvironment([{'scale': scale}]),
49-
"evalenv_transform_standardize": EvalEnvironment([{
50-
'standardize': standardize
51-
}]),
52-
"evalenv_transform_categorical": EvalEnvironment([{'C': C}]),
53-
"evalenv_transform_bs": EvalEnvironment([{'cs': bs}]),
54-
"evalenv_transform_te": EvalEnvironment([{'te': te}]),
55-
"evalenv_transform_cr": EvalEnvironment([{'cs': cr}]),
56-
"evalenv_transform_cc": EvalEnvironment([{'cc': cc}]),
57-
"evalenv_pickle": EvalEnvironment([{'np': np}]),
5845
"term": Term([1, 2, 1]),
5946
"contrast_matrix": ContrastMatrix([[1, 0], [0, 1]], ["a", "b"]),
6047
"subterm_info": si,

patsy/util.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
import numpy as np
3030
import six
3131
from six.moves import cStringIO as StringIO
32-
from patsy.compat import optional_dep_ok
32+
from .compat import optional_dep_ok
3333

3434
try:
3535
import pandas
55 Bytes
Binary file not shown.
-128 Bytes
Binary file not shown.
-67 Bytes
Binary file not shown.
-60 Bytes
Binary file not shown.
-89 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)