Commit b8add3a0 by rfkelly0

LazyFS: lazy-creation code factored out of ConnectionManagerFS

parent d18fb2a3
...@@ -22,7 +22,7 @@ import time ...@@ -22,7 +22,7 @@ import time
import copy import copy
from fs.base import FS, threading from fs.base import FS, threading
from fs.wrapfs import WrapFS, wrap_fs_methods from fs.wrapfs import WrapFS, LazyFS, wrap_fs_methods
from fs.path import * from fs.path import *
from fs.errors import * from fs.errors import *
...@@ -156,7 +156,7 @@ class RemoteFileBuffer(object): ...@@ -156,7 +156,7 @@ class RemoteFileBuffer(object):
self._lock.release() self._lock.release()
class ConnectionManagerFS(WrapFS): class ConnectionManagerFS(LazyFS):
"""FS wrapper providing simple connection management of a remote FS. """FS wrapper providing simple connection management of a remote FS.
The ConnectionManagerFS class is designed to wrap a remote FS object The ConnectionManagerFS class is designed to wrap a remote FS object
...@@ -174,9 +174,9 @@ class ConnectionManagerFS(WrapFS): ...@@ -174,9 +174,9 @@ class ConnectionManagerFS(WrapFS):
operating-system integration may be added. operating-system integration may be added.
Since some remote FS classes can raise RemoteConnectionError during Since some remote FS classes can raise RemoteConnectionError during
initialisation, this class also provides a simple "lazy initialisation" initialisation, this class makes use of lazy initialization. The
facility. The remote FS can be specified as an FS instance, an FS remote FS can be specified as an FS instance, an FS subclass, or a
subclass, or a (class,args) or (class,args,kwds) tuple. For example: (class,args) or (class,args,kwds) tuple. For example:
>>> fs = ConnectionManagerFS(MyRemoteFS("http://www.example.com/")) >>> fs = ConnectionManagerFS(MyRemoteFS("http://www.example.com/"))
Traceback (most recent call last): Traceback (most recent call last):
...@@ -200,41 +200,6 @@ class ConnectionManagerFS(WrapFS): ...@@ -200,41 +200,6 @@ class ConnectionManagerFS(WrapFS):
self._poll_sleeper = threading.Event() self._poll_sleeper = threading.Event()
self.connected = connected self.connected = connected
def _get_wrapped_fs(self):
try:
return self.__dict__["wrapped_fs"]
except KeyError:
self._connection_cond.acquire()
try:
try:
return self.__dict__["wrapped_fs"]
except KeyError:
fs = self._fsclass(*self._fsargs,**self._fskwds)
self.__dict__["wrapped_fs"] = fs
return fs
finally:
self._connection_cond.release()
def _set_wrapped_fs(self,fs):
if isinstance(fs,FS):
self.__dict__["wrapped_fs"] = fs
elif isinstance(fs,type):
self._fsclass = fs
self._fsargs = []
self._fskwds = {}
else:
self._fsclass = fs[0]
try:
self._fsargs = fs[1]
except IndexError:
self._fsargs = []
try:
self._fskwds = fs[2]
except IndexError:
self._fskwds = {}
wrapped_fs = property(_get_wrapped_fs,_set_wrapped_fs)
def setcontents(self,path,data): def setcontents(self,path,data):
self.wrapped_fs.setcontents(path,data) self.wrapped_fs.setcontents(path,data)
......
...@@ -512,6 +512,7 @@ class FSTestCases: ...@@ -512,6 +512,7 @@ class FSTestCases:
fs3 = pickle.loads(pickle.dumps(self.fs,-1)) fs3 = pickle.loads(pickle.dumps(self.fs,-1))
self.assert_(fs3.isfile("test1")) self.assert_(fs3.isfile("test1"))
def test_big_file(self): def test_big_file(self):
chunk_size = 1024 * 256 chunk_size = 1024 * 256
num_chunks = 4 num_chunks = 4
......
...@@ -233,6 +233,7 @@ class WrapFS(FS): ...@@ -233,6 +233,7 @@ class WrapFS(FS):
self.wrapped_fs.close() self.wrapped_fs.close()
super(WrapFS,self).close() super(WrapFS,self).close()
def wrap_fs_methods(decorator,cls=None,exclude=[]): def wrap_fs_methods(decorator,cls=None,exclude=[]):
"""Apply the given decorator to all FS methods on the given class. """Apply the given decorator to all FS methods on the given class.
...@@ -270,6 +271,73 @@ def wrap_fs_methods(decorator,cls=None,exclude=[]): ...@@ -270,6 +271,73 @@ def wrap_fs_methods(decorator,cls=None,exclude=[]):
return apply_decorator return apply_decorator
class LazyFS(WrapFS):
"""Simple 'lazy initialization' for FS objects.
This FS wrapper can be created with an FS instance, an FS class, or a
(class,args,kwds) tuple. The actual FS instance will be created on demand
the first time it is accessed.
"""
def __init__(self,fs):
super(LazyFS,self).__init__(fs)
self._lazy_creation_lock = threading.RLock()
def __getstate__(self):
state = super(LazyFS,self).__getstate__()
del state["_lazy_creation_lock"]
return state
def __setstate__(self,state):
self.__dict__.update(state)
self._lazy_creation_lock = threading.RLock()
def _get_wrapped_fs(self):
"""Obtain the wrapped FS instance, created it if necessary."""
try:
return self.__dict__["wrapped_fs"]
except KeyError:
self._lazy_creation_lock.acquire()
try:
try:
return self.__dict__["wrapped_fs"]
except KeyError:
fs = self._fsclass(*self._fsargs,**self._fskwds)
self.__dict__["wrapped_fs"] = fs
return fs
finally:
self._lazy_creation_lock.release()
def _set_wrapped_fs(self,fs):
if isinstance(fs,FS):
self.__dict__["wrapped_fs"] = fs
elif isinstance(fs,type):
self._fsclass = fs
self._fsargs = []
self._fskwds = {}
else:
self._fsclass = fs[0]
try:
self._fsargs = fs[1]
except IndexError:
self._fsargs = []
try:
self._fskwds = fs[2]
except IndexError:
self._fskwds = {}
wrapped_fs = property(_get_wrapped_fs,_set_wrapped_fs)
def close(self):
if not self.closed:
# If it was never initialized, create a fake one to close.
if "wrapped_fs" not in self.__dict__:
self.__dict__["wrapped_fs"] = FS()
super(LazyFS,self).close()
class HideDotFiles(WrapFS): class HideDotFiles(WrapFS):
"""FS wrapper class that hides dot-files in directory listings. """FS wrapper class that hides dot-files in directory listings.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment