Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Comparing changes

Choose two branches to see what's changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
base fork: tv42/fs
base: master
...
head fork: tv42/fs
compare: errno-exceptions
Checking mergeability… Don't worry, you can still create the pull request.
  • 1 commit
  • 2 files changed
  • 0 commit comments
  • 1 contributor
Commits on Jul 11, 2008
@tv42 Map OSError/IOError to errno-specific classes.
This allows you to switch from old-style

    try:
        os.mkdir(path)
    except OSError, e:
        if e.errno == errno.EEXIST:
            pass
        else:
            raise

to new-style

    try:
        path.mkdir()
    except FileExistsError:
        pass
2ab6ef2
Showing with 121 additions and 0 deletions.
  1. +72 −0 fs/errno_exceptions.py
  2. +49 −0 fs/test/test_errno_exceptions.py
View
72 fs/errno_exceptions.py
@@ -0,0 +1,72 @@
+import errno
+import os
+import string
+
+class ErrnoException(Exception):
+ """
+ Base class for all errno-based exceptions.
+ """
+
+ def __init__(self, original):
+ self.original = original
+ self.args = original.args
+ self.filename = original.filename
+
+ def __str__(self):
+ return os.strerror(self.errno)
+
+_ALLOWED = string.ascii_letters + string.digits
+
+def _munge_name(s):
+ result = ''.join(
+ ''.join(c for c in word if c in _ALLOWED).capitalize()
+ for word in s.split(None)
+ )
+ return result
+
+def _init(errors):
+ for num, abbrev in errors.items():
+ errstr = os.strerror(num)
+ classname = '%sError' % _munge_name(errstr)
+ class_ = type(
+ classname,
+ (ErrnoException,),
+ dict(
+ errno=num,
+ strerror=errstr
+ ),
+ )
+ globals()[classname] = class_
+ globals()['%s_Error' % abbrev] = class_
+
+_init(errno.errorcode)
+
+def adapt(e):
+ if not isinstance(e, EnvironmentError):
+ # we only handle exceptions known to always have errno
+ return e
+
+ if isinstance(e, ErrnoException):
+ # already wrapped
+ return e
+
+ abbrev = errno.errorcode.get(e.errno)
+ if abbrev is None:
+ # dunno what happened, but can't map it
+ return e
+
+ class_ = globals().get('%s_Error' % abbrev)
+ if class_ is None:
+ # dunno what happened, but can't map it
+ return e
+
+ new = class_(e)
+ return new
+
+def wrap(fn):
+ def handle(*a, **kw):
+ try:
+ return fn(*a, **kw)
+ except EnvironmentError, e:
+ raise adapt(e)
+ return handle
View
49 fs/test/test_errno_exceptions.py
@@ -0,0 +1,49 @@
+from nose.tools import (
+ eq_ as eq,
+ )
+
+from fs.test.util import (
+ assert_raises,
+ )
+
+import errno
+import os
+
+from fs import errno_exceptions
+
+def test_adapt_simple():
+ old = OSError(
+ errno.ENOENT,
+ os.strerror(errno.ENOENT),
+ 'fake-filename',
+ )
+ new = errno_exceptions.adapt(old)
+ assert type(new) is errno_exceptions.NoSuchFileOrDirectoryError, \
+ 'New has wrong type: %r' % type(new)
+ assert type(new) is errno_exceptions.ENOENT_Error, \
+ 'New has wrong type: %r' % type(new)
+ eq(new.errno, errno.ENOENT)
+ eq(new.strerror, os.strerror(errno.ENOENT))
+ eq(new.filename, 'fake-filename')
+ eq(
+ new.args,
+ (
+ errno.ENOENT,
+ os.strerror(errno.ENOENT),
+ # EnvironmentError doesn't put filename here, for
+ # backwards compat
+ ),
+ )
+
+def test_wrap_simple():
+ @errno_exceptions.wrap
+ def broken():
+ file('/does-not-exist')
+
+ e = assert_raises(
+ errno_exceptions.NoSuchFileOrDirectoryError,
+ broken,
+ )
+ eq(e.errno, errno.ENOENT)
+ eq(e.strerror, os.strerror(errno.ENOENT))
+ eq(e.filename, '/does-not-exist')

No commit comments for this range

Something went wrong with that request. Please try again.