Implement a new Python wrapper for the local database.
[cumulus.git] / python / cumulus / store / __init__.py
index 0899d70..a59c217 100644 (file)
 # with this program; if not, write to the Free Software Foundation, Inc.,
 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 
 # with this program; if not, write to the Free Software Foundation, Inc.,
 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 
-import exceptions, re, urlparse
+from __future__ import division, print_function, unicode_literals
+
+import importlib
+import re
+try:
+    # Python 3
+    from urllib import parse as urlparse
+    from urllib.parse import quote, unquote
+except ImportError:
+    # Python 2
+    from urllib import quote, unquote
+    import urlparse
 
 type_patterns = {
     'checksums': re.compile(r"^snapshot-(.*)\.(\w+)sums$"),
 
 type_patterns = {
     'checksums': re.compile(r"^snapshot-(.*)\.(\w+)sums$"),
@@ -24,36 +35,24 @@ type_patterns = {
     'snapshots': re.compile(r"^snapshot-(.*)\.(cumulus|lbs)$")
 }
 
     'snapshots': re.compile(r"^snapshot-(.*)\.(cumulus|lbs)$")
 }
 
-class NotFoundError(exceptions.KeyError):
+class NotFoundError(KeyError):
     """Exception thrown when a file is not found in a repository."""
 
     pass
 
     """Exception thrown when a file is not found in a repository."""
 
     pass
 
-class Store (object):
+class Store(object):
     """Base class for all cumulus storage backends."""
 
     """Base class for all cumulus storage backends."""
 
-    def __new__ (cls, url, **kw):
-        """ Return the correct sub-class depending on url,
-        pass parsed url parameters to object
+    def __init__(self, url):
+        """Initializes a new storage backend.
+
+        Params:
+          url: The parsed (by urlsplit) URL that specifies the storage
+              location.
         """
         """
-        if cls != Store:
-            return super(Store, cls).__new__(cls, url, **kw)
-        (scheme, netloc, path, params, query, fragment) \
-            = urlparse.urlparse(url)
-
-        try:
-            cumulus = __import__('cumulus.store.%s' % scheme, globals())
-            subcls = getattr (cumulus.store, scheme).Store
-            obj = super(Store, cls).__new__(subcls, url, **kw)
-            obj.scheme = scheme
-            obj.netloc = netloc
-            obj.path = path
-            obj.params = params
-            obj.query = query
-            obj.fragment = fragment
-            return obj
-        except ImportError:
-            raise NotImplementedError, "Scheme %s not implemented" % scheme
+        pass
+
+    # TODO: Implement context manager.
 
     def list(self, path):
         raise NotImplementedError
 
     def list(self, path):
         raise NotImplementedError
@@ -70,7 +69,7 @@ class Store (object):
     def stat(self, path):
         raise NotImplementedError
 
     def stat(self, path):
         raise NotImplementedError
 
-    def scan(self):
+    def scan(self, path):
         """Cache file information stored in this backend.
 
         This might make subsequent list or stat calls more efficient, but this
         """Cache file information stored in this backend.
 
         This might make subsequent list or stat calls more efficient, but this
@@ -89,4 +88,23 @@ class Store (object):
         self.close()
 
 def open(url):
         self.close()
 
 def open(url):
-    return Store(url)
+    """Parse a storage url, then locate and initialize a backend for it."""
+    parsed_url = urlparse.urlsplit(url)
+
+    # If there is no scheme, fall back to treating the string as local path and
+    # construct a file:/// URL.
+    if not parsed_url.scheme:
+        parsed_url = urlparse.SplitResult("file", "", quote(url), "", "")
+
+    try:
+        # TODO: Support a registry for schemes that don't map to a module.
+        if re.match(r"^\w+$", parsed_url.scheme):
+            handler = importlib.import_module("cumulus.store.%s" %
+                                              parsed_url.scheme)
+            obj = handler.Store(parsed_url)
+            return obj
+    except ImportError:
+        # Fall through to error below
+        pass
+
+    raise NotImplementedError("Scheme %s not implemented" % scheme)