Repository: rootpy/rootpy

Issue:
Proxy broken in rootpy.io.pickler:load
In both the latest version available with `pip` (`0.8.1` I believe) and in `0.8.2.dev0`, I can no longer use the pickler with proxies.  Here is an example:

``` python
from rootpy.plotting import Hist
from rootpy.io import pickler, root_open

h = Hist(5,0,1)
h.Print("all")
with root_open('pickled.root','recreate') as outfile:
    pickler.dump([h], outfile)

# This works fine!
with root_open('pickled.root') as infile:
    print pickler.load(infile, use_proxy=0)

# DoesNotExist Error
with root_open('pickled.root') as infile:
    print pickler.load(infile, use_proxy=1)
```

The proxies are a great idea and a nice feature - it would be great to have them back. 



Discussion:
Thanks for reporting. This must be an unintentional side-effect of changes made to support python 3. I'll try to fix and add a unit test to prevent this from happening again.

I can confirm that it's broken and that it did in fact work in cc6ab53f2c

Fixed. Will create a PR now and will release a new tag


Resolving patch:
diff --git a/rootpy/io/pickler.py b/rootpy/io/pickler.py
--- a/rootpy/io/pickler.py
+++ b/rootpy/io/pickler.py
@@ -44,7 +44,7 @@
   ROOT object will then be read the first time the proxy is accessed. This can
   help significantly with time and memory usage if you're only accessing a
   small fraction of the ROOT objects, but it does mean that you need to keep
-  the ROOT file open. Pass use_proxy=0 to disable this behavior.
+  the ROOT file open. Pass use_proxy=False to disable this behavior.
 
 """
 from __future__ import absolute_import
@@ -130,16 +130,16 @@ def __init__(self, f, pid):
 
     def __getattr__(self, a):
         if self.__o is None:
+            log.debug("unpickler proxy reading {0}".format(self.__pid))
             self.__o = self.__f.Get(self.__pid)
-            if self.__o.__class__.__module__ != 'ROOT':
-                self.__o.__class__.__module__ = 'ROOT'
+            self.__o.__class__.__module__ = 'ROOT'
         return getattr(self.__o, a)
 
     def __obj(self):
         if self.__o is None:
+            log.debug("unpickler proxy reading {0}".format(self.__pid))
             self.__o = self.__f.Get(self.__pid)
-            if self.__o.__class__.__module__ != 'ROOT':
-                self.__o.__class__.__module__ = 'ROOT'
+            self.__o.__class__.__module__ = 'ROOT'
         return self.__o
 
 
@@ -293,11 +293,11 @@ def load(self, key=None):
         return obj
 
     def persistent_load(self, pid):
+        log.debug("unpickler reading {0}".format(pid))
         if self.__use_proxy:
-            obj = ROOT_Proxy(self.__file, pid.decode('utf-8'))
+            obj = ROOT_Proxy(self.__file, pid)
         else:
             obj = self.__file.Get(pid)
-        log.debug("load {0} {1}".format(pid, obj))
         xdict[self.__serial + pid] = obj
         return obj
 
@@ -358,7 +358,7 @@ def dump(obj, root_file, proto=0, key=None):
     return ret
 
 
-def load(root_file, use_proxy=1, key=None):
+def load(root_file, use_proxy=True, key=None):
     """Load an object from a ROOT TFile.
 
     `root_file` may be an open ROOT file or directory, or a string path to an


Test patch:
diff --git a/rootpy/io/tests/test_pickler.py b/rootpy/io/tests/test_pickler.py
--- a/rootpy/io/tests/test_pickler.py
+++ b/rootpy/io/tests/test_pickler.py
@@ -4,15 +4,15 @@
 Tests for the file module.
 """
 
-from rootpy.io import TemporaryFile
+from rootpy.io import root_open, TemporaryFile
 from rootpy.io.pickler import load, dump
 from rootpy.plotting import Hist
 import random
-from nose.tools import assert_equal
+import tempfile
+from nose.tools import assert_equal, assert_true, assert_false
 
 
 def test_pickler():
-
     hlist = list()
     for i in range(10):
         hlist.append(Hist(10, 0, 10))
@@ -37,6 +37,38 @@ def test_pickler():
             assert_equal(hist.TYPE, hdict[hist.name].TYPE)
 
 
+def test_pickler_proxy():
+    h = Hist(5, 0, 1, name='hist')
+    f = tempfile.NamedTemporaryFile(suffix='.root')
+
+    with root_open(f.name, 'recreate') as outfile:
+        dump([h], outfile)
+
+    class IsCalled(object):
+        def __init__(self, func):
+            self.func = func
+            self.called = False
+
+        def __call__(self, path):
+            if path != '_pickle;1':
+                self.called = True
+            return self.func(path)
+
+    with root_open(f.name) as infile:
+        infile.Get = IsCalled(infile.Get)
+        hlist = load(infile, use_proxy=False)
+        assert_true(infile.Get.called)
+
+    with root_open(f.name) as infile:
+        infile.Get = IsCalled(infile.Get)
+        hlist = load(infile, use_proxy=True)
+        assert_false(infile.Get.called)
+        assert_equal(hlist[0].name, 'hist')
+        assert_true(infile.Get.called)
+
+    f.close()
+
+
 if __name__ == "__main__":
     import nose
     nose.runmodule()