Run update-copyright.py
[rss2email.git] / rss2email / error.py
1 # Copyright (C) 2012 W. Trevor King <wking@tremily.us>
2 #
3 # This file is part of rss2email.
4 #
5 # rss2email is free software: you can redistribute it and/or modify it under
6 # the terms of the GNU General Public License as published by the Free Software
7 # Foundation, either version 2 of the License, or (at your option) version 3 of
8 # the License.
9 #
10 # rss2email is distributed in the hope that it will be useful, but WITHOUT ANY
11 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
12 # A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU General Public License along with
15 # rss2email.  If not, see <http://www.gnu.org/licenses/>.
16
17 """rss2email-specific errors 
18 """
19
20 from . import LOG as _LOG
21
22 import pprint as _pprint
23
24 import feedparser as _feedparser
25 import html2text as _html2text
26
27
28 class RSS2EmailError (Exception):
29     def __init__(self, message):
30         super(RSS2EmailError, self).__init__(message)
31
32     def log(self):
33         _LOG.error(str(self))
34         if self.__cause__ is not None:
35             _LOG.error('cause: {}'.format(self.__cause__))
36
37
38 class TimeoutError (RSS2EmailError):
39     def __init__(self, time_limited_function, message=None):
40         if message is None:
41             if time_limited_function.error is not None:
42                 message = (
43                     'error while running time limited function: {}'.format(
44                         time_limited_function.error[1]))
45             else:
46                 message = '{} second timeout exceeded'.format(
47                     time_limited_function.timeout)
48         super(TimeoutError, self).__init__(message=message)
49         self.time_limited_function = time_limited_function
50
51
52 class NoValidEncodingError (RSS2EmailError, ValueError):
53     def __init__(self, string, encodings):
54         message = 'no valid encoding for {} in {}'.format(string, encodings)
55         super(NoValidEncodingError, self).__init__(message=message)
56         self.string = string
57         self.encodings = encodings
58
59
60 class SMTPConnectionError (ValueError, RSS2EmailError):
61     def __init__(self, server, message=None):
62         if message is None:
63             message = 'could not connect to mail server {}'.format(server)
64         super(SMTPConnectionError, self).__init__(message=message)
65         self.server = server
66
67     def log(self):
68         super(SMTPConnectionError, self).log()
69         _LOG.warning(
70             'check your config file to confirm that smtp-server and other '
71             'mail server settings are configured properly')
72         if hasattr(self.__cause__, 'reason'):
73             _LOG.error('reason: {}'.format(self.__cause__.reason))
74
75
76 class SMTPAuthenticationError (SMTPConnectionError):
77     def __init__(self, server, username):
78         message = (
79             'could not authenticate with mail server {} as user {}'.format(
80                 server, username))
81         super(SMTPConnectionError, self).__init__(
82             server=server, message=message)
83         self.server = server
84         self.username = username
85
86
87 class SendmailError (RSS2EmailError):
88     def __init__(self, status=None, stdout=None, stderr=None):
89         if status:
90             message = 'sendmail exited with code {}'.format(status)
91         else:
92             message = ''
93         super(SendmailError, self).__init__(message=message)
94         self.status = status
95         self.stdout = stdout
96         self.stderr = stderr
97
98     def log(self):
99         super(SendmailError, self).log()
100         _LOG.warning((
101                 'Error attempting to send email via sendmail. You may need '
102                 'to configure rss2email to use an SMTP server. Please refer '
103                 'to the rss2email documentation or website ({}) for complete '
104                 'documentation.').format(__url__))
105
106
107 class FeedError (RSS2EmailError):
108     def __init__(self, feed, message=None):
109         if message is None:
110             message = 'error with feed {}'.format(feed.name)
111         super(FeedError, self).__init__(message=message)
112         self.feed = feed
113
114
115 class InvalidFeedName (FeedError):
116     def __init__(self, name, **kwargs):
117         message = "invalid feed name '{}'".format(name)
118         super(InvalidFeedName, self).__init__(message=message, **kwargs)
119
120
121 class ProcessingError (FeedError):
122     def __init__(self, parsed, feed, **kwargs):
123         if message is None:
124             message = 'error processing feed {}'.format(feed)
125         super(FeedError, self).__init__(feed=feed, message=message)
126         self.parsed = parsed
127
128     def log(self):
129         super(ProcessingError, self).log()
130         if type(self) == ProcessingError:  # not a more specific subclass
131             _LOG.warning(
132                 '=== rss2email encountered a problem with this feed ===')
133             _LOG.warning(
134                 '=== See the rss2email FAQ at {} for assistance ==='.format(
135                     __url__))
136             _LOG.warning(
137                 '=== If this occurs repeatedly, send this to {} ==='.format(
138                     __email__))
139             _LOG.warning(
140                 'error: {} {}'.format(
141                     self.parsed.get('bozo_exception', "can't process"),
142                     self.feed.url))
143             _LOG.warning(_pprint.pformat(self.parsed))
144             _LOG.warning('rss2email', __version__)
145             _LOG.warning('feedparser', _feedparser.__version__)
146             _LOG.warning('html2text', _html2text.__version__)
147             _LOG.warning('Python', _sys.version)
148             _LOG.warning('=== END HERE ===')
149
150
151 class HTTPError (ProcessingError):
152     def __init__(self, status, feed, **kwargs):
153         message = 'HTTP status {} fetching feed {}'.format(status, feed)
154         super(FeedError, self).__init__(feed=feed, message=message)
155         self.status = status
156
157
158 class FeedsError (RSS2EmailError):
159     def __init__(self, feeds=None, message=None, **kwargs):
160         if message is None:
161             message = 'error with feeds'
162         super(FeedsError, self).__init__(message=message, **kwargs)
163         self.feeds = feeds
164
165
166 class DataFileError (FeedsError):
167     def __init__(self, feeds, message=None):
168         if message is None:
169             message = 'problem with the feed data file {}'.format(
170                 feeds.datafile)
171         super(DataFileError, self).__init__(feeds=feeds, message=message)
172
173
174 class NoDataFile (DataFileError):
175     def __init__(self, feeds):
176         message = 'feed data file {} does not exist'.format(feeds.datafile)
177         super(NoDataFile, self).__init__(feeds=feeds, message=message)
178
179     def log(self):
180         super(NoDataFile, self).log()
181         _LOG.warning(
182             "if you're using r2e for the first time, you have to run "
183             "'r2e new' first.")
184
185
186 class NoToEmailAddress (FeedsError, FeedError):
187     def __init__(self, **kwargs):
188         message = 'no target email address has been defined'
189         super(NoToEmailAddress, self).__init__(message=message, **kwargs)
190
191     def log(self):
192         super(NoToEmailAddress, self).log()
193         _LOG.warning(
194             "please run 'r2e email emailaddress' or "
195             "'r2e add name url emailaddress'.")
196
197
198 class OPMLReadError (RSS2EmailError):
199     def __init__(self, **kwargs):
200         message = 'error reading OPML'
201         super(RSS2EmailError, self).__init__(message=message, **kwargs)