Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
  • 1 commit
  • 2 files changed
  • 0 comments
  • 1 contributor
Jul 11, 2008
Tv 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 2 changed files with 121 additions and 0 deletions. Show diff stats Hide diff stats

  1. +72 0 fs/errno_exceptions.py
  2. +49 0 fs/test/test_errno_exceptions.py
72 fs/errno_exceptions.py
... ... @@ -0,0 +1,72 @@
  1 +import errno
  2 +import os
  3 +import string
  4 +
  5 +class ErrnoException(Exception):
  6 + """
  7 + Base class for all errno-based exceptions.
  8 + """
  9 +
  10 + def __init__(self, original):
  11 + self.original = original
  12 + self.args = original.args
  13 + self.filename = original.filename
  14 +
  15 + def __str__(self):
  16 + return os.strerror(self.errno)
  17 +
  18 +_ALLOWED = string.ascii_letters + string.digits
  19 +
  20 +def _munge_name(s):
  21 + result = ''.join(
  22 + ''.join(c for c in word if c in _ALLOWED).capitalize()
  23 + for word in s.split(None)
  24 + )
  25 + return result
  26 +
  27 +def _init(errors):
  28 + for num, abbrev in errors.items():
  29 + errstr = os.strerror(num)
  30 + classname = '%sError' % _munge_name(errstr)
  31 + class_ = type(
  32 + classname,
  33 + (ErrnoException,),
  34 + dict(
  35 + errno=num,
  36 + strerror=errstr
  37 + ),
  38 + )
  39 + globals()[classname] = class_
  40 + globals()['%s_Error' % abbrev] = class_
  41 +
  42 +_init(errno.errorcode)
  43 +
  44 +def adapt(e):
  45 + if not isinstance(e, EnvironmentError):
  46 + # we only handle exceptions known to always have errno
  47 + return e
  48 +
  49 + if isinstance(e, ErrnoException):
  50 + # already wrapped
  51 + return e
  52 +
  53 + abbrev = errno.errorcode.get(e.errno)
  54 + if abbrev is None:
  55 + # dunno what happened, but can't map it
  56 + return e
  57 +
  58 + class_ = globals().get('%s_Error' % abbrev)
  59 + if class_ is None:
  60 + # dunno what happened, but can't map it
  61 + return e
  62 +
  63 + new = class_(e)
  64 + return new
  65 +
  66 +def wrap(fn):
  67 + def handle(*a, **kw):
  68 + try:
  69 + return fn(*a, **kw)
  70 + except EnvironmentError, e:
  71 + raise adapt(e)
  72 + return handle
49 fs/test/test_errno_exceptions.py
... ... @@ -0,0 +1,49 @@
  1 +from nose.tools import (
  2 + eq_ as eq,
  3 + )
  4 +
  5 +from fs.test.util import (
  6 + assert_raises,
  7 + )
  8 +
  9 +import errno
  10 +import os
  11 +
  12 +from fs import errno_exceptions
  13 +
  14 +def test_adapt_simple():
  15 + old = OSError(
  16 + errno.ENOENT,
  17 + os.strerror(errno.ENOENT),
  18 + 'fake-filename',
  19 + )
  20 + new = errno_exceptions.adapt(old)
  21 + assert type(new) is errno_exceptions.NoSuchFileOrDirectoryError, \
  22 + 'New has wrong type: %r' % type(new)
  23 + assert type(new) is errno_exceptions.ENOENT_Error, \
  24 + 'New has wrong type: %r' % type(new)
  25 + eq(new.errno, errno.ENOENT)
  26 + eq(new.strerror, os.strerror(errno.ENOENT))
  27 + eq(new.filename, 'fake-filename')
  28 + eq(
  29 + new.args,
  30 + (
  31 + errno.ENOENT,
  32 + os.strerror(errno.ENOENT),
  33 + # EnvironmentError doesn't put filename here, for
  34 + # backwards compat
  35 + ),
  36 + )
  37 +
  38 +def test_wrap_simple():
  39 + @errno_exceptions.wrap
  40 + def broken():
  41 + file('/does-not-exist')
  42 +
  43 + e = assert_raises(
  44 + errno_exceptions.NoSuchFileOrDirectoryError,
  45 + broken,
  46 + )
  47 + eq(e.errno, errno.ENOENT)
  48 + eq(e.strerror, os.strerror(errno.ENOENT))
  49 + eq(e.filename, '/does-not-exist')

No commit comments for this range

Something went wrong with that request. Please try again.