Skip to content
This repository

Unicode-aware logger #1792

Merged
merged 2 commits into from almost 2 years ago

2 participants

Thomas Kluyver Fernando Perez
Thomas Kluyver
Collaborator

Fixes logging to work properly with non-ascii characters in Python 2 (issue #1777).

Fernando Perez
Owner
fperez commented

Test results for commit 773bd4c merged into master
Platform: linux2

  • python2.7: OK
  • python3.2: OK (libraries not available: matplotlib pygments pymongo qt tornado wx wx.aui)

Not available for testing:

Fernando Perez
Owner
fperez commented

Thanks, looks good! Merging now.

Fernando Perez fperez merged commit e7f8981 into from
Fernando Perez fperez closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Showing 2 unique commits by 1 author.

May 30, 2012
Thomas Kluyver Make logging unicode-aware
Closes gh-1777
0eeff21
Thomas Kluyver Add test for unicode in logging. 773bd4c
This page is out of date. Refresh to see the latest.
27  IPython/core/logger.py
@@ -14,9 +14,12 @@
14 14
 
15 15
 # Python standard modules
16 16
 import glob
  17
+import io
17 18
 import os
18 19
 import time
19 20
 
  21
+from IPython.utils.py3compat import str_to_unicode
  22
+
20 23
 #****************************************************************************
21 24
 # FIXME: This class isn't a mixin anymore, but it still needs attributes from
22 25
 # ipython and does input cache management.  Finish cleanup later...
@@ -24,7 +27,7 @@
24 27
 class Logger(object):
25 28
     """A Logfile class with different policies for file creation"""
26 29
 
27  
-    def __init__(self, home_dir, logfname='Logger.log', loghead='',
  30
+    def __init__(self, home_dir, logfname='Logger.log', loghead=u'',
28 31
                  logmode='over'):
29 32
 
30 33
         # this is the full ipython instance, we need some attributes from it
@@ -59,8 +62,8 @@ def _get_mode(self):
59 62
 
60 63
     logmode = property(_get_mode,_set_mode)
61 64
 
62  
-    def logstart(self,logfname=None,loghead=None,logmode=None,
63  
-                 log_output=False,timestamp=False,log_raw_input=False):
  65
+    def logstart(self, logfname=None, loghead=None, logmode=None,
  66
+                 log_output=False, timestamp=False, log_raw_input=False):
64 67
         """Generate a new log-file with a default header.
65 68
 
66 69
         Raises RuntimeError if the log has already been started"""
@@ -84,7 +87,7 @@ def logstart(self,logfname=None,loghead=None,logmode=None,
84 87
         logmode = self.logmode
85 88
 
86 89
         if logmode == 'append':
87  
-            self.logfile = open(self.logfname,'a')
  90
+            self.logfile = io.open(self.logfname, 'a', encoding='utf-8')
88 91
 
89 92
         elif logmode == 'backup':
90 93
             if isfile(self.logfname):
@@ -94,16 +97,16 @@ def logstart(self,logfname=None,loghead=None,logmode=None,
94 97
                 if isfile(backup_logname):
95 98
                     os.remove(backup_logname)
96 99
                 os.rename(self.logfname,backup_logname)
97  
-            self.logfile = open(self.logfname,'w')
  100
+            self.logfile = io.open(self.logfname, 'w', encoding='utf-8')
98 101
 
99 102
         elif logmode == 'global':
100 103
             self.logfname = os.path.join(self.home_dir,self.logfname)
101  
-            self.logfile = open(self.logfname, 'a')
  104
+            self.logfile = io.open(self.logfname, 'a', encoding='utf-8')
102 105
 
103 106
         elif logmode == 'over':
104 107
             if isfile(self.logfname):
105 108
                 os.remove(self.logfname)
106  
-            self.logfile = open(self.logfname,'w')
  109
+            self.logfile = io.open(self.logfname,'w', encoding='utf-8')
107 110
 
108 111
         elif logmode == 'rotate':
109 112
             if isfile(self.logfname):
@@ -116,7 +119,7 @@ def logstart(self,logfname=None,loghead=None,logmode=None,
116 119
                         num = int(ext[1:-1])+1
117 120
                         os.rename(f, root+'.'+`num`.zfill(3)+'~')
118 121
                 os.rename(self.logfname, self.logfname+'.001~')
119  
-            self.logfile = open(self.logfname,'w')
  122
+            self.logfile = io.open(self.logfname, 'w', encoding='utf-8')
120 123
 
121 124
         if logmode != 'append':
122 125
             self.logfile.write(self.loghead)
@@ -190,13 +193,13 @@ def log_write(self, data, kind='input'):
190 193
             write = self.logfile.write
191 194
             if kind=='input':
192 195
                 if self.timestamp:
193  
-                    write(time.strftime('# %a, %d %b %Y %H:%M:%S\n',
194  
-                                        time.localtime()))
  196
+                    write(str_to_unicode(time.strftime('# %a, %d %b %Y %H:%M:%S\n',
  197
+                                        time.localtime())))
195 198
                 write(data)
196 199
             elif kind=='output' and self.log_output:
197  
-                odata = '\n'.join(['#[Out]# %s' % s
  200
+                odata = u'\n'.join([u'#[Out]# %s' % s
198 201
                                    for s in data.splitlines()])
199  
-                write('%s\n' % odata)
  202
+                write(u'%s\n' % odata)
200 203
             self.logfile.flush()
201 204
 
202 205
     def logstop(self):
13  IPython/core/magics/logging.py
@@ -19,6 +19,7 @@
19 19
 # Our own packages
20 20
 from IPython.core.magic import Magics, magics_class, line_magic
21 21
 from IPython.utils.warn import warn
  22
+from IPython.utils.py3compat import str_to_unicode
22 23
 
23 24
 #-----------------------------------------------------------------------------
24 25
 # Magic implementation classes
@@ -96,7 +97,7 @@ def logstart(self, parameter_s=''):
96 97
             logfname = os.path.expanduser(logfname)
97 98
         self.shell.logfile = logfname
98 99
 
99  
-        loghead = '# IPython log file\n\n'
  100
+        loghead = u'# IPython log file\n\n'
100 101
         try:
101 102
             logger.logstart(logfname, loghead, logmode, log_output, timestamp,
102 103
                             log_raw_input)
@@ -121,12 +122,12 @@ def logstart(self, parameter_s=''):
121 122
                 log_write = logger.log_write
122 123
                 output_hist = self.shell.history_manager.output_hist
123 124
                 for n in range(1,len(input_hist)-1):
124  
-                    log_write(input_hist[n].rstrip() + '\n')
  125
+                    log_write(input_hist[n].rstrip() + u'\n')
125 126
                     if n in output_hist:
126  
-                        log_write(repr(output_hist[n]),'output')
  127
+                        log_write(str_to_unicode(repr(output_hist[n])),'output')
127 128
             else:
128  
-                logger.log_write('\n'.join(input_hist[1:]))
129  
-                logger.log_write('\n')
  129
+                logger.log_write(u'\n'.join(input_hist[1:]))
  130
+                logger.log_write(u'\n')
130 131
             if timestamp:
131 132
                 # re-enable timestamping
132 133
                 logger.timestamp = True
@@ -142,7 +143,7 @@ def logstop(self, parameter_s=''):
142 143
         In order to start logging again, a new %logstart call needs to be made,
143 144
         possibly (though not necessarily) with a new filename, mode and other
144 145
         options."""
145  
-        self.logger.logstop()
  146
+        self.shell.logger.logstop()
146 147
 
147 148
     @line_magic
148 149
     def logoff(self, parameter_s=''):
14  IPython/core/tests/test_logger.py
... ...
@@ -1,6 +1,9 @@
1 1
 """Test IPython.core.logger"""
2 2
 
  3
+import os.path
  4
+
3 5
 import nose.tools as nt
  6
+from IPython.utils.tempdir import TemporaryDirectory
4 7
 
5 8
 _ip = get_ipython()
6 9
 
@@ -16,4 +19,13 @@ def test_logstart_inaccessible_file():
16 19
         _ip.run_cell("a=1")                 # Check it doesn't try to log this
17 20
     finally:
18 21
         _ip.logger.log_active = False  # If this fails, don't let later tests fail
19  
-    
  22
+
  23
+def test_logstart_unicode():
  24
+    with TemporaryDirectory() as tdir:
  25
+        logfname = os.path.join(tdir, "test_unicode.log")
  26
+        _ip.run_cell("'abc€'")
  27
+        try:
  28
+            _ip.magic("logstart -to %s" % logfname)
  29
+            _ip.run_cell("'abc€'")
  30
+        finally:
  31
+            _ip.logger.logstop()
Commit_comment_tip

Tip: You can add notes to lines in a file. Hover to the left of a line to make a note

Something went wrong with that request. Please try again.