✏️ 编辑:utilities.py
路径:
/virtual/bigbrother/public_html/edream-c.com/cr/utilities.py
大小:42.3 KB · 修改:2014-04-14 07:45:00 · 权限:0755 · 可写
← 返回目录
👁 查看
⬇ 下载
#!/usr/bin/python # -*- coding: utf-8 -*- # TOMUSS: The Online Multi User Simple Spreadsheet # Copyright (C) 2008-2012 Thierry EXCOFFIER, Universite Claude Bernard # # 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 # # Contact: Thierry.EXCOFFIER@bat710.univ-lyon1.fr import resource import time import re import os import sys import traceback import gettext import cgi import threading import shutil import gc import ast from . import configuration def read_file(filename): f = open(filename, 'r') c = f.read() f.close() return c def write_file(filename, content): warn('%s : %d' % (filename, len(content)), what='debug') f = open(filename, 'w') f.write(content) f.close() def write_file_safe(filename, content): write_file(filename, content) if configuration.backup: write_file(configuration.backup + filename, content) lock_list = [] def add_a_lock(fct): """Add a lock to a function to forbid simultaneous call""" def f(*arg, **keys): warn('[[[' + f.fct.func_name + ']]]', what='debug') f.the_lock.acquire() try: r = f.fct(*arg, **keys) finally: f.the_lock.release() return r f.fct = fct f.the_lock = threading.Lock() f.__doc__ = fct.__doc__ f.func_name = fct.func_name f.__module__ = fct.__module__ lock_list.append(f) return f def append_file_unlocked(filename, content): """Paranoid : check file size before and after append""" try: before = os.path.getsize(filename) except OSError: before = 0 f = open(filename, 'a') f.write(content) f.close() after = os.path.getsize(filename) if before + len(content) != after: raise IOError("Append file failed %s before=%d + %d ==> %d" % ( filename, before, len(content), after)) if filename.endswith('.py'): try: os.unlink(filename + 'c') except OSError: pass filename_to_bufferize = None filename_buffer = [] def bufferize_this_file(filename): """Should be called with None to flush the buffered content""" global filename_to_bufferize, filename_buffer if filename == filename_to_bufferize: return append_file.the_lock.acquire() try: if filename_to_bufferize: append_file_unlocked(filename_to_bufferize, ''.join(filename_buffer)) filename_to_bufferize = filename filename_buffer = [] finally: append_file.the_lock.release() @add_a_lock def append_file(filename, content): if filename == filename_to_bufferize: filename_buffer.append(content) else: append_file_unlocked(filename, content) def append_file_safe(filename, content): append_file(filename, content) if configuration.backup: append_file(configuration.backup + filename, content) def unlink_safe(filename, do_backup=True): if do_backup and os.path.exists(filename): dirname = os.path.join('Trash', time.strftime('%Y%m%d')) mkpath(dirname) shutil.move(filename, os.path.join(dirname, filename.replace(os.path.sep, '___')) ) try: os.unlink(filename) except OSError: pass if configuration.backup: try: os.unlink(configuration.backup + filename) except OSError: pass def rename_safe(old_filename, new_filename): unlink_safe(new_filename) os.rename(old_filename, new_filename) if configuration.backup: os.rename(configuration.backup + old_filename, configuration.backup + new_filename) def symlink_safe(old_filename, new_filename): os.symlink(old_filename, new_filename) if configuration.backup: os.symlink(old_filename, configuration.backup + new_filename) def safe(txt): return re.sub('[^0-9a-zA-Z-.]', '_', txt) def safe_quote(txt): return re.sub('[^\'0-9a-zA-Z-.]', '_', txt) def safe_space(txt): return re.sub('[^0-9a-zA-Z-. ]', '_', txt) def safe_space_quote(txt): return re.sub('[^\'0-9a-zA-Z-. ]', '_', txt) def flat(txt): return txt.translate(u"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f ! #$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~?\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f?????Y|?????????????'u?.????????AAAAAA?CEEEEIIIIDNOOOOOXOUUUUY?Baaaaaa?ceeeeiiiionooooo??uuuuy?y") def same(a, b): return flat(a).lower() == flat(b).lower() def university_year(year=None, semester=None): if semester is None: semester = configuration.year_semester[1] if year is None: year = configuration.year_semester[0] try: i = configuration.semesters.index(semester) except ValueError: return year return year + configuration.semesters_year[i] def university_year_semester(year=None, semester=None): "Return the first year+semester of the university" if semester is None: semester = configuration.year_semester[1] if year is None: year = configuration.year_semester[0] try: i = configuration.semesters.index(semester) except ValueError: return year, semester return (year + configuration.semesters_year[i], configuration.university_semesters[0]) def next_year_semester(year, semester): try: i = (configuration.semesters.index(semester) + 1) % len( configuration.semesters) except ValueError: return year + 1, semester if i != 0: return year, configuration.semesters[i] else: return year + 1, configuration.semesters[i] def previous_year_semester(year, semester): try: i = (configuration.semesters.index(semester) + len(configuration.semesters) - 1) % len( configuration.semesters) except ValueError: return year - 1, semester if i != len(configuration.semesters) - 1: return year, configuration.semesters[i] else: return year - 1, configuration.semesters[i] def semester_key(year, semester): try: return year, configuration.semesters.index(semester) except ValueError: return year, semester def year_semester_from_date(yyyymm): """The time can be longer""" month = int(yyyymm[4:6]) year = int(yyyymm[:4]) for s, m in zip(configuration.semesters,configuration.semesters_months): if m[0] <= month <= m[1]: return year, s if m[0] <= 12+month <= m[1]: return year-1, s live_log = None def warn(text, what='info'): if what in configuration.do_not_display: return x = [] try: for i in range(1, 4): x.append(sys._getframe(i).f_code.co_name) except ValueError: pass x.reverse() x = '/'.join(x).rjust(50)[-50:] x = '%c %13.2f %4d %s %s\n' % ( what[0].upper(), time.time(), resource.getrusage(resource.RUSAGE_SELF)[2]//1000, x, text) sys.stderr.write(x) global live_log if live_log: try: live_log.write(x) except: live_log = None @add_a_lock def send_mail(to, subject, message, frome=None, show_to=False, reply_to=None, error_to=None): "Not safe with user given subject" import smtplib if isinstance(to, list) or isinstance(to, tuple): recipients = to else: recipients = [to] if frome == None: frome = configuration.maintainer new_to = [] for addr in recipients: if '@' not in addr or '.' not in addr: continue try: new_to.append(addr.encode('ascii')) except UnicodeEncodeError: warn('bad email address: ' + repr(addr), what='error') to = new_to if len(to) == 0: return header = "From: " + frome + '\n' if isinstance(subject, unicode): s = subject.encode("utf-8") else: s = subject header += "Subject: " + s.replace('\n',' ').replace('\r',' ') + '\n' if len(to) == 1: header += "To: " + to[0] + '\n' elif show_to: for tto in to: header += "To: " + tto + '\n' if reply_to: header += 'Reply-To: ' + reply_to + '\n' if error_to: header += 'Error-To: ' + error_to + '\n' if message.startswith('<html>'): header += 'Content-Type: text/html; charset=UTF-8\n' else: if isinstance(message, unicode): header += 'Content-Type: text/plain; charset=UTF-8\n' if isinstance(message, unicode): message = message.encode('utf-8') while True: # Stop only if the mail is sent try: smtpresult = send_mail.session.sendmail(frome, recipients, header + '\n' + message) break except smtplib.SMTPRecipientsRefused: warn("Can't deliver mail to " + repr(recipients)) break except smtplib.SMTPServerDisconnected: # It is normal: connection is closed by SMTP if unused send_mail.session = smtplib.SMTP(configuration.smtpserver) continue except: if send_mail.session is not None: send_backtrace('from=%s\nrecipients=%s\nheaders=%s' % (repr(frome), repr(recipients), repr(header))) send_mail.session = smtplib.SMTP(configuration.smtpserver) try: if smtpresult: errstr = "" for recip in smtpresult.keys(): errstr += _("MSG_utilities_smtp_error") % recip \ + smtpresult[recip][0] + ' ' + smtpresult[recip][1] send_mail.session = None return errstr except: return 'BUG in utilities.send_mail' send_mail.session = None thread_list = [] def start_new_thread_immortal(fct, args, send_mail=True): start_new_thread(fct, args, send_mail=send_mail, immortal=True) def start_new_thread(fct, args, send_mail=True, immortal=False): class T(threading.Thread): def __init__(self): self.send_mail = send_mail self.immortal = immortal self.fct = fct self.args = args threading.Thread.__init__(self) def run(self): thread_list.append(self) warn("Start %s" % self) # turn around a locking problem BUG in python threads while True: try: time.strptime('2010', '%Y') break except: warn('strptime' + str(self), what='error') time.sleep(0.1) while True: warn('Call ' + self.fct.func_name) try: self.fct(*self.args) except: warn("Exception in %s" % self, what="Error") if self.send_mail: send_backtrace("Exception in %s" % self) if not self.immortal: break thread_list.remove(self) def backtrace_html(self): return str(self) def __str__(self): return 'Thread immortal=%-5s send_mail=%-5s %s' % ( self.immortal, self.send_mail, fct.func_name) def stack(self): return (str(self) + '\n' + ''.join(traceback.format_stack( sys._current_frames()[self.ident])[3:])) t = T() t.setDaemon(True) t.start() def stop_threads(): sys.exit(0) for t in threading.enumerate(): t.join() send_mail_in_background_list = [] def sendmail_thread(): """Send the mail in background with a minimal time between mails""" while send_mail_in_background_list: time.sleep(configuration.time_between_mails) send_mail(*send_mail_in_background_list.pop(0)) def send_mail_in_background(to, subject, message, frome=None, show_to=False, reply_to=None, error_to=None): send_mail_in_background_list.append((to, subject, message, frome, show_to, reply_to, error_to)) start_job(sendmail_thread, 1) def js(t): if isinstance(t, basestring): # return repr(unicode(t,'utf8').encode('latin1')) return '"' + t.replace('\\','\\\\').replace('"','\\"').replace('>','\\x3E').replace('<','\\x3C').replace('&', '\\x26').replace('\r','').replace('\n','\\n') + '"' elif isinstance(t, float): return '%g' % t elif isinstance(t, dict): return '{' + ','.join("'%s':%s" % (k, js(v)) for k, v in t.items()) + '}' elif isinstance(t, tuple): return str(list(t)) else: return str(t) def js2(t): return '"' + t.replace('\\','\\\\').replace('"','\\"').replace('\n','\\n') + '"' def mkpath(path, create_init=True, mode=0777): s = '' for i in path.split(os.path.sep): s += i + os.path.sep try: os.mkdir(s, mode) if create_init: write_file(os.path.join(s, '__init__.py'), '') except OSError: pass def mkpath_safe(path): mkpath(path) if configuration.backup: mkpath(configuration.backup + path) #REDEFINE # If the student login in LDAP is not the same as the student ID. # This function translate student ID to student login. # The returned value must be usable safely. def the_login(student): return safe(student) def tipped(html, tip, classname="", url=''): """Do not use this function, use 'hidden' javascript utility""" if url == '': html = html.split('<script>') if len(html) == 2: if html[0] == '': html = html[1].replace('</script>','') else: html = js2(html[0]) + '+' + html[1].replace('</script>','') else: html = js2(html[0]) return '<script>hidden(%s,%s,%s);</script>' % (html, js2(tip), js2(classname)) return '<script>hidden(%s,%s,%s);</script>' % ( js2('<a target="_blank" href="%s">%s</a>' % (url, html)), js2(tip), js2(classname)) def newline(): return '<br>' def frame_info(frame, displayed): s = '<tr><td class="name"><small><small>%s</small></small>/<b>%s</b><br><td class="line">%s<td>\n' % ( frame.f_code.co_filename.replace(os.getcwd(), '').strip('/'), frame.f_code.co_name, frame.f_lineno) for k, v in frame.f_locals.items(): if id(v) not in displayed: try: s += "<p><b>" + cgi.escape(k) + "</b>:<br>" + v.backtrace_html() + "\n" except AttributeError: pass except TypeError: pass displayed[id(v)] = True s += '</tr>' return s import socket def send_backtrace(txt, subject='Backtrace', exception=True): s = configuration.version if exception and sys.exc_info()[0] != None \ and sys.exc_info()[0] == socket.error: s += '*' else: s += ' ' s += ' '.join(sys.argv) + ' ' + subject subject = s displayed = {} s = '' if txt: s += ('<h1>Information reported by the exception catcher</h1><pre>' + cgi.escape(txt) + '</pre>\n') if exception and sys.exc_info()[0] != None: s += '<h1>Exception stack</h1>\n' s += '<p>Exception class: ' + cgi.escape(str(sys.exc_info()[0])) + '\n' s += '<p>Exception value: ' + cgi.escape(str(sys.exc_info()[1])) + '\n' f = sys.exc_info()[2] s += '<p>Exception Stack:<table>\n' x = '' while f: ss = frame_info(f.tb_frame, displayed) x = ss + x f = f.tb_next s += x + '</table>' s += '<h1>Current Stack:</h1>\n<table>\n' try: for i in range(1, 20): ss = frame_info(sys._getframe(i), displayed) s += ss except ValueError: pass s += '</table>' filename = os.path.join("LOGS", "BACKTRACES", time.strftime('%Y-%m-%d' + os.path.sep + "%H:%M:%S") ) mkpath(os.path.join(*filename.split(os.path.sep)[:-1]), create_init=False) s = '<html><style>TABLE TD { border: 1px solid black;} .name { text-align:right } PRE { background: white ; border: 2px solid red ;}</style><body>' + s + '</body></html>' f = open(filename, "a") f.write(subject + '\n' + s) f.close() warn(subject + '\n' + s, what="error") if send_backtrace.last_subject != subject and '*./' not in subject: # Not send twice the same mail subject. # Do not send closed connection traceback. send_mail_in_background(configuration.maintainer, subject, s) send_backtrace.last_subject = subject send_backtrace.last_subject = '' class StaticFile(object): """Emulate a string, but it is a file content""" mimetypes = {'html': 'text/html;charset=utf8', 'css': 'text/css;charset=utf8', 'png': 'image/png', 'ico': 'image/png', 'jpg': 'image/jpeg', 'gif': 'image/gif', 'js': 'application/x-javascript;charset=utf8', 'txt': 'text/plain', 'xml': 'application/rss+xml;charset=utf8', } _url_ = 'http://???/' # The current server (TOMUSS or 'suivi') def __init__(self, name, mimetype=None, content=None): self.name = name if mimetype == None: if '.' in name: n = name.split('.')[-1] if n == 'gz': n = name.split('.')[-2] mimetype = self.mimetypes[n] self.mimetype = mimetype self.content = content if self.content: # Not a file, so NEVER reload it self.time = -1 else: self.time = 0 self.append_text = {} self.replace_text = {} def __str__(self): if self.time != -1 and (self.content == None or self.time != os.path.getmtime(self.name)): self.time = os.path.getmtime(self.name) content = read_file(self.name) for old, new in self.replace_text.values(): content = content.replace(old, new) content += ''.join(str(i) for i in self.append_text.values()) if self.name.endswith('.js') or self.name.endswith('.html'): content = content.replace('_FILES_', configuration.url_files) self.content = content dirname = os.path.join("TMP", configuration.version) mkpath(dirname) filename = os.path.join(dirname, self.name.split(os.path.sep)[-1]) write_file(filename, content) return self.content def clear_cache(self): if self.time != -1: self.content = None def __len__(self): return len(str(self)) def replace(self, key, old, new): """The replacement is done each time the file is reloaded""" self.replace_text[key] = (old, new) self.clear_cache() def append(self, key, content): """The append is done each time the file is reloaded""" self.append_text[key] = content self.clear_cache() caches = [] def register_cache(f, fct, timeout, the_type): f.__doc__ = fct.__doc__ f.fct = fct f.timeout = timeout f.the_type = the_type caches.append(f) def clean_cache0(f): if f.cache[1] and time.time() - f.cache[1] > f.timeout: f.cache = ('', 0) def add_a_cache0(fct, timeout=None): """Add a cache to a function without parameters""" if timeout is None: timeout = 3600 def f(): cache = f.cache if time.time() - cache[1] > f.timeout: cache = (f.fct(), time.time()) f.cache = cache return cache[0] f.cache = ('', 0) register_cache(f, fct, timeout, 'add_a_cache0') f.clean = clean_cache0 return f def clean_cache(f): if getattr(f, 'last_value_on_exception', 0): return # Do not erase in order to reuse if there is an exception for key, value in f.cache.items(): if time.time() - value[1] > f.timeout: del f.cache[key] def add_a_cache(fct, timeout=1, not_cached='neverreturnedvalue', last_value_on_exception=False): """Add a cache to a function with one parameter. If the returned value is 'not_cached' then it is not cached. If the cached function may sometime raise an exception, it may be interesting to set last_value_on_exception=True in order to return the previously cached value and hide the exception. """ def f(x): cache = f.cache.get(x, ('',0)) if time.time() - cache[1] > f.timeout: try: cache = (f.fct(x), time.time()) except: if f.last_value_on_exception and cache[1] != 0: cache = (cache[0], time.time()) send_backtrace(str(f.fct), "Cache update failed", exception=False) else: raise if cache[0] == f.not_cached: return f.not_cached else: f.cache[x] = cache return cache[0] f.cache = {} register_cache(f, fct, timeout, 'add_a_cache') f.clean = clean_cache f.not_cached = not_cached f.last_value_on_exception = last_value_on_exception return f def add_a_method_cache(fct, timeout=None, not_cached='neverreturnedvalue'): """Add a cache to a method with one parameter. If the returned value is 'not_cached' then it is not cached. The CACHE IS COMMON TO EVERY INSTANCE of the class""" if timeout == None: timeout = 3600 def f(self, x): cache = f.cache.get(x, ('',0)) if time.time() - cache[1] > f.timeout: cache = (f.fct(self, x), time.time()) if cache[0] == f.not_cached: return f.not_cached else: f.cache[x] = cache return cache[0] f.cache = {} register_cache(f, fct, timeout, 'add_a_method_cache') f.clean = clean_cache f.not_cached = not_cached return f def unload_module(m): if m not in sys.modules: return # print "unload", m del(sys.modules[m]) # print "UNLOAD", '.'.join(m.split('.')[:-1]), '====', m.split('.')[-1] try: del(sys.modules['.'.join(m.split('.')[:-1])].__dict__[m.split('.')[-1]]) except KeyError: pass def import_reload(filename): mtime = os.path.getmtime(filename) name = filename.split(os.path.sep) name[-1] = name[-1].replace('.py','') name.insert(0, 'TOMUSS') module_name = '.'.join(name) __import__(module_name) # force the .pyc creation old_module = sys.modules[module_name] mtime_pyc = os.path.getmtime(filename + 'c') to_reload = mtime > mtime_pyc if to_reload: unload_module(module_name) __import__(module_name) module = sys.modules[module_name] # replace the old by the new one for o in gc.get_referrers(old_module): if isinstance(o, dict): for k, v in o.items(): if v is old_module: o[k] = module break else: module = old_module return module, to_reload def nice_date(x): year = x[0:4] month = x[4:6] day = x[6:8] hours = x[8:10] minutes = x[10:12] seconds = x[12:14] return hours + 'h' + minutes + '.' + seconds + ' le ' + \ day + '/' + month + '/' + year def wait_scripts(): # Returns 'true' if the script are loaded and so processing must continue. # If it returns 'false' then the calling function must stop processing. # It will be recalled with a 'setTimeOut' # The parameter is a string evaluated if the loading is not fine, # It must be a function recalling 'wait_scripts' # By the way : # * this function can not be stored in a script. # * It must not be in a loop return """ function wait_scripts(recall) { if ( navigator.userAgent.indexOf('Konqueror') == -1 ) { var d = document.getElementsByTagName('SCRIPT'), e ; for(var i=0; i<d.length; i++) { e = d[i] ; if ( e.src === undefined ) continue ; if ( e.src === '' ) continue ; if ( e.onloadDone ) continue ; /* if ( e.readyState === "loaded" ) continue ; */ if ( e.readyState === "complete" ) continue ; setTimeout(recall, 1000) ; return ; } } return true ; } """ #REDEFINE # This function returns True if the user uses a stupid password. # Potential stupid passwords are in the 'passwords' list. # Each of the passwords should be tried to login, # if the login is a success, the password is bad. def stupid_password(login, passwords): return False def module_to_login(module): return module.replace('__','.').replace('_','-') def login_to_module(login): return login.replace('.','__').replace('-','_') class AtomicWrite(object): """Act as 'open' function but rename file once it is closed.""" def __init__(self, filename, reduce_ok=True, display_diff=False): self.real_filename = filename self.filename = filename + '.new' self.file = open(self.filename, 'w') self.reduce_ok = reduce_ok self.display_diff = display_diff def write(self, v): self.file.write(v) def close(self): self.file.close() if not self.reduce_ok \ and os.path.exists(self.real_filename) \ and os.path.getsize(self.filename) \ < 0.5 * os.path.getsize(self.real_filename): send_mail(configuration.maintainer, 'BUG TOMUSS : AtomicWrite Reduce' + self.real_filename, self.real_filename) return if self.display_diff: os.system("diff -u '%s' '%s'" % ( self.real_filename.replace("'","'\"'\"'"), self.filename.replace("'","'\"'\"'"))) os.rename(self.filename, self.real_filename) def python_files(dirname): a = os.listdir(dirname) for ue in a: if not ue.endswith('.py'): continue if ue.startswith('__'): continue yield ue def count(t): """Generator : given an iterable it returns tuples : (nr_identical_items, item_value) """ t = t.__iter__() last = t.next() i = 1 try: while True: a = t.next() if a == last: i += 1 else: yield (i, last) i = 1 last = a except StopIteration: yield (i, last) def get_tuples(an_iterable, size): """ >>> for i in get_tuple([1,2,3,4,5,6,7], 3): print i (1, 2, 3) (4, 5, 6) """ return zip( * ( [iter(an_iterable)]*size ) ) def manage_key_real(dirname, key, separation=3, content=None, reduce_ok=True, append=False, delete=False): """ Do not use this function """ if content is None and not os.path.isdir(dirname): return False try: mkpath(dirname) except OSError: pass f1 = os.path.join(dirname, key[:separation]) if content is None and not os.path.isdir(f1): return False try: os.mkdir(f1, 0750) except OSError: pass if os.path.sep in key: key_dir = key.split(os.path.sep)[0] if content is None and not os.path.isdir(os.path.join(f1, key_dir)): return False try: os.mkdir(os.path.join(f1, key_dir), 0750) except OSError: pass f1 = os.path.join(f1, key) if os.path.exists(f1): if delete: os.unlink(f1) return f = open(f1, 'r') c = f.read() f.close() else: c = False if content is not None: if configuration.read_only: send_backtrace("Manage key with content in 'suivi' server", exception=False) return if c is False: c = '' if append: content = c + content else: if not reduce_ok and len(content) < len(c)*0.5: warn("Size not reduced for " + f1) return c if content != c: # Write if modified (non-existant files are empty) f = open(f1, 'w') f.write(content) f.close() return c @add_a_lock def manage_key(dirname, key, separation=3, content=None, reduce_ok=True, append=False, delete=False): """ Store the content in the key and return the old content or False The write is not *process* safe. """ key = key.replace('/.', '/_') if key is '': return False c = manage_key_real(os.path.join(configuration.db, dirname), key, separation, content, reduce_ok, append, delete) if configuration.backup: d = manage_key_real(os.path.join(configuration.backup + configuration.db, dirname), key, separation, content, reduce_ok, append) if c != d: send_backtrace('normal=%s\nbackup=%s\n' % (repr(c), repr(d)), 'manage key backup' + key, exception=False) return c def key_mtime(dirname, key, separation=3): """Return the modification time of the key""" try: return os.path.getmtime(os.path.join(configuration.db, dirname, key[:separation], key)) except OSError: return 0 def charte(login, year=None, semester=None): if year == None: year, semester = configuration.year_semester return os.path.join(login, 'charte_%s_%s' % (str(year), semester)) def charte_signed(login, server=None, year=None, semester=None): from . import signature if server: year = server.year semester = server.semester # For the old files if manage_key('LOGINS', charte(login, str(year), semester)): return True year = int(year) qs = signature.get_state(login) for q in qs.get_by_content('suivi_student_charte'): if year_semester_from_date(q.date) == (year, semester): return q.answer # Not found : add the question only for the current semester if year_semester_from_date(time.strftime("%Y%m")) == (year, semester): server.the_file.write('<img src="%s/=%s/signature/-1/x">' % (configuration.server_url, server.ticket.ticket) ) time.sleep(1) def lock_state(): import imp s = 'Global Python import locked: %s\n' % imp.lock_held() for f in lock_list: if f.the_lock.locked(): s += 'Locked ' else: s += 'Unlocked ' s += '%s [%s]\n' % (f.fct.func_name, f.fct.__module__) return s def on_kill(dummy_x, dummy_y): sys.stderr.write('=' * 79 + '\n' + 'KILLED\n' + '=' * 79 + '\n' + 'LOCKS\n' + '-' * 79 + '\n' + lock_state() + '=' * 79 + '\n' 'THREADS\n' + '-' * 79 + '\n' + '\n'.join(t.stack() for t in thread_list) + '=' * 79 + '\n' ) traceback.print_stack() sys.exit(0) def print_lock_state_clean_cache(): while True: f = open(os.path.join('LOGS', 'xxx.locks.%d' % os.getpid()), 'w') f.write(lock_state()) f.close() for cache in caches: cache.clean(cache) time.sleep(60) class Useles(object): closed = False def close(self): self.closed = True def flush(self): pass def write(self, dummy_txt): raise ValueError('write on Useles') # For socket replacement def sendall(self, dummy=None): pass def shutdown(self,dummy=None): pass Useles = Useles() class Variables(object): """Map variables to a TOMUSS configuration table stored in 0/Variables/group The default group is the name of the module using Variables. Usage Example : V = Variables({'foo': ('foo comment', 'default_value'), 'bar': ('bar comment', 5), }) print V.foo Beware : * The V.foo access time is long. * The V.foo value will change if the user modify the table 0/Variables/group * The user may only enter values of the same type. With the example, only integer values are allowed * The table is filled only when it is used (V.foo will do it) """ _initialized = False def __init__(self, variables, group=None): self.__dict__['_variables'] = variables if group is None: group = sys._getframe(1).f_code.co_filename group = group.split(os.path.sep)[-1].replace('.py', '') self.__dict__['_group'] = group # Can't create the table here: catch 22 def __iter__(self): return self._variables.keys() def items(self): for k in self._variables: yield k, getattr(self, k) def __getattr__(self, name): from . import document # '_' to remove ambiguity between 'Variables' template # and the table template. t = document.table(0, "Variables", '_' + self._group) if t and t.modifiable and not self._initialized: ro = t.pages[0] rw = t.pages[1] t.lock() try: for k, v in self._variables.items(): new_line = k not in t.lines t.cell_change(ro, '0', k, v[0]) t.cell_change(ro, '1', k, v[1].__class__.__name__) if new_line: t.cell_change(rw, '2', k, repr(v[1])) finally: t.unlock() self.__dict__["_initialized"] = True if t is None or name not in t.lines: try: return self._variables[name][1] except KeyError: raise AttributeError(name) return ast.literal_eval(t.lines[name][2].value) def __setattr__(self, name, value): raise AttributeError("Edit the Variable table to change parameters") @add_a_lock def _(msgid, language=None): "Translate the message (local then global dictionary)" if language is None: language = (configuration.language, 'en', 'fr') else: language = tuple(language) + (configuration.language, 'en', 'fr') if _.language != language: _.language = language try: _.loc_tr = gettext.translation('tomuss', os.path.join('LOCAL', 'LOCAL_TRANSLATIONS'), language) except IOError: _.loc_tr = None _.glo_tr = gettext.translation('tomuss', 'TRANSLATIONS', language) if _.loc_tr: tr = _.loc_tr.gettext(msgid) if tr != msgid: return tr return _.glo_tr.gettext(msgid) _.language = None def __(txt): return unicode(_(txt), 'utf-8') import BaseHTTPServer class FakeRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): """ """ please_do_not_close = False # 0.3 is too short for tablets timeout = 0.5 # For Opera that does not send GET on HTTP request it_is_a_post = False do_profile = False def do_POST(self): self.it_is_a_post = True self.do_GET() def get_posted_data(self): if not self.it_is_a_post: return None ctype, pdict = cgi.parse_header(self.headers.getheader('content-type')) if ctype != 'multipart/form-data': warn("ctype=%s" % ctype) return None return cgi.parse_multipart(self.the_rfile, pdict) def send_response(self, i, comment=None): if comment: # To answer HEAD request no handled BaseHTTPServer.BaseHTTPRequestHandler.send_response(self,i,comment) return BaseHTTPServer.BaseHTTPRequestHandler.send_response(self, i) # Needed for HTTP/1.1 requests self.send_header('Connection', 'close') self.wfile.flush() def backtrace_html(self): s = repr(self) + '\nRequest started %f seconds before\n' % ( time.time() - self.start_time, ) if hasattr(self, 'start_time_old'): s+= 'Authentication started %f seconds before\n' % ( time.time() - self.start_time, ) s += '<h2>SERVER HEADERS</h2>\n' for k,v in self.headers.items(): if k != 'authorization': s += '<b>' + k + '</b>:' + cgi.escape(str(v)) + '<br>\n' s += '<h2>SERVER DICT</h2>\n' for k,v in self.__dict__.items(): if k != 'headers': s += '<b>' + k + '</b>:' + cgi.escape(str(v)) + '<br>\n' return s def address_string(self): """Override to avoid DNS lookups""" return "%s:%d" % self.client_address def log_time(self, action, **keys): try: self.__class__.log_time.im_func(self, action, **keys) except TypeError: self.__class__.log_time.__func__(self, action, **keys) def do_not_close_connection(self): self.wfile = Useles self.the_rfile = self.rfile self.rfile = Useles self.please_do_not_close = True try: # self.request is self.connection # self.rfile is self.wfile self.the_sock = self.request._sock self.connection._sock = Useles self.request._sock = Useles self.the_fp = self.headers.__dict__['fp'] self.headers.__dict__['fp'] = Useles except AttributeError: # Before Python 2.7 pass def restore_connection(self): self.wfile = self.the_file self.rfile = self.the_rfile self.please_do_not_close = False try: self.request._sock = self.the_sock self.headers.__dict__['fp'] = self.the_fp except ValueError: # Before Python 2.7 pass def close_connection_now(self): self.the_file.close() try: self.the_rfile.close() self.the_fp.close() self.the_sock.close() except AttributeError: pass def unsafe(self): if 'unsafe=1' in self.path: return True else: return False def _(self, msgid): return _(msgid, self.ticket.language.split(',')) def __(self, msgid): return unicode(self._(msgid), "utf-8") def start_threads(): start_new_thread_immortal(print_lock_state_clean_cache, ()) def start_job(fct, seconds): """In a new thread 'fct' will be called in 'seconds'. If the same 'fct' is started multiple times, only the first one is taken into account. """ if getattr(fct, 'job_in_file', False): return def wait(): time.sleep(seconds) try: fct() finally: fct.job_in_file = False if fct.__doc__: wait.__doc__ = ('Wait %d before running:\n\n' % seconds) + fct.__doc__ fct.job_in_file = True start_new_thread(wait, ()) def display_stack_on_kill(): import signal signal.signal(signal.SIGTERM, on_kill) def init(launch_threads=True): if launch_threads: start_threads() display_stack_on_kill() configuration.ampms_full = [ unicode(ampm, 'utf-8') for ampm in eval(_("MSG_ampms_full"))] s = "" for k in ("yes", "no", "abi", "abj", "pre", "tnr", "ppn"): configuration.__dict__[k] = _(k) s += "var %s = %s, " % (k, js(_(k))) k_short = k + '_short' if _(k_short) != k_short: s += "%s = %s, " % (k_short, js(_(k_short))) configuration.__dict__[k_short] = _(k_short) k += "_char" configuration.__dict__[k] = _(k) s += "%s = %s;\n" % (k, js(_(k))) s += "var COL_TITLE_0_2 = %s;\n" % js(_("COL_TITLE_0_2")) from . import files # Here to avoid circular import files.files['types.js'].append("utilities.py", s) files.files['auth_close.html'] = StaticFile( 'auth_close.html', content=_("MSG_authentication_close") + '<script>window.close();</script>') files.files['allow_error.html'] = StaticFile( 'allow_error.html', content=_("TIP_violet_square")) files.files['ip_error.html'] = StaticFile( 'ip_error.html', content=_("ip_error.html")) files.add('PLUGINS', 'suivi_student_charte.html') if __name__ == "__main__": def square(g): print 'square', g return g*g square = add_a_cache(square) print square(6) print square(7) print square(8) print square(7) print square(6) def square(g): print 'square', g return g*g square = add_a_cache(square, not_cached=64) print square(7) print square(7) print square(8) print square(8) class X: @add_a_method_cache def square(self, g): print 'square', g return g*g xx = X() xx.square(10) xx.square(10) xx.square(20) def xxx(g): if g <= 1: return 1 return g * xxx(g-1) print xxx(1) print xxx(2) xxx = add_a_lock(xxx) print xxx(1) print xxx(2)
💾 保存
取消
保存为 UTF-8,换行统一为 LF