# -*- coding: utf-8 -*- # ***************************************************************************** # # This program is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software # Foundation; either version 2 of the License, or (at your option) any later # version. # # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more # details. # # You should have received a copy of the GNU General Public License along with # this program; if not, write to the Free Software Foundation, Inc., # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Module authors: # Enrico Faulhaber # # ***************************************************************************** """Define helpers""" import linecache import socket import sys import threading import traceback import importlib from os import path, environ repodir = path.abspath(path.join(path.dirname(__file__), '..', '..')) if path.splitext(sys.executable)[1] == ".exe" and not path.basename(sys.executable).startswith('python'): CONFIG = { 'piddir': './', 'logdir': './log', 'confdir': './', } elif not path.exists(path.join(repodir, '.git')): CONFIG = { 'piddir': '/var/run/secop', 'logdir': '/var/log', 'confdir': '/etc/secop', } else: CONFIG = { 'piddir': path.join(repodir, 'pid'), 'logdir': path.join(repodir, 'log'), 'confdir': path.join(repodir, 'cfg'), } # overwrite with env variables SECOP_LOGDIR, SECOP_PIDDIR, SECOP_CONFDIR, if present for dirname in CONFIG: CONFIG[dirname] = environ.get('SECOP_%s' % dirname.upper(), CONFIG[dirname]) # this is not customizable CONFIG['basedir'] = repodir unset_value = object() class lazy_property: """A property that calculates its value only once.""" def __init__(self, func): self._func = func self.__name__ = func.__name__ self.__doc__ = func.__doc__ def __get__(self, obj, obj_class): if obj is None: return self obj.__dict__[self.__name__] = self._func(obj) return obj.__dict__[self.__name__] class attrdict(dict): """a normal dict, providing access also via attributes""" def __getattr__(self, key): return self[key] def __setattr__(self, key, value): self[key] = value def clamp(_min, value, _max): """return the median of 3 values, i.e. value if min <= value <= max, else min or max depending on which side value lies outside the [min..max] interval. This works even when min > max! """ # return median, i.e. clamp the the value between min and max return sorted([_min, value, _max])[1] def get_class(spec): """loads a class given by string in dotted notaion (as python would do)""" modname, classname = spec.rsplit('.', 1) if modname.startswith('secop'): module = importlib.import_module(modname) else: # rarely needed by now.... module = importlib.import_module('secop.' + modname) return getattr(module, classname) def mkthread(func, *args, **kwds): t = threading.Thread( name='%s:%s' % (func.__module__, func.__name__), target=func, args=args, kwargs=kwds) t.daemon = True t.start() return t def formatExtendedFrame(frame): ret = [] for key, value in frame.f_locals.items(): try: valstr = repr(value)[:256] except Exception: valstr = '' ret.append(' %-20s = %s\n' % (key, valstr)) ret.append('\n') return ret def formatExtendedTraceback(exc_info=None): if exc_info is None: etype, value, tb = sys.exc_info() else: etype, value, tb = exc_info ret = ['Traceback (most recent call last):\n'] while tb is not None: frame = tb.tb_frame filename = frame.f_code.co_filename item = ' File "%s", line %d, in %s\n' % (filename, tb.tb_lineno, frame.f_code.co_name) linecache.checkcache(filename) line = linecache.getline(filename, tb.tb_lineno, frame.f_globals) if line: item = item + ' %s\n' % line.strip() ret.append(item) if filename not in ('