Commit f92af63f by willmcgugan

Added getmeta and hasmeta methods

parent bc9437bf
...@@ -59,4 +59,5 @@ ...@@ -59,4 +59,5 @@
the info dict and avoid an additional query to the filesystem. the info dict and avoid an additional query to the filesystem.
* Added utility module 'fs.filelike' with some helpers for building and * Added utility module 'fs.filelike' with some helpers for building and
manipulating file-like objects. manipulating file-like objects.
* Added getmeta and hasmeta methods
...@@ -133,6 +133,8 @@ class FS(object): ...@@ -133,6 +133,8 @@ class FS(object):
""" """
_meta = {}
def __init__(self, thread_synchronize=False): def __init__(self, thread_synchronize=False):
"""The base class for Filesystem objects. """The base class for Filesystem objects.
...@@ -186,6 +188,33 @@ class FS(object): ...@@ -186,6 +188,33 @@ class FS(object):
else: else:
self._lock = DummyLock() self._lock = DummyLock()
def getmeta(self, meta_name, default=Ellipsis):
"""Retrieve a meta value associated with the FS object
:param meta_name: The name of the meta value to retrieve
:param default: An option default to return, if the meta value isn't present
:raises NoMetaError: If specified meta value is not present, and there is no default
"""
if meta_name not in self._meta:
if default is not Ellipsis:
return default
raise NoMetaError(meta_name=meta_name)
return self._meta[meta_name]
def hasmeta(self, meta_name):
"""Check that a meta value is supported
:param meta_name: The name of a meta value to check
:rtype: bool
"""
try:
self.getmeta('meta_name')
except NoMetaError:
return False
return True
def getsyspath(self, path, allow_none=False): def getsyspath(self, path, allow_none=False):
"""Returns the system path (a path recognised by the OS) if present. """Returns the system path (a path recognised by the OS) if present.
......
...@@ -157,6 +157,12 @@ class BigFS(FS): ...@@ -157,6 +157,12 @@ class BigFS(FS):
"""A FileSystem that represents a BIG file.""" """A FileSystem that represents a BIG file."""
_meta = { 'virtual' : False,
'read_only' : True,
'unicode_paths' : True,
'case_insensitive_paths' : False,
}
def __init__(self, filename, mode="r", thread_synchronize=True): def __init__(self, filename, mode="r", thread_synchronize=True):
"""Create a FS that maps on to a big file. """Create a FS that maps on to a big file.
......
...@@ -73,6 +73,12 @@ class DAVFS(FS): ...@@ -73,6 +73,12 @@ class DAVFS(FS):
"https": httplib.HTTPSConnection, "https": httplib.HTTPSConnection,
} }
_meta = { 'virtual' : False,
'read_only' : False,
'unicode_paths' : True,
'case_insensitive_paths' : False,
}
def __init__(self,url,credentials=None,get_credentials=None,thread_synchronize=True,connection_classes=None,timeout=None): def __init__(self,url,credentials=None,get_credentials=None,thread_synchronize=True,connection_classes=None,timeout=None):
"""DAVFS constructor. """DAVFS constructor.
......
...@@ -75,6 +75,14 @@ def _fix_path(func): ...@@ -75,6 +75,14 @@ def _fix_path(func):
return wrapper return wrapper
class TahoeFS(CacheFS): class TahoeFS(CacheFS):
_meta = { 'virtual' : False,
'read_only' : False,
'unicode_paths' : True,
'case_insensitive_paths' : False,
'may_block' : False
}
def __init__(self, dircap, timeout=60, autorun=True, largefilesize=10*1024*1024, webapi='http://127.0.0.1:3456'): def __init__(self, dircap, timeout=60, autorun=True, largefilesize=10*1024*1024, webapi='http://127.0.0.1:3456'):
''' '''
Creates instance of TahoeFS. Creates instance of TahoeFS.
......
...@@ -20,6 +20,7 @@ __all__ = ['FSError', ...@@ -20,6 +20,7 @@ __all__ = ['FSError',
'OperationTimeoutError', 'OperationTimeoutError',
'ResourceError', 'ResourceError',
'NoSysPathError', 'NoSysPathError',
'NoMetaError',
'NoPathURLError', 'NoPathURLError',
'ResourceNotFoundError', 'ResourceNotFoundError',
'ResourceInvalidError', 'ResourceInvalidError',
...@@ -131,6 +132,14 @@ class NoSysPathError(ResourceError): ...@@ -131,6 +132,14 @@ class NoSysPathError(ResourceError):
default_message = "No mapping to OS filesystem: %(path)s" default_message = "No mapping to OS filesystem: %(path)s"
class NoMetaError(FSError):
"""Exception raised when there is no meta value available."""
default_message = "No meta value named '%(meta_name)s' could be retrieved"
def __init__(self, meta_name, msg=None):
self.meta_name = meta_name
super(NoMetaError, self).__init__(msg)
class NoPathURLError(ResourceError): class NoPathURLError(ResourceError):
"""Exception raised when there is no URL form for a given path.""" """Exception raised when there is no URL form for a given path."""
default_message = "No URL form: %(path)s" default_message = "No URL form: %(path)s"
......
...@@ -737,6 +737,13 @@ class FTPFS(FS): ...@@ -737,6 +737,13 @@ class FTPFS(FS):
_locals = threading.local() _locals = threading.local()
_meta = { 'virtual': False,
'read_only' : False,
'unicode_paths' : True,
'case_insensitive_paths' : False,
'may_block' : True
}
def __init__(self, host='', user='', passwd='', acct='', timeout=_GLOBAL_DEFAULT_TIMEOUT, def __init__(self, host='', user='', passwd='', acct='', timeout=_GLOBAL_DEFAULT_TIMEOUT,
port=21, port=21,
dircache=True, dircache=True,
......
...@@ -184,6 +184,12 @@ class MemoryFS(FS): ...@@ -184,6 +184,12 @@ class MemoryFS(FS):
""" """
_meta = { 'virtual': False,
'read_only' : False,
'unicode_paths' : True,
'case_insensitive_paths' : False
}
def _make_dir_entry(self, *args, **kwargs): def _make_dir_entry(self, *args, **kwargs):
return self.dir_entry_factory(*args, **kwargs) return self.dir_entry_factory(*args, **kwargs)
......
...@@ -68,6 +68,13 @@ class FileMount(object): ...@@ -68,6 +68,13 @@ class FileMount(object):
class MountFS(FS): class MountFS(FS):
"""A filesystem that delegates to other filesystems.""" """A filesystem that delegates to other filesystems."""
_meta = { 'virtual': True,
'read_only' : False,
'unicode_paths' : True,
'case_insensitive_paths' : False
}
DirMount = DirMount DirMount = DirMount
FileMount = FileMount FileMount = FileMount
......
...@@ -69,6 +69,12 @@ class MultiFS(FS): ...@@ -69,6 +69,12 @@ class MultiFS(FS):
dirs of its children. dirs of its children.
""" """
_meta = { 'virtual': True,
'read_only' : False,
'unicode_paths' : True,
'case_insensitive_paths' : False
}
def __init__(self): def __init__(self):
super(MultiFS, self).__init__(thread_synchronize=_thread_synchronize_default) super(MultiFS, self).__init__(thread_synchronize=_thread_synchronize_default)
......
...@@ -14,6 +14,7 @@ For example, to print all the files and directories in the OS root:: ...@@ -14,6 +14,7 @@ For example, to print all the files and directories in the OS root::
import os import os
import os.path
import sys import sys
import errno import errno
import datetime import datetime
...@@ -72,6 +73,12 @@ class OSFS(OSFSXAttrMixin, OSFSWatchMixin, FS): ...@@ -72,6 +73,12 @@ class OSFS(OSFSXAttrMixin, OSFSWatchMixin, FS):
methods in the os and os.path modules. methods in the os and os.path modules.
""" """
_meta = { 'virtual' : False,
'read_only' : False,
'unicode_paths' : os.path.supports_unicode_filenames,
'case_insensitive_paths' : os.path.normcase('Aa') == 'aa',
}
def __init__(self, root_path, thread_synchronize=_thread_synchronize_default, encoding=None, create=False, dir_mode=0700): def __init__(self, root_path, thread_synchronize=_thread_synchronize_default, encoding=None, create=False, dir_mode=0700):
""" """
Creates an FS object that represents the OS Filesystem under a given root path Creates an FS object that represents the OS Filesystem under a given root path
......
...@@ -88,6 +88,13 @@ class RPCFS(FS): ...@@ -88,6 +88,13 @@ class RPCFS(FS):
""" """
_meta = { 'virtual': False,
'read_only' : False,
'unicode_paths' : True,
'case_insensitive_paths' : False,
'may_block' : True,
}
def __init__(self, uri, transport=None): def __init__(self, uri, transport=None):
"""Constructor for RPCFS objects. """Constructor for RPCFS objects.
......
...@@ -56,6 +56,13 @@ class S3FS(FS): ...@@ -56,6 +56,13 @@ class S3FS(FS):
or flushed. or flushed.
""" """
_meta = { 'virtual': False,
'read_only' : False,
'unicode_paths' : True,
'case_insensitive_paths' : False,
'may_block' : True,
}
class meta: class meta:
PATH_MAX = None PATH_MAX = None
NAME_MAX = None NAME_MAX = None
......
...@@ -43,8 +43,16 @@ class SFTPFS(FS): ...@@ -43,8 +43,16 @@ class SFTPFS(FS):
This is basically a compatability wrapper for the excellent SFTPClient This is basically a compatability wrapper for the excellent SFTPClient
class in the paramiko module. class in the paramiko module.
""" """
_meta = { 'virtual': False,
'read_only' : False,
'unicode_paths' : True,
'case_insensitive_paths' : False,
'may_block' : True,
}
def __init__(self, connection, root_path="/", encoding=None, **credentials): def __init__(self, connection, root_path="/", encoding=None, **credentials):
"""SFTPFS constructor. """SFTPFS constructor.
......
...@@ -20,6 +20,12 @@ class TempFS(OSFS): ...@@ -20,6 +20,12 @@ class TempFS(OSFS):
"""Create a Filesystem in a tempory directory (with tempfile.mkdtemp), """Create a Filesystem in a tempory directory (with tempfile.mkdtemp),
and removes it when the TempFS object is cleaned up.""" and removes it when the TempFS object is cleaned up."""
_meta = { 'virtual' : False,
'read_only' : False,
'unicode_paths' : os.path.supports_unicode_filenames,
'case_insensitive_paths' : os.path.normcase('Aa') == 'aa',
}
def __init__(self, identifier=None, temp_dir=None, dir_mode=0700, thread_synchronize=_thread_synchronize_default): def __init__(self, identifier=None, temp_dir=None, dir_mode=0700, thread_synchronize=_thread_synchronize_default):
"""Creates a temporary Filesystem """Creates a temporary Filesystem
......
...@@ -118,6 +118,14 @@ class WrapFS(FS): ...@@ -118,6 +118,14 @@ class WrapFS(FS):
return (mode,mode) return (mode,mode)
@rewrite_errors @rewrite_errors
def getmeta(self, meta_name, default=Ellipsis):
return self.wrapped_fs.getmeta(meta_name, default)
@rewrite_errors
def hasmeta(self, meta_name):
return self.wrapped_fs.hasmeta(meta_name)
@rewrite_errors
def getsyspath(self, path, allow_none=False): def getsyspath(self, path, allow_none=False):
return self.wrapped_fs.getsyspath(self._encode(path),allow_none) return self.wrapped_fs.getsyspath(self._encode(path),allow_none)
......
...@@ -20,6 +20,16 @@ class ReadOnlyFS(WrapFS): ...@@ -20,6 +20,16 @@ class ReadOnlyFS(WrapFS):
""" """
def getmeta(self, meta_name, default=Ellipsis):
if meta_name == 'read_only':
return True
return self.wrapped_fs(meta_name, default)
def hasmeta(self, meta_name):
if meta_name == 'read_only':
return True
return self.wrapped_fs(meta_name)
def getsyspath(self, path, allow_none=False): def getsyspath(self, path, allow_none=False):
""" Doesn't technically modify the filesystem but could be used to work """ Doesn't technically modify the filesystem but could be used to work
around read-only restrictions. """ around read-only restrictions. """
......
...@@ -7,6 +7,7 @@ A FS object that represents the contents of a Zip file ...@@ -7,6 +7,7 @@ A FS object that represents the contents of a Zip file
""" """
import datetime import datetime
import os.path
from fs.base import * from fs.base import *
from fs.path import * from fs.path import *
...@@ -68,6 +69,12 @@ class ZipFS(FS): ...@@ -68,6 +69,12 @@ class ZipFS(FS):
"""A FileSystem that represents a zip file.""" """A FileSystem that represents a zip file."""
_meta = { 'virtual' : False,
'read_only' : False,
'unicode_paths' : os.path.supports_unicode_filenames,
'case_insensitive_paths' : os.path.normcase('Aa') == 'aa',
}
def __init__(self, zip_file, mode="r", compression="deflated", allow_zip_64=False, encoding="CP437", thread_synchronize=True): def __init__(self, zip_file, mode="r", compression="deflated", allow_zip_64=False, encoding="CP437", thread_synchronize=True):
"""Create a FS that maps on to a zip file. """Create a FS that maps on to a zip file.
...@@ -116,6 +123,8 @@ class ZipFS(FS): ...@@ -116,6 +123,8 @@ class ZipFS(FS):
if mode in 'ra': if mode in 'ra':
self._parse_resource_list() self._parse_resource_list()
self._meta['read_only'] = self.zip_mode != 'w'
def __str__(self): def __str__(self):
return "<ZipFS: %s>" % self.zip_path return "<ZipFS: %s>" % self.zip_path
...@@ -138,7 +147,6 @@ class ZipFS(FS): ...@@ -138,7 +147,6 @@ class ZipFS(FS):
f = self._path_fs.open(path, 'w') f = self._path_fs.open(path, 'w')
f.close() f.close()
def close(self): def close(self):
"""Finalizes the zip file so that it can be read. """Finalizes the zip file so that it can be read.
No further operations will work after this method is called.""" No further operations will work after this method is called."""
......
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