2424
2525When any problem occurred, you can turn on internal debugging messages::
2626
27- import logging
27+ import logging
2828 l = logging.getLogger()
2929 l.setLevel(logging.DEBUG)
3030 l.addHandler(logging.StreamHandler(sys.stdout))
3131
3232 ... your Python code using TahoeLAFS ...
33-
33+
3434TODO:
3535
3636 * unicode support
3737 * try network errors / bad happiness
3838 * exceptions
39- * tests
39+ * tests
4040 * sanitize all path types (., /)
4141 * support for extra large file uploads (poster module)
4242 * Possibility to block write until upload done (Tahoe mailing list)
4646 * docs & author
4747 * python3 support
4848 * remove creating blank files (depends on FileUploadManager)
49-
49+
5050TODO (Not TahoeLAFS specific tasks):
5151 * RemoteFileBuffer on the fly buffering support
5252 * RemoteFileBuffer unit tests
5353 * RemoteFileBuffer submit to trunk
5454 * Implement FileUploadManager + faking isfile/exists of just processing file
55- * pyfilesystem docs is outdated (rename, movedir, ...)
55+ * pyfilesystem docs is outdated (rename, movedir, ...)
5656
5757'''
5858
7171from fs .base import fnmatch , NoDefaultMeta
7272
7373from util import TahoeUtil
74- from connection import Connection
74+ from connection import Connection
7575
7676from six import b
7777
@@ -90,8 +90,8 @@ def wrapper(self, *args, **kwds):
9090def _fixpath (path ):
9191 """Normalize the given path."""
9292 return abspath (normpath (path ))
93-
94-
93+
94+
9595
9696class _TahoeLAFS (FS ):
9797 """FS providing raw access to a Tahoe-LAFS Filesystem.
@@ -101,18 +101,18 @@ class _TahoeLAFS(FS):
101101 TahoeLAFS class instead, which has some internal caching to improve
102102 performance.
103103 """
104-
104+
105105 _meta = { 'virtual' : False ,
106106 'read_only' : False ,
107107 'unicode_paths' : True ,
108108 'case_insensitive_paths' : False ,
109109 'network' : True
110110 }
111-
111+
112112
113113 def __init__ (self , dircap , largefilesize = 10 * 1024 * 1024 , webapi = 'http://127.0.0.1:3456' ):
114114 '''Creates instance of TahoeLAFS.
115-
115+
116116 :param dircap: special hash allowing user to work with TahoeLAFS directory.
117117 :param largefilesize: - Create placeholder file for files larger than this treshold.
118118 Uploading and processing of large files can last extremely long (many hours),
@@ -123,11 +123,11 @@ def __init__(self, dircap, largefilesize=10*1024*1024, webapi='http://127.0.0.1:
123123 self .largefilesize = largefilesize
124124 self .connection = Connection (webapi )
125125 self .tahoeutil = TahoeUtil (webapi )
126- super (_TahoeLAFS , self ).__init__ (thread_synchronize = _thread_synchronize_default )
127-
126+ super (_TahoeLAFS , self ).__init__ (thread_synchronize = _thread_synchronize_default )
127+
128128 def __str__ (self ):
129- return "<TahoeLAFS: %s>" % self .dircap
130-
129+ return "<TahoeLAFS: %s>" % self .dircap
130+
131131 @classmethod
132132 def createdircap (cls , webapi = 'http://127.0.0.1:3456' ):
133133 return TahoeUtil (webapi ).createdircap ()
@@ -136,10 +136,10 @@ def getmeta(self,meta_name,default=NoDefaultMeta):
136136 if meta_name == "read_only" :
137137 return self .dircap .startswith ('URI:DIR2-RO' )
138138 return super (_TahoeLAFS ,self ).getmeta (meta_name ,default )
139-
139+
140140 @_fix_path
141141 def open (self , path , mode = 'r' , ** kwargs ):
142- self ._log (INFO , 'Opening file %s in mode %s' % (path , mode ))
142+ self ._log (INFO , 'Opening file %s in mode %s' % (path , mode ))
143143 newfile = False
144144 if not self .exists (path ):
145145 if 'w' in mode or 'a' in mode :
@@ -152,7 +152,7 @@ def open(self, path, mode='r', **kwargs):
152152 raise errors .ResourceInvalidError (path )
153153 elif 'w' in mode :
154154 newfile = True
155-
155+
156156 if newfile :
157157 self ._log (DEBUG , 'Creating empty file %s' % path )
158158 if self .getmeta ("read_only" ):
@@ -162,7 +162,7 @@ def open(self, path, mode='r', **kwargs):
162162 else :
163163 self ._log (DEBUG , 'Opening existing file %s for reading' % path )
164164 handler = self .getrange (path ,0 )
165-
165+
166166 return RemoteFileBuffer (self , path , mode , handler ,
167167 write_on_flush = False )
168168
@@ -172,7 +172,7 @@ def desc(self, path):
172172 return self .getinfo (path )
173173 except :
174174 return ''
175-
175+
176176 @_fix_path
177177 def exists (self , path ):
178178 try :
@@ -185,7 +185,7 @@ def exists(self, path):
185185 except errors .ResourceInvalidError :
186186 self ._log (DEBUG , "Path %s does not exists, probably misspelled URI" % path )
187187 return False
188-
188+
189189 @_fix_path
190190 def getsize (self , path ):
191191 try :
@@ -194,7 +194,7 @@ def getsize(self, path):
194194 return size
195195 except errors .ResourceNotFoundError :
196196 return 0
197-
197+
198198 @_fix_path
199199 def isfile (self , path ):
200200 try :
@@ -204,8 +204,8 @@ def isfile(self, path):
204204 isfile = False
205205 self ._log (DEBUG , "Path %s is file: %d" % (path , isfile ))
206206 return isfile
207-
208- @_fix_path
207+
208+ @_fix_path
209209 def isdir (self , path ):
210210 try :
211211 isdir = (self .getinfo (path )['type' ] == 'dirnode' )
@@ -214,48 +214,48 @@ def isdir(self, path):
214214 self ._log (DEBUG , "Path %s is directory: %d" % (path , isdir ))
215215 return isdir
216216
217-
217+
218218 def listdir (self , * args , ** kwargs ):
219- return [ item [0 ] for item in self .listdirinfo (* args , ** kwargs ) ]
219+ return [ item [0 ] for item in self .listdirinfo (* args , ** kwargs ) ]
220220
221221 def listdirinfo (self , * args , ** kwds ):
222222 return list (self .ilistdirinfo (* args ,** kwds ))
223223
224224 def ilistdir (self , * args , ** kwds ):
225225 for item in self .ilistdirinfo (* args ,** kwds ):
226226 yield item [0 ]
227-
227+
228228 @_fix_path
229229 def ilistdirinfo (self , path = "/" , wildcard = None , full = False , absolute = False ,
230230 dirs_only = False , files_only = False ):
231231 self ._log (DEBUG , "Listing directory (listdirinfo) %s" % path )
232-
232+
233233 if dirs_only and files_only :
234234 raise ValueError ("dirs_only and files_only can not both be True" )
235-
235+
236236 for item in self .tahoeutil .list (self .dircap , path ):
237237 if dirs_only and item ['type' ] == 'filenode' :
238238 continue
239239 elif files_only and item ['type' ] == 'dirnode' :
240240 continue
241-
241+
242242 if wildcard is not None :
243243 if isinstance (wildcard ,basestring ):
244244 if not fnmatch .fnmatch (item ['name' ], wildcard ):
245245 continue
246246 else :
247247 if not wildcard (item ['name' ]):
248248 continue
249-
249+
250250 if full :
251251 item_path = relpath (pathjoin (path , item ['name' ]))
252252 elif absolute :
253- item_path = abspath (pathjoin (path , item ['name' ]))
253+ item_path = abspath (pathjoin (path , item ['name' ]))
254254 else :
255255 item_path = item ['name' ]
256-
256+
257257 yield (item_path , item )
258-
258+
259259 @_fix_path
260260 def remove (self , path ):
261261 self ._log (INFO , 'Removing file %s' % path )
@@ -266,15 +266,15 @@ def remove(self, path):
266266 if not self .isdir (path ):
267267 raise errors .ResourceNotFoundError (path )
268268 raise errors .ResourceInvalidError (path )
269-
269+
270270 try :
271271 self .tahoeutil .unlink (self .dircap , path )
272272 except Exception , e :
273273 raise errors .ResourceInvalidError (path )
274-
274+
275275 @_fix_path
276276 def removedir (self , path , recursive = False , force = False ):
277- self ._log (INFO , "Removing directory %s" % path )
277+ self ._log (INFO , "Removing directory %s" % path )
278278 if self .getmeta ("read_only" ):
279279 raise errors .UnsupportedError ('read only filesystem' )
280280 if not self .isdir (path ):
@@ -283,32 +283,32 @@ def removedir(self, path, recursive=False, force=False):
283283 raise errors .ResourceInvalidError (path )
284284 if not force and self .listdir (path ):
285285 raise errors .DirectoryNotEmptyError (path )
286-
286+
287287 self .tahoeutil .unlink (self .dircap , path )
288288
289289 if recursive and path != '/' :
290290 try :
291291 self .removedir (dirname (path ), recursive = True )
292292 except errors .DirectoryNotEmptyError :
293293 pass
294-
294+
295295 @_fix_path
296296 def makedir (self , path , recursive = False , allow_recreate = False ):
297297 self ._log (INFO , "Creating directory %s" % path )
298298 if self .getmeta ("read_only" ):
299- raise errors .UnsupportedError ('read only filesystem' )
299+ raise errors .UnsupportedError ('read only filesystem' )
300300 if self .exists (path ):
301301 if not self .isdir (path ):
302302 raise errors .ResourceInvalidError (path )
303- if not allow_recreate :
303+ if not allow_recreate :
304304 raise errors .DestinationExistsError (path )
305305 if not recursive and not self .exists (dirname (path )):
306306 raise errors .ParentDirectoryMissingError (path )
307307 self .tahoeutil .mkdir (self .dircap , path )
308-
308+
309309 def movedir (self , src , dst , overwrite = False ):
310310 self .move (src , dst , overwrite = overwrite )
311-
311+
312312 def move (self , src , dst , overwrite = False ):
313313 self ._log (INFO , "Moving file from %s to %s" % (src , dst ))
314314 if self .getmeta ("read_only" ):
@@ -323,27 +323,27 @@ def move(self, src, dst, overwrite=False):
323323
324324 def rename (self , src , dst ):
325325 self .move (src , dst )
326-
326+
327327 def copy (self , src , dst , overwrite = False , chunk_size = 16384 ):
328328 if self .getmeta ("read_only" ):
329329 raise errors .UnsupportedError ('read only filesystem' )
330330 # FIXME: this is out of date; how to do native tahoe copy?
331331 # FIXME: Workaround because isfile() not exists on _TahoeLAFS
332332 FS .copy (self , src , dst , overwrite , chunk_size )
333-
333+
334334 def copydir (self , src , dst , overwrite = False , ignore_errors = False , chunk_size = 16384 ):
335335 if self .getmeta ("read_only" ):
336336 raise errors .UnsupportedError ('read only filesystem' )
337337 # FIXME: this is out of date; how to do native tahoe copy?
338338 # FIXME: Workaround because isfile() not exists on _TahoeLAFS
339339 FS .copydir (self , src , dst , overwrite , ignore_errors , chunk_size )
340-
341-
340+
341+
342342 def _log (self , level , message ):
343343 if not logger .isEnabledFor (level ): return
344344 logger .log (level , u'(%d) %s' % (id (self ),
345345 unicode (message ).encode ('ASCII' , 'replace' )))
346-
346+
347347 @_fix_path
348348 def getpathurl (self , path , allow_none = False , webapi = None ):
349349 '''
@@ -359,15 +359,15 @@ def getpathurl(self, path, allow_none=False, webapi=None):
359359 def getrange (self , path , offset , length = None ):
360360 return self .connection .get (u'/uri/%s%s' % (self .dircap , path ),
361361 offset = offset , length = length )
362-
363- @_fix_path
364- def setcontents (self , path , file , chunk_size = 64 * 1024 ):
362+
363+ @_fix_path
364+ def setcontents (self , path , file , chunk_size = 64 * 1024 , bypass_lock = False ):
365365 self ._log (INFO , 'Uploading file %s' % path )
366366 size = None
367-
367+
368368 if self .getmeta ("read_only" ):
369369 raise errors .UnsupportedError ('read only filesystem' )
370-
370+
371371 # Workaround for large files:
372372 # First create zero file placeholder, then
373373 # upload final content.
@@ -385,9 +385,9 @@ def setcontents(self, path, file, chunk_size=64*1024):
385385 self .connection .put (u'/uri/%s%s' % (self .dircap , path ), file , size = size )
386386
387387 @_fix_path
388- def getinfo (self , path ):
388+ def getinfo (self , path ):
389389 self ._log (INFO , 'Reading meta for %s' % path )
390- info = self .tahoeutil .info (self .dircap , path )
390+ info = self .tahoeutil .info (self .dircap , path )
391391 #import datetime
392392 #info['created_time'] = datetime.datetime.now()
393393 #info['modified_time'] = datetime.datetime.now()
0 commit comments