##// END OF EJS Templates
Merge pull request #1627 from minrk/msgspec...
Merge pull request #1627 from minrk/msgspec Test the Message Spec and add our zmq subpackage to the test suite. It uses Traitlets to perform validation of keys. Checks right now are not very strict, as (almost) any key is allowed to be None, as long as it is defined. This is because I simply do not know which keys are allowed to be None, and this is not discussed in the specification. If no keys are allowed to be None, we violate that all over the place. Parametric tests are used, so every key validation counts as a test (147!). Message spec doc was found to misrepresent code in a few points, and some changes were made: * spec had error keys as `exc_name/value`, but we are actually using `ename/value` (docs updated to match code) * payloads were inaccurate - list of dicts, rather than single dict, and transformed_output is a payload, not top-level in exec-reply (docs update to match code). * in oinfo_request, detail_level was in message spec, but not actually implemented (code updated to match docs). History messages are not yet tested, but I think I get at least elementary coverage of everything else in the doc.

File last commit:

r4872:34c10438
r6567:232fa81a merge
Show More
logger.py
217 lines | 7.6 KiB | text/x-python | PythonLexer
Fernando Perez
Remove all direct shell access from logger....
r3086 """Logger class for IPython's logging facilities.
fperez
Reorganized the directory for ipython/ to have its own dir, which is a bit...
r0 """
#*****************************************************************************
# Copyright (C) 2001 Janko Hauser <jhauser@zscout.de> and
fperez
Small fix in ultraTB, and fix autocall....
r88 # Copyright (C) 2001-2006 Fernando Perez <fperez@colorado.edu>
fperez
Reorganized the directory for ipython/ to have its own dir, which is a bit...
r0 #
# Distributed under the terms of the BSD License. The full license is in
# the file COPYING, distributed as part of this software.
#*****************************************************************************
#****************************************************************************
# Modules and globals
# Python standard modules
fperez
Cosmetic cleanups: put all imports in a single line, and sort them...
r52 import glob
import os
fperez
Major cleanups and changes, see changelog/changeset for full details.
r60 import time
fperez
Reorganized the directory for ipython/ to have its own dir, which is a bit...
r0
#****************************************************************************
fperez
Major cleanups and changes, see changelog/changeset for full details.
r60 # FIXME: This class isn't a mixin anymore, but it still needs attributes from
# ipython and does input cache management. Finish cleanup later...
class Logger(object):
"""A Logfile class with different policies for file creation"""
Fernando Perez
Remove all direct shell access from logger....
r3086 def __init__(self, home_dir, logfname='Logger.log', loghead='',
logmode='over'):
fperez
Reorganized the directory for ipython/ to have its own dir, which is a bit...
r0
fperez
Major cleanups and changes, see changelog/changeset for full details.
r60 # this is the full ipython instance, we need some attributes from it
# which won't exist until later. What a mess, clean up later...
Fernando Perez
Remove all direct shell access from logger....
r3086 self.home_dir = home_dir
fperez
Major cleanups and changes, see changelog/changeset for full details.
r60
self.logfname = logfname
self.loghead = loghead
self.logmode = logmode
self.logfile = None
fperez
Add -r option to %logstart, to log 'raw' input instead of the processed one....
r305 # Whether to log raw or processed input
self.log_raw_input = False
fperez
Major cleanups and changes, see changelog/changeset for full details.
r60 # whether to also log output
self.log_output = False
# whether to put timestamps before each log entry
self.timestamp = False
# activity control flags
self.log_active = False
# logmode is a validated property
def _set_mode(self,mode):
if mode not in ['append','backup','global','over','rotate']:
raise ValueError,'invalid log mode %s given' % mode
self._logmode = mode
def _get_mode(self):
return self._logmode
logmode = property(_get_mode,_set_mode)
Bernardo B. Marques
remove all trailling spaces
r4872
fperez
Major cleanups and changes, see changelog/changeset for full details.
r60 def logstart(self,logfname=None,loghead=None,logmode=None,
fperez
Add -r option to %logstart, to log 'raw' input instead of the processed one....
r305 log_output=False,timestamp=False,log_raw_input=False):
fperez
Major cleanups and changes, see changelog/changeset for full details.
r60 """Generate a new log-file with a default header.
Raises RuntimeError if the log has already been started"""
if self.logfile is not None:
raise RuntimeError('Log file is already active: %s' %
self.logfname)
Bernardo B. Marques
remove all trailling spaces
r4872
fperez
Add -r option to %logstart, to log 'raw' input instead of the processed one....
r305 # The parameters can override constructor defaults
if logfname is not None: self.logfname = logfname
if loghead is not None: self.loghead = loghead
if logmode is not None: self.logmode = logmode
# Parameters not part of the constructor
fperez
Major cleanups and changes, see changelog/changeset for full details.
r60 self.timestamp = timestamp
self.log_output = log_output
fperez
Add -r option to %logstart, to log 'raw' input instead of the processed one....
r305 self.log_raw_input = log_raw_input
Bernardo B. Marques
remove all trailling spaces
r4872
fperez
Major cleanups and changes, see changelog/changeset for full details.
r60 # init depending on the log mode requested
isfile = os.path.isfile
logmode = self.logmode
if logmode == 'append':
self.logfile = open(self.logfname,'a')
elif logmode == 'backup':
if isfile(self.logfname):
fperez
Reorganized the directory for ipython/ to have its own dir, which is a bit...
r0 backup_logname = self.logfname+'~'
# Manually remove any old backup, since os.rename may fail
# under Windows.
fperez
Major cleanups and changes, see changelog/changeset for full details.
r60 if isfile(backup_logname):
fperez
Reorganized the directory for ipython/ to have its own dir, which is a bit...
r0 os.remove(backup_logname)
os.rename(self.logfname,backup_logname)
self.logfile = open(self.logfname,'w')
fperez
Major cleanups and changes, see changelog/changeset for full details.
r60
elif logmode == 'global':
Fernando Perez
Remove all direct shell access from logger....
r3086 self.logfname = os.path.join(self.home_dir,self.logfname)
fperez
Reorganized the directory for ipython/ to have its own dir, which is a bit...
r0 self.logfile = open(self.logfname, 'a')
fperez
Major cleanups and changes, see changelog/changeset for full details.
r60
elif logmode == 'over':
if isfile(self.logfname):
Bernardo B. Marques
remove all trailling spaces
r4872 os.remove(self.logfname)
fperez
Major cleanups and changes, see changelog/changeset for full details.
r60 self.logfile = open(self.logfname,'w')
elif logmode == 'rotate':
if isfile(self.logfname):
Bernardo B. Marques
remove all trailling spaces
r4872 if isfile(self.logfname+'.001~'):
fperez
Reorganized the directory for ipython/ to have its own dir, which is a bit...
r0 old = glob.glob(self.logfname+'.*~')
old.sort()
old.reverse()
for f in old:
root, ext = os.path.splitext(f)
num = int(ext[1:-1])+1
os.rename(f, root+'.'+`num`.zfill(3)+'~')
os.rename(self.logfname, self.logfname+'.001~')
self.logfile = open(self.logfname,'w')
Bernardo B. Marques
remove all trailling spaces
r4872
fperez
Major cleanups and changes, see changelog/changeset for full details.
r60 if logmode != 'append':
self.logfile.write(self.loghead)
fperez
Reorganized the directory for ipython/ to have its own dir, which is a bit...
r0
fperez
Major cleanups and changes, see changelog/changeset for full details.
r60 self.logfile.flush()
Luis Pedro Coelho
BUG Move setting of log_active flag down...
r3887 self.log_active = True
fperez
Reorganized the directory for ipython/ to have its own dir, which is a bit...
r0
def switch_log(self,val):
fperez
Major cleanups and changes, see changelog/changeset for full details.
r60 """Switch logging on/off. val should be ONLY a boolean."""
fperez
Reorganized the directory for ipython/ to have its own dir, which is a bit...
r0
fperez
Major cleanups and changes, see changelog/changeset for full details.
r60 if val not in [False,True,0,1]:
fperez
Reorganized the directory for ipython/ to have its own dir, which is a bit...
r0 raise ValueError, \
fperez
Major cleanups and changes, see changelog/changeset for full details.
r60 'Call switch_log ONLY with a boolean argument, not with:',val
Bernardo B. Marques
remove all trailling spaces
r4872
fperez
Major cleanups and changes, see changelog/changeset for full details.
r60 label = {0:'OFF',1:'ON',False:'OFF',True:'ON'}
fperez
Reorganized the directory for ipython/ to have its own dir, which is a bit...
r0
fperez
Major cleanups and changes, see changelog/changeset for full details.
r60 if self.logfile is None:
fperez
Reorganized the directory for ipython/ to have its own dir, which is a bit...
r0 print """
fperez
Major cleanups and changes, see changelog/changeset for full details.
r60 Logging hasn't been started yet (use logstart for that).
fperez
Reorganized the directory for ipython/ to have its own dir, which is a bit...
r0
%logon/%logoff are for temporarily starting and stopping logging for a logfile
which already exists. But you must first start the logging process with
%logstart (optionally giving a logfile name)."""
Bernardo B. Marques
remove all trailling spaces
r4872
fperez
Reorganized the directory for ipython/ to have its own dir, which is a bit...
r0 else:
fperez
Major cleanups and changes, see changelog/changeset for full details.
r60 if self.log_active == val:
fperez
Reorganized the directory for ipython/ to have its own dir, which is a bit...
r0 print 'Logging is already',label[val]
else:
print 'Switching logging',label[val]
fperez
Major cleanups and changes, see changelog/changeset for full details.
r60 self.log_active = not self.log_active
self.log_active_out = self.log_active
fperez
Reorganized the directory for ipython/ to have its own dir, which is a bit...
r0
def logstate(self):
"""Print a status message about the logger."""
fperez
Major cleanups and changes, see changelog/changeset for full details.
r60 if self.logfile is None:
fperez
Reorganized the directory for ipython/ to have its own dir, which is a bit...
r0 print 'Logging has not been activated.'
else:
fperez
Major cleanups and changes, see changelog/changeset for full details.
r60 state = self.log_active and 'active' or 'temporarily suspended'
fperez
doc fixes to logging
r68 print 'Filename :',self.logfname
print 'Mode :',self.logmode
print 'Output logging :',self.log_output
fperez
Minor fix to diagnostics, forgot to list raw input.
r306 print 'Raw input log :',self.log_raw_input
fperez
doc fixes to logging
r68 print 'Timestamping :',self.timestamp
print 'State :',state
fperez
Reorganized the directory for ipython/ to have its own dir, which is a bit...
r0
Fernando Perez
Remove all direct shell access from logger....
r3086 def log(self, line_mod, line_ori):
"""Write the sources to a log.
fperez
Add -r option to %logstart, to log 'raw' input instead of the processed one....
r305
Inputs:
- line_mod: possibly modified input, such as the transformations made
by input prefilters or input handlers of various kinds. This should
always be valid Python.
Fernando Perez
Remove all direct shell access from logger....
r3086 - line_ori: unmodified input line from the user. This is not
necessarily valid Python.
"""
fperez
Add -r option to %logstart, to log 'raw' input instead of the processed one....
r305
# Write the log line, but decide which one according to the
# log_raw_input flag, set when the log is started.
if self.log_raw_input:
self.log_write(line_ori)
else:
self.log_write(line_mod)
fperez
Major cleanups and changes, see changelog/changeset for full details.
r60
Fernando Perez
Remove all direct shell access from logger....
r3086 def log_write(self, data, kind='input'):
fperez
Major cleanups and changes, see changelog/changeset for full details.
r60 """Write data to the log file, if active"""
vivainio
Merged 1071-1076 from banches/0.7.1
r145 #print 'data: %r' % data # dbg
fperez
Major cleanups and changes, see changelog/changeset for full details.
r60 if self.log_active and data:
write = self.logfile.write
if kind=='input':
if self.timestamp:
write(time.strftime('# %a, %d %b %Y %H:%M:%S\n',
time.localtime()))
Fernando Perez
Remove all direct shell access from logger....
r3086 write(data)
fperez
Major cleanups and changes, see changelog/changeset for full details.
r60 elif kind=='output' and self.log_output:
odata = '\n'.join(['#[Out]# %s' % s
Fernando Perez
Remove all direct shell access from logger....
r3086 for s in data.splitlines()])
fperez
Major cleanups and changes, see changelog/changeset for full details.
r60 write('%s\n' % odata)
fperez
Reorganized the directory for ipython/ to have its own dir, which is a bit...
r0 self.logfile.flush()
fperez
- Add %logstop functionality to fully stop logger after turning it on....
r895 def logstop(self):
"""Fully stop logging and close log file.
In order to start logging again, a new logstart() call needs to be
made, possibly (though not necessarily) with a new filename, mode and
other options."""
Bernardo B. Marques
remove all trailling spaces
r4872
Bernard Paulus
Issue https://github.com/ipython/ipython/issues/832 resolution
r4870 if self.logfile is not None:
self.logfile.close()
self.logfile = None
else:
print "Logging hadn't been started."
fperez
- Add %logstop functionality to fully stop logger after turning it on....
r895 self.log_active = False
# For backwards compatibility, in case anyone was using this.
close_log = logstop