root/ftp_error.py

Revision 869:808476873684, 4.4 kB (checked in by Stefan Schwarzer <sschwarzer@…>, 3 months ago)
Replaced licenses in each file with reference to common `LICENSE` file (suggested by Steve Steiner). I removed the copyright notice for Roger Demetrescu from `_test_ftputil.py` because I remembered only after the last commit that the tests for the `with` statement had gone into their own file, `_test_with_statement.py`. I added Roger's name there, and also in `ftp_file.py` which had also gotten `with` support.
Line 
1# Copyright (C) 2003-2009, Stefan Schwarzer <sschwarzer@sschwarzer.net>
2# See the file LICENSE for licensing terms.
3
4"""
5ftp_error.py - exception classes and wrappers
6"""
7
8# "Too many ancestors"
9# pylint: disable-msg = R0901
10
11import ftplib
12import sys
13import warnings
14
15import ftputil_version
16
17
18class FTPError(Exception):
19    """General error class."""
20
21    def __init__(self, *args):
22        # `ftplib.Error` doesn't have a `__subclasses__` _method_ but a
23        #  static method, so my use of `ftplib.Error.__subclasses__` in
24        #  my opinion is valid
25        # pylint: disable-msg = e1101
26        # contrary to what `ftplib`'s documentation says, `all_errors`
27        #  does _not_ contain the subclasses, so I explicitly add them
28        if args and (args[0].__class__ in ftplib.all_errors or
29                     issubclass(args[0].__class__, ftplib.Error)):
30            warnings.warn(("Passing exception objects into the FTPError "
31              "constructor is deprecated and will be disabled in ftputil 2.6"),
32              DeprecationWarning, stacklevel=2)
33        try:
34            # works only for new style-classes (Python 2.5+)
35            super(FTPError, self).__init__(*args)
36        except TypeError:
37            # fallback to old approach
38            Exception.__init__(self, *args)
39        # don't use `args[0]` because `args` may be empty
40        if args:
41            self.strerror = self.args[0]
42        else:
43            self.strerror = ""
44        try:
45            self.errno = int(self.strerror[:3])
46        except (TypeError, IndexError, ValueError):
47            self.errno = None
48        self.filename = None
49
50    def __str__(self):
51        return "%s\nDebugging info: %s" % \
52               (self.strerror, ftputil_version.version_info)
53
54# internal errors are those that have more to do with the inner
55#  workings of ftputil than with errors on the server side
56class InternalError(FTPError):
57    """Internal error."""
58    pass
59
60class RootDirError(InternalError):
61    """Raised for generic stat calls on the remote root directory."""
62    pass
63
64class InaccessibleLoginDirError(InternalError):
65    """May be raised if the login directory isn't accessible."""
66    pass
67
68class TimeShiftError(InternalError):
69    """Raised for invalid time shift values."""
70    pass
71
72class ParserError(InternalError):
73    """Raised if a line of a remote directory can't be parsed."""
74    pass
75
76# currently not used
77class KeepAliveError(InternalError):
78    """Raised if the keep-alive feature failed."""
79    pass
80
81class FTPOSError(FTPError, OSError):
82    """Generic FTP error related to `OSError`."""
83    pass
84
85class TemporaryError(FTPOSError):
86    """Raised for temporary FTP errors (4xx)."""
87    pass
88
89class PermanentError(FTPOSError):
90    """Raised for permanent FTP errors (5xx)."""
91    pass
92
93class CommandNotImplementedError(PermanentError):
94    """Raised if the server doesn't implement a certain feature (502)."""
95    pass
96
97# currently not used
98class SyncError(PermanentError):
99    """Raised for problems specific to syncing directories."""
100    pass
101
102
103#XXX Do you know better names for `_try_with_oserror` and
104#    `_try_with_ioerror`?
105def _try_with_oserror(callee, *args, **kwargs):
106    """
107    Try the callee with the given arguments and map resulting
108    exceptions from `ftplib.all_errors` to `FTPOSError` and its
109    derived classes.
110    """
111    # use `*exc.args` instead of `str(args)` because args might be
112    #  a unicode string with non-ascii characters
113    try:
114        return callee(*args, **kwargs)
115    except ftplib.error_temp, exc:
116        raise TemporaryError(*exc.args)
117    except ftplib.error_perm, exc:
118        # if `exc.args` is present, assume it's a byte or unicode string
119        if exc.args and exc.args[0].startswith("502"):
120            raise CommandNotImplementedError(*exc.args)
121        else:
122            raise PermanentError(*exc.args)
123    except ftplib.all_errors:
124        exc = sys.exc_info()[1]
125        raise FTPOSError(*exc.args)
126
127class FTPIOError(FTPError, IOError):
128    """Generic FTP error related to `IOError`."""
129    pass
130
131
132def _try_with_ioerror(callee, *args, **kwargs):
133    """
134    Try the callee with the given arguments and map resulting
135    exceptions from `ftplib.all_errors` to `FTPIOError`.
136    """
137    try:
138        return callee(*args, **kwargs)
139    except ftplib.all_errors:
140        exc = sys.exc_info()[1]
141        # use `*exc.args` instead of `str(args)` because args might be
142        #  a unicode string with non-ascii characters
143        raise FTPIOError(*exc.args)
Note: See TracBrowser for help on using the browser.