[Zope3-checkins]
SVN: Zope3/branches/zipimport-support/src/zope/filereference/
- extend the interface to support exists/isdir/isfile checks
Fred L. Drake, Jr.
fdrake at gmail.com
Wed Nov 9 17:02:23 EST 2005
Log message for revision 40013:
- extend the interface to support exists/isdir/isfile checks
- add a specialized zipimport-specific reference implementation that
can use more direct checks for the checks
Changed:
U Zope3/branches/zipimport-support/src/zope/filereference/README.txt
U Zope3/branches/zipimport-support/src/zope/filereference/__init__.py
U Zope3/branches/zipimport-support/src/zope/filereference/interfaces.py
U Zope3/branches/zipimport-support/src/zope/filereference/reference.py
U Zope3/branches/zipimport-support/src/zope/filereference/tests.py
-=-
Modified: Zope3/branches/zipimport-support/src/zope/filereference/README.txt
===================================================================
--- Zope3/branches/zipimport-support/src/zope/filereference/README.txt 2005-11-09 21:52:05 UTC (rev 40012)
+++ Zope3/branches/zipimport-support/src/zope/filereference/README.txt 2005-11-09 22:02:23 UTC (rev 40013)
@@ -13,9 +13,11 @@
before this API existed, while new code can use the extended API for
more flexibility.
-There are two interesting functions: `new()` is used to construct a
-new path reference, and `open()` is used to open the resource as a
-file-like object.
+There are several interesting functions: `new()` is used to construct
+a new path reference, and `open()` is used to open the resource as a
+file-like object. Additional functions correlate to the common
+functions `os.path.exists()`, `os.path.isdir()`, and
+`os.path.isfile()`.
`new()` takes three arguments: a path, a package, and a base path.
Only the first is required; passing `None` for the `package` and
@@ -47,6 +49,15 @@
'====================================\n'
>>> f.close()
+We can also ask whether the reference points to a file that exists::
+
+ >>> zope.filereference.exists(ref)
+ True
+ >>> zope.filereference.isfile(ref)
+ True
+ >>> zope.filereference.isdir(ref)
+ False
+
While this looks little different from using a simple string to refer
to the referenced file, it provides more functionality if the file
being referenced is part of a package contained in a ZIP archive.
@@ -70,6 +81,15 @@
'<configure\n'
>>> f.close()
+The query methods provide the expected results as well::
+
+ >>> zope.filereference.exists(ref)
+ True
+ >>> zope.filereference.isdir(ref)
+ False
+ >>> zope.filereference.isfile(ref)
+ True
+
Note that only read modes are supported::
>>> zope.filereference.open(ref, "w")
@@ -91,3 +111,25 @@
Traceback (most recent call last):
...
ValueError: `mode` must be a read-only mode
+
+References to directories in ZIP files work as well::
+
+ >>> ref = zope.filereference.new("sample", package=zippity)
+ >>> zope.filereference.exists(ref)
+ True
+ >>> zope.filereference.isdir(ref)
+ True
+ >>> zope.filereference.isfile(ref)
+ False
+
+If we refer to a resource in a ZIP archive that doesn't exist, we get
+the expected results::
+
+ >>> ref = zope.filereference.new("MISSING.txt", package=zippity.sample)
+
+ >>> zope.filereference.exists(ref)
+ False
+ >>> zope.filereference.isfile(ref)
+ False
+ >>> zope.filereference.isdir(ref)
+ False
Modified: Zope3/branches/zipimport-support/src/zope/filereference/__init__.py
===================================================================
--- Zope3/branches/zipimport-support/src/zope/filereference/__init__.py 2005-11-09 21:52:05 UTC (rev 40012)
+++ Zope3/branches/zipimport-support/src/zope/filereference/__init__.py 2005-11-09 22:02:23 UTC (rev 40013)
@@ -19,4 +19,4 @@
__docformat__ = "reStructuredText"
-from reference import open, new
+from reference import open, new, exists, isdir, isfile
Modified: Zope3/branches/zipimport-support/src/zope/filereference/interfaces.py
===================================================================
--- Zope3/branches/zipimport-support/src/zope/filereference/interfaces.py 2005-11-09 21:52:05 UTC (rev 40012)
+++ Zope3/branches/zipimport-support/src/zope/filereference/interfaces.py 2005-11-09 22:02:23 UTC (rev 40013)
@@ -27,3 +27,12 @@
Only 'read' modes are supported.
"""
+
+ def isfile():
+ """Returns True iff the resource exists and is a file."""
+
+ def isdir():
+ """Returns True iff the resource exists and is a directory."""
+
+ def exists():
+ """Returns True iff the resource exists."""
Modified: Zope3/branches/zipimport-support/src/zope/filereference/reference.py
===================================================================
--- Zope3/branches/zipimport-support/src/zope/filereference/reference.py 2005-11-09 21:52:05 UTC (rev 40012)
+++ Zope3/branches/zipimport-support/src/zope/filereference/reference.py 2005-11-09 22:02:23 UTC (rev 40013)
@@ -20,6 +20,7 @@
import errno
import os
import StringIO
+import zipimport
import zope.interface
@@ -31,6 +32,27 @@
pkg_resources = None
+def exists(path):
+ if IResourceReference.providedBy(path):
+ return path.exists()
+ else:
+ return os.path.exists(path)
+
+
+def isdir(path):
+ if IResourceReference.providedBy(path):
+ return path.isdir()
+ else:
+ return os.path.isdir(path)
+
+
+def isfile(path):
+ if IResourceReference.providedBy(path):
+ return path.isfile()
+ else:
+ return os.path.isfile(path)
+
+
def open(path, mode="rb"):
if not mode.startswith("r"):
raise ValueError("`mode` must be a read-only mode")
@@ -60,7 +82,11 @@
p = os.path.abspath(p)
if package:
- return PackagePathReference(p, package, path)
+ loader = getattr(package, "__loader__", None)
+ if isinstance(loader, zipimport.zipimporter):
+ return ZipImporterPackagePathReference(p, package, path)
+ else:
+ return PackagePathReference(p, package, path)
else:
return PathReference(p)
@@ -76,11 +102,28 @@
def open(self, mode="rb"):
return __builtin__.open(self, mode)
+ def isfile(self):
+ return os.path.isfile(self)
-class PackagePathReference(str):
+ def isdir(self):
+ return os.path.isdir(self)
+ def exists(self):
+ return os.path.exists(self)
+
+
+class PackageStr(str):
+
zope.interface.implements(IResourceReference)
+ def __add__(self, other):
+ value = str(self) + other
+ relpath = self._relpath + other
+ return self.__class__(value, self._package, relpath)
+
+
+class PackagePathReference(PackageStr):
+
def __new__(cls, value, package, relpath):
assert package
self = str.__new__(cls, value)
@@ -88,13 +131,9 @@
self._relpath = relpath
return self
- def __add__(self, other):
- value = str(self) + other
- relpath = self._relpath + other
- return self.__class__(value, self._package, relpath)
-
def open_pkg_resources(self, mode="rb"):
- return self._open_packaged_resource(
+ return _open_packaged_resource(
+ self,
mode,
pkg_resources.resource_string,
self._package.__name__,
@@ -112,8 +151,8 @@
else:
dir = os.path.dirname(self._package.__file__)
filename = os.path.join(dir, self._relpath)
- return self._open_packaged_resource(
- mode, loader.get_data, filename)
+ return _open_packaged_resource(
+ self, mode, loader.get_data, filename)
def open(self, mode="rb"):
#
@@ -127,15 +166,123 @@
else:
return self.open_path_or_loader(mode)
- def _open_packaged_resource(self, mode, opener, *args):
+ def isfile(self):
try:
- data = opener(*args)
- except IOError, e:
- if len(e.args) == 1:
- raise IOError(errno.ENOENT, "file not found", self)
+ f = self.open()
+ except IOError:
+ return False
+ f.close()
+ return True
+
+ def isdir(self):
+ if pkg_resources:
+ return pkg_resources.resource_isdir(
+ self._package.__name__, self._relpath)
+ else:
+ try:
+ loader = self._package.__loader__
+ except AttributeError:
+ for dir in self._package.__path__:
+ filename = os.path.join(dir, self._relpath)
+ if os.path.isdir(filename):
+ return True
+ return False
else:
- raise
- f = StringIO.StringIO(data)
- f.name = self
- f.mode = mode
- return f
+ dir = os.path.dirname(self._package.__file__)
+ path = os.path.join(dir, self._relpath)
+ try:
+ if loader.is_package(path):
+ return True
+ except zipimport.ZipImportError:
+ pass
+ try:
+ loader.get_data(path)
+ except IOError:
+ pass
+ else:
+ return False
+
+ def exists(self):
+ if pkg_resources:
+ return pkg_resources.resource_exists(
+ self._package.__name__, self._relpath)
+ else:
+ try:
+ loader = self._package.__loader__
+ except AttributeError:
+ for dir in self._package.__path__:
+ filename = os.path.join(dir, self._relpath)
+ if os.path.exists(filename):
+ return True
+ return False
+ else:
+ dir = os.path.dirname(self._package.__file__)
+ path = os.path.join(dir, self._relpath)
+ try:
+ if loader.is_package(path):
+ return True
+ except zipimport.ZipImportError:
+ pass
+ try:
+ loader.get_data(path)
+ except IOError:
+ pass
+ else:
+ return True
+
+
+class ZipImporterPackagePathReference(PackageStr):
+
+ def __new__(cls, value, package, relpath):
+ assert package
+ assert isinstance(package.__loader__, zipimport.zipimporter)
+ self = str.__new__(cls, value)
+ self._package = package
+ self._relpath = relpath
+ self._loader = package.__loader__
+ return self
+
+ def open(self, mode="rb"):
+ dir = os.path.dirname(self._package.__file__)
+ filename = os.path.join(dir, self._relpath)
+ return _open_packaged_resource(
+ self, mode, self._loader.get_data, filename)
+
+ def exists(self):
+ relpath = self._getpath()
+ if relpath in self._loader._files:
+ return True
+ relpath += os.path.sep
+ return relpath in self._loader._files
+
+ def isdir(self):
+ relpath = self._getpath()
+ return (relpath + os.sep) in self._loader._files
+
+ def isfile(self):
+ relpath = self._getpath()
+ return relpath in self._loader._files
+
+ def _getpath(self):
+ relpath = self._relpath.replace("/", os.sep)
+ if os.altsep:
+ relpath = relpath.replace(os.altsep, os.sep)
+ while relpath.endswith(os.sep):
+ relpath = relpath[:-len(os.sep)]
+ pkglastname = self._package.__name__.split(".")[-1]
+ relpath = os.path.join(self._loader.prefix, pkglastname, relpath)
+ return relpath
+
+
+def _open_packaged_resource(self, mode, opener, *args):
+ try:
+ data = opener(*args)
+ except IOError, e:
+ if len(e.args) == 1:
+ raise IOError(errno.ENOENT, "file not found", self)
+ else:
+ raise
+ f = StringIO.StringIO(data)
+ f.name = self
+ f.mode = mode
+ return f
Modified: Zope3/branches/zipimport-support/src/zope/filereference/tests.py
===================================================================
--- Zope3/branches/zipimport-support/src/zope/filereference/tests.py 2005-11-09 21:52:05 UTC (rev 40012)
+++ Zope3/branches/zipimport-support/src/zope/filereference/tests.py 2005-11-09 22:02:23 UTC (rev 40013)
@@ -52,11 +52,14 @@
def test_suite():
suite = unittest.TestSuite()
- suite.addTest(doctest.DocFileSuite(
+ suite.addTest(doctest.DocFileTest(
"README.txt",
setUp=sys_path_setUp, tearDown=sys_path_tearDown))
if pkg_resources is not None:
- suite.addTest(doctest.DocFileSuite(
+ name_prefix = zope.filereference.__name__ + "/README.txt - "
+ test = doctest.DocFileTest(
"README.txt",
- setUp=pkg_resources_setUp, tearDown=pkg_resources_tearDown))
+ setUp=pkg_resources_setUp, tearDown=pkg_resources_tearDown)
+ test._dt_test.name = name_prefix + "without pkg_resources"
+ suite.addTest(test)
return suite
More information about the Zope3-Checkins
mailing list