12
12
import re
13
13
from datetime import datetime , date
14
14
from operator import itemgetter
15
+ from logging import getLogger
15
16
16
17
from six import moves , iteritems , text_type , integer_types , PY3 , binary_type , iterbytes
17
18
28
29
long = int # long is just int in python3
29
30
30
31
32
+ logger = getLogger (__name__ )
33
+ imaplib_logger = getLogger ('imapclient.imaplib' )
34
+
31
35
__all__ = ['IMAPClient' , 'DELETED' , 'SEEN' , 'ANSWERED' , 'FLAGGED' , 'DRAFT' , 'RECENT' ]
32
36
33
37
@@ -104,16 +108,6 @@ class IMAPClient(object):
104
108
system time). This attribute can be changed between ``fetch()``
105
109
calls if required.
106
110
107
- The *debug* property can be used to enable debug logging. It can
108
- be set to an integer from 0 to 5 where 0 disables debug output and
109
- 5 enables full output with wire logging and parsing logs. ``True``
110
- and ``False`` can also be assigned where ``True`` sets debug level
111
- 4.
112
-
113
- By default, debug output goes to stderr. The *log_file* attribute
114
- can be assigned to an alternate file handle for writing debug
115
- output to.
116
-
117
111
"""
118
112
119
113
Error = imaplib .IMAP4 .error
@@ -137,14 +131,19 @@ def __init__(self, host, port=None, use_uid=True, ssl=False, stream=False,
137
131
self .stream = stream
138
132
self .use_uid = use_uid
139
133
self .folder_encode = True
140
- self .log_file = sys .stderr
141
134
self .normalise_times = True
142
135
143
136
self ._timeout = timeout
144
137
self ._starttls_done = False
145
138
self ._cached_capabilities = None
139
+
146
140
self ._imap = self ._create_IMAP4 ()
147
- self ._imap ._mesg = self ._log # patch in custom debug log method
141
+ logger .debug ("Connected to host %s" , self .host )
142
+
143
+ # Small hack to make imaplib log everything to its own logger
144
+ self ._imap .debug = 5
145
+ self ._imap ._mesg = imaplib_logger .debug
146
+
148
147
self ._idle_tag = None
149
148
150
149
self ._set_timeout ()
@@ -202,12 +201,14 @@ def login(self, username, password):
202
201
"""Login using *username* and *password*, returning the
203
202
server response.
204
203
"""
205
- return self ._command_and_check (
204
+ rv = self ._command_and_check (
206
205
'login' ,
207
206
to_unicode (username ),
208
207
to_unicode (password ),
209
208
unpack = True ,
210
209
)
210
+ logger .info ('Logged in as %s' , username )
211
+ return rv
211
212
212
213
def oauth2_login (self , user , access_token , mech = 'XOAUTH2' , vendor = None ):
213
214
"""Authenticate using the OAUTH2 method.
@@ -234,6 +235,7 @@ def logout(self):
234
235
"""
235
236
typ , data = self ._imap .logout ()
236
237
self ._check_resp ('BYE' , 'logout' , typ , data )
238
+ logger .info ('Logged out, connection closed' )
237
239
return data [0 ]
238
240
239
241
def shutdown (self ):
@@ -243,6 +245,7 @@ def shutdown(self):
243
245
this. The logout method also shutdown down the connection.
244
246
"""
245
247
self ._imap .shutdown ()
248
+ logger .info ('Connection closed' )
246
249
247
250
def id_ (self , parameters = None ):
248
251
"""Issue the ID command, returning a dict of server implementation
@@ -596,10 +599,7 @@ def idle_done(self):
596
599
any). These are returned in parsed form as per
597
600
``idle_check()``.
598
601
"""
599
- if self .debug >= 4 :
600
- self ._log_ts ()
601
- self ._log_write ('< DONE' , end = True )
602
-
602
+ logger .debug ('< DONE' )
603
603
self ._imap .send (b'DONE\r \n ' )
604
604
return self ._consume_until_tagged_response (self ._idle_tag , 'IDLE' )
605
605
@@ -1103,10 +1103,6 @@ def _raw_command(self, command, args):
1103
1103
*command* should be specified as bytes.
1104
1104
*args* should be specified as a list of bytes.
1105
1105
"""
1106
- if self .debug >= 4 :
1107
- self ._log_ts ()
1108
- self ._log_write ('> ' )
1109
-
1110
1106
command = command .upper ()
1111
1107
1112
1108
if isinstance (args , tuple ):
@@ -1128,8 +1124,7 @@ def _raw_command(self, command, args):
1128
1124
if _is8bit (item ):
1129
1125
if line :
1130
1126
out = b' ' .join (line )
1131
- if self .debug >= 4 :
1132
- self ._log_write (out )
1127
+ logger .debug ('> %s' , out )
1133
1128
self ._imap .send (out )
1134
1129
line = []
1135
1130
self ._send_literal (tag , item )
@@ -1140,22 +1135,18 @@ def _raw_command(self, command, args):
1140
1135
1141
1136
if line :
1142
1137
out = b' ' .join (line )
1143
- if self .debug >= 4 :
1144
- self ._log_write (out )
1138
+ logger .debug ('> %s' , out )
1145
1139
self ._imap .send (out )
1146
1140
1147
1141
self ._imap .send (b'\r \n ' )
1148
- if self .debug >= 4 :
1149
- self ._log_write ("" , end = True )
1150
1142
1151
1143
return self ._imap ._command_complete (to_unicode (command ), tag )
1152
1144
1153
1145
def _send_literal (self , tag , item ):
1154
1146
"""Send a single literal for the command with *tag*.
1155
1147
"""
1156
1148
out = b' {' + str (len (item )).encode ('ascii' ) + b'}\r \n '
1157
- if self .debug >= 4 :
1158
- self ._log_write (out , end = True )
1149
+ logger .debug (out )
1159
1150
self ._imap .send (out )
1160
1151
1161
1152
# Wait for continuation response
@@ -1166,9 +1157,7 @@ def _send_literal(self, tag, item):
1166
1157
"unexpected response while waiting for continuation response: " +
1167
1158
repr (tagged_resp ))
1168
1159
1169
- if self .debug >= 4 :
1170
- self ._log_write (" (literal) > " )
1171
- self ._log_write (item )
1160
+ logger .debug (" (literal) > %s" , item )
1172
1161
self ._imap .send (item )
1173
1162
1174
1163
def _command_and_check (self , command , * args , ** kwargs ):
@@ -1219,38 +1208,6 @@ def _filter_fetch_dict(self, fetch_dict, key):
1219
1208
return dict ((msgid , data [key ])
1220
1209
for msgid , data in iteritems (fetch_dict ))
1221
1210
1222
- def __debug_get (self ):
1223
- return self ._imap .debug
1224
-
1225
- def __debug_set (self , level ):
1226
- if level is True :
1227
- level = 4
1228
- elif level is False :
1229
- level = 0
1230
- self ._imap .debug = level
1231
-
1232
- debug = property (__debug_get , __debug_set )
1233
-
1234
- def _log_ts (self ):
1235
- self .log_file .write (datetime .now ().strftime ('%M:%S.%f' ) + ' ' )
1236
-
1237
- def _log_write (self , text , end = False ):
1238
- if isinstance (text , binary_type ):
1239
- text = repr (text )
1240
- for i , c in enumerate (text ):
1241
- if c in "\" '" :
1242
- break
1243
- text = text [i + 1 :- 1 ]
1244
- self .log_file .write (text )
1245
-
1246
- if end :
1247
- self .log_file .write ('\n ' )
1248
- self .log_file .flush ()
1249
-
1250
- def _log (self , text ):
1251
- self ._log_ts ()
1252
- self ._log_write (text , end = True )
1253
-
1254
1211
def _normalise_folder (self , folder_name ):
1255
1212
if isinstance (folder_name , binary_type ):
1256
1213
folder_name = folder_name .decode ('ascii' )
0 commit comments