root/trunk/src/__init__.py

Revision 468, 8.9 KB (checked in by emuller, 20 months ago)

Alternate solution to psyco 32bit limitation & unwanted warnings

Line 
1# -*- coding: utf-8 -*-
2"""
3NeuroTools
4==========
5
6NeuroTools is not a neural simulator, but a collection of tools
7to support all tasks associated with a neural simulation project which
8are not handled by the simulation engine.
9
10For more information see:
11http://neuralensemble.org/NeuroTools
12
13
14Available subpackages
15---------------------
16
17NeuroTools functionality is modularized as follows:
18
19signals    - provides core classes for manipulation of spike trains and analog signals.
20spike2     - offers an easy way for reading data from CED's Spike2 Son files.
21parameters - contains classes for managing large, hierarchical parameter sets.
22analysis   - cross-correlation, tuning curves, frequency spectrum, etc.
23stgen      - various stochastic process generators relevant for Neuroscience
24             (OU, poisson, inhomogenous gamma, ...).
25utilities  - miscellaneous stuff, like SRB access.
26io         - NeuroTools support for reading and writing of files in various formats.
27plotting   - routines for plotting and visualization.
28datastore  - a consistent interface for persistent data storage (e.g. for caching intermediate results).
29random     - a set of classes representing statistical distributions
30
31Sub-package specific documentation is available by importing the
32sub-package, and requesting help on it:
33
34>>> import NeuroTools.signals
35>>> help(NeuroTools.signals)
36"""
37
38__all__ = ['analysis', 'parameters', 'plotting', 'signals', 'stgen', 'io', 'datastore', 'utilities', 'spike2', 'random', 'optimize', 'tisean']
39__version__ = "0.1.0 (Asynchronous Astrocyte)"
40import warnings
41import platform
42from operator import __or__
43
44#########################################################
45## ALL DEPENDENCIES SHOULD BE GATHERED HERE FOR CLARITY
46#########################################################
47
48# The nice thing would be to gather every non standard
49# dependency here, in order to centralize the warning
50# messages and the check
51dependencies = {'pylab' : {'website' : 'http://matplotlib.sourceforge.net/', 'is_present' : False, 'check':False},
52                'matplotlib': {'website' : 'http://matplotlib.sourceforge.net/', 'is_present' : False, 'check':False},
53                'tables': {'website' : 'http://www.pytables.org/moin' , 'is_present' : False, 'check':False},
54                'psyco' : {'website' : 'http://psyco.sourceforge.net/', 'is_present' : False, 'check':False},
55                'pygsl' : {'website' : 'http://pygsl.sourceforge.net/', 'is_present' : False, 'check':False},
56                'PIL'   : {'website' : 'http://www.pythonware.com/products/pil/', 'is_present':False, 'check':False},
57                'scipy' : {'website' : 'http://numpy.scipy.org/' , 'is_present' : False, 'check':False},
58                'NeuroTools.facets.hdf5' : {'website' : None, 'is_present' : False, 'check':False},
59                'srblib'  : {'website' : 'http://www.sdsc.edu/srb/index.php/Python', 'is_present' : False, 'check':False},
60                'rpy'     : {'website' : 'http://rpy.sourceforge.net/', 'is_present' : False, 'check':False},
61                'rpy2'     : {'website' : 'http://rpy.sourceforge.net/rpy2.html', 'is_present' : False, 'check':False},
62
63                'django'  : {'website': 'http://www.djangoproject.com', 'is_present': False, 'check': False},
64                'IPython' : {'website': 'http://ipython.scipy.org/', 'is_present': False, 'check': False},
65                'interval': {'website': 'http://pypi.python.org/pypi/interval/1.0.0', 'is_present': False, 'check': False},
66                'TableIO' : {'website': 'http://kochanski.org/gpk/misc/TableIO.html', 'is_present': False, 'check': False},
67                ## Add here your extensions ###
68               }
69
70
71# Don't raise warnings for psyco on non-32bit systems
72if platform.machine() != 'i386':
73    dependencies['psyco']['check']=True
74
75#########################################################
76## Function to display error messages on the dependencies
77#########################################################
78
79
80class DependencyWarning(UserWarning):
81    pass
82
83def get_import_warning(name):
84    return '''** %s ** package is not installed.
85To have functions using %s please install the package.
86website : %s
87''' %(name, name, dependencies[name]['website'])
88
89def get_runtime_warning(name, errmsg):
90    return '** %s ** package is installed but cannot be imported. The error message is: %s' %(name, errmsg)
91
92def check_numpy_version():
93    import numpy
94    numpy_version = numpy.__version__.split(".")[0:2]
95    numpy_version = float(".".join(numpy_version))
96    if numpy_version >= 1.2:
97        return True
98    else:
99        return False
100
101def check_pytables_version():
102   #v = [int(s) for s in __version__.split('.')]
103   if tables.__version__<= 2: #1.4: #v[0] < 1 or (v[0] == 1 and v[1] < 4):
104       raise Exception('PyTables version must be >= 1.4, installed version is %s' % __version__)
105
106def check_dependency(name):
107    if dependencies[name]['check']:
108        return dependencies[name]['is_present']
109    else:
110        try:
111            exec("import %s" %name)
112            dependencies[name]['is_present'] = True
113        except ImportError:
114            warnings.warn(get_import_warning(name), DependencyWarning)
115        except RuntimeError, errmsg:
116            warnings.warn(get_runtime_warning(name, errmsg), DependencyWarning)
117        dependencies[name]['check'] = True
118        return dependencies[name]['is_present']
119
120
121
122# Setup fancy logging
123
124red     = 0010; green  = 0020; yellow = 0030; blue = 0040;
125magenta = 0050; cyan   = 0060; bright = 0100
126try:
127    import ll.ansistyle
128    def colour(col, text):
129        try:
130            return unicode(ll.ansistyle.Text(col, unicode(text)))
131        except UnicodeDecodeError, e:
132            raise UnicodeDecodeError("%s. text was %s" % (e, text))
133except ImportError:
134    def colour(col, text):
135            return text
136       
137import logging
138
139# Add a header() level to logging
140logging.HEADER = (logging.WARNING + logging.ERROR)/2 # higher than warning, lower than error
141logging.addLevelName(logging.HEADER, 'HEADER')
142
143root = logging.getLogger()
144
145def root_header(msg, *args, **kwargs):
146    if len(root.handlers) == 0:
147        basicConfig()
148    apply(root.header, (msg,)+args, kwargs)
149
150def logger_header(self, msg, *args, **kwargs):
151    if self.manager.disable >= logging.HEADER:
152        return
153    if logging.HEADER >= self.getEffectiveLevel():
154        apply(self._log, (logging.HEADER, msg, args), kwargs)
155
156logging.Logger.header = logger_header
157logging.header = root_header
158
159class FancyFormatter(logging.Formatter):
160    """
161    A log formatter that colours and indents the log message depending on the level.
162    """
163   
164    DEFAULT_COLOURS = {
165        'CRITICAL': bright+red,
166        'ERROR': red,
167        'WARNING': magenta,
168        'HEADER': bright+yellow,
169        'INFO': cyan,
170        'DEBUG': green
171    }
172   
173    DEFAULT_INDENTS = {
174        'CRITICAL': "",
175        'ERROR': "",
176        'WARNING': "",
177        'HEADER': "",
178        'INFO': "  ",
179        'DEBUG': "    ",
180    }
181   
182    def __init__(self, fmt=None, datefmt=None, colours=DEFAULT_COLOURS, mpi_rank=None):
183        logging.Formatter.__init__(self, fmt, datefmt)
184        self._colours = colours
185        self._indents = FancyFormatter.DEFAULT_INDENTS
186        if mpi_rank is None:
187            self.prefix = ""
188        else:
189            self.prefix = "%-3d" % mpi_rank
190   
191    def format(self, record):
192        s = logging.Formatter.format(self, record)
193        if record.levelname == "HEADER":
194            s = "=== %s ===" % s
195        if self._colours:
196            s = colour(self._colours[record.levelname], s)
197        return self.prefix + self._indents[record.levelname] + s
198
199
200class NameOrLevelFilter(logging.Filter):
201    """
202    Logging filter which allows messages that either have an approved name, or
203    have a level >= the level specified.
204   
205    The intended use is when you want to receive most messages at a high level,
206    but receive certain named messages at a lower level, e.g. for debugging a
207    particular component.
208    """
209    def __init__(self, names=[], level=logging.INFO):
210        self.names = names
211        self.level = level
212       
213    def filter(self, record):
214        if len(self.names) == 0:
215            allow_by_name = True
216        else:
217            allow_by_name = record.name in self.names
218        allow_by_level = record.levelno >= self.level
219        return (allow_by_name or allow_by_level)
220
221
222def init_logging(filename, file_level=logging.INFO, console_level=logging.WARNING, mpi_rank=None):
223    if mpi_rank is None:
224        mpi_fmt = ""
225    else:
226        mpi_fmt = "%3d " % mpi_rank
227    logging.basicConfig(level=file_level,
228                        format='%%(asctime)s %s%%(name)-10s %%(levelname)-6s %%(message)s [%%(pathname)s:%%(lineno)d]' % mpi_fmt,
229                        filename=filename,
230                        filemode='w')
231    console = logging.StreamHandler()
232    console.setLevel(console_level)
233    console.setFormatter(FancyFormatter('%(message)s', mpi_rank=mpi_rank))
234    logging.getLogger('').addHandler(console)
235    return console
Note: See TracBrowser for help on using the browser.