better portalocker

This commit is contained in:
mdipierro
2012-08-27 10:06:09 -05:00
parent 86df475ae2
commit 9c4375258b
3 changed files with 72 additions and 116 deletions
+1 -1
View File
@@ -1 +1 @@
Version 2.00.0 (2012-08-27 07:41:29) dev Version 2.00.0 (2012-08-27 10:06:06) dev
+58 -114
View File
@@ -31,10 +31,19 @@ __all__ = ['translator', 'findT', 'update_all_languages']
ospath = os.path ospath = os.path
ostat = os.stat ostat = os.stat
osep = os.sep osep = os.sep
isdir = os.path.isdir
is_gae = settings.global_settings.web2py_runtime_gae is_gae = settings.global_settings.web2py_runtime_gae
DEFAULT_ACCEPT_LANGUAGE = 'en' DEFAULT_ACCEPT_LANGUAGE = 'en'
# DEFAULT PLURAL-FORMS RULES:
# language doesn't use plural forms
DEFAULT_NPLURALS = 1
# only one singular/plural form is used
DEFAULT_GET_PLURAL_ID = lambda n: 0
# word is unchangeable
DEFAULT_CONSTRUCTOR_PLURAL_FORM = lambda word, plural_id: word
def safe_eval(text): def safe_eval(text):
if text.strip(): if text.strip():
try: try:
@@ -79,11 +88,6 @@ upper_fun = lambda s: unicode(s,'utf-8').upper().encode('utf-8')
title_fun = lambda s: unicode(s,'utf-8').title().encode('utf-8') title_fun = lambda s: unicode(s,'utf-8').title().encode('utf-8')
cap_fun = lambda s: unicode(s,'utf-8').capitalize().encode('utf-8') cap_fun = lambda s: unicode(s,'utf-8').capitalize().encode('utf-8')
# DEFAULT PLURAL-FORMS RULES:
default_nplurals = 1 # language doesn't use plural forms
default_get_plural_id = lambda n: 0 # only one singular/plural form is used
default_construct_plural_form = lambda word, plural_id: word # word is unchangeable
ttab_in = maketrans("\\%{}", '\x1c\x1d\x1e\x1f') ttab_in = maketrans("\\%{}", '\x1c\x1d\x1e\x1f')
ttab_out = maketrans('\x1c\x1d\x1e\x1f', "\\%{}") ttab_out = maketrans('\x1c\x1d\x1e\x1f', "\\%{}")
@@ -161,7 +165,7 @@ def read_dict_aux(filename):
# clear cache of processed messages: # clear cache of processed messages:
clear_cache(tcache.setdefault(filename, ({}, allocate_lock()))) clear_cache(tcache.setdefault(filename, ({}, allocate_lock())))
try: try:
return save_eval(lang_text) or {} return safe_eval(lang_text) or {}
except Exception, e: except Exception, e:
status = 'Syntax error in %s (%s)' % (filename, e) status = 'Syntax error in %s (%s)' % (filename, e)
logging.error(status) logging.error(status)
@@ -224,113 +228,61 @@ def read_possible_languages(appdir):
langs['default'] = ('en', 'English', 0) langs['default'] = ('en', 'English', 0)
return langs return langs
def read_plural_rules_aux(filename): def read_global_plural_rules(filename):
"""retrieve plural rules from rules/*plural_rules-lang*.py file. """
retrieve plural rules from rules/*plural_rules-lang*.py file.
args: args:
filename (str): plural_rules filename filename (str): plural_rules filename
returns: returns:
tuple(nplurals, get_plural_id, construct_plural_form) (nplurals, get_plural_id, construct_plural_form, status)
e.g.: (3, <function>, <function>) e.g.: (3, <function>, <function>, ok)
""" """
f = portalocker.LockedFile(filename, 'r') env = {}
plural_py=f.read().replace('\r\n','\n') lock = portalocker.LockedFile(filename, 'r')
f.close()
try: try:
exec(plural_py) execfile(filename) in env
nplurals=locals().get('nplurals', default_nplurals)
get_plural_id=locals().get('get_plural_id', default_get_plural_id)
construct_plural_form=locals().get('construct_plural_form',
default_construct_plural_form)
status='ok' status='ok'
except Exception, e: except Exception, e:
nplurals=default_nplurals
get_plural_id=default_get_plural_id
construct_plural_form=default_construct_plural_form
status='Syntax error in %s (%s)' % (filename, e) status='Syntax error in %s (%s)' % (filename, e)
logging.error(status) logging.error(status)
lock.close()
nplurals = env.get('nplurals', DEFAULT_NPLURALS)
get_plural_id = env.get('get_plural_id', DEFAULT_GET_PLURAL_ID)
construct_plural_form = env.get('construct_plural_form',
DEFAULT_CONSTRUCTOR_PLURAL_FORM)
return (nplurals, get_plural_id, construct_plural_form, status) return (nplurals, get_plural_id, construct_plural_form, status)
def read_plural_rules(lang):
filename = abspath('gluon','contrib','rules', 'plural_rules-%s.py' % lang)
return getcfs('plural_rules-'+lang, filename,
lambda: read_plural_rules_aux(filename))
pcache={}
def read_possible_plurals(): def read_possible_plurals():
""" create list of all possible plural rules files """ create list of all possible plural rules files
result is cached to increase speed result is cached to increase speed
""" """
global pcache
pdir = abspath('gluon','contrib','rules') pdir = abspath('gluon','contrib','rules')
plurals = {} plurals = {}
# scan rules directory for plural_rules-*.py files: # scan rules directory for plural_rules-*.py files:
for pname in [f for f in listdir(pdir, regex_plural_rules) for pname in os.listdir(pdir):
if osep not in f]: if not isdir(pname) and regex_plural_rules.match(pname):
lang = pname[13:-3]
lang=pname[13:-3] fname = ospath.join(pdir, pname)
fname=ospath.join(pdir, pname) n, f1, f2, status = read_global_plural_rules(fname)
mtime=ostat(fname).st_mtime if status == 'ok':
if lang in pcache and pcache[lang][2] == mtime: plurals[lang] = (lang, n, f1, f2)
# if plural_file's mtime wasn't changed - use previous value: plurals['default'] = ('default',
plurals[lang]=pcache[lang] DEFAULT_NPLURALS,
else: DEFAULT_GET_PLURAL_ID,
# otherwise, reread plural_rules-file: DEFAULT_CONSTRUCTOR_PLURAL_FORM)
if 'plural_rules-'+lang in cfs: return plurals
n,f1,f2,status=read_plural_rules(lang)
else:
n,f1,f2,status=read_plural_rules_aux(fname)
plurals[lang]=(n, pname, mtime, status)
pcache=plurals
return pcache
def get_plural_rules(languages):
"""get plural-forms rules for language *lang*
if rules not found - default rules will be return and lang=='unknown'
args:
lang (str): the languages, for one of which the plural-forms is return
returns:
tuples(lang, plural_rules-filename, nplurals,
get_plural_id(), construct_plural_form(), status)
"""
if isinstance(languages, str):
languages = [languages]
all_plurals=read_possible_plurals()
for lang in languages:
match_language = regex_language.match(lang.strip().lower())
if match_language:
match_language = tuple(part
for part in match_language.groups()
if part)
lang = lang_sampling(match_language, all_plurals.keys())
if lang:
( nplurals,
get_plural_id,
construct_plural_form,
status
) = read_plural_rules(lang)
return (lang, all_plurals[lang][1], nplurals,
get_plural_id,
construct_plural_form,
status)
return ('unknown', None, default_nplurals,
default_get_plural_id,
default_construct_plural_form,
'ok')
PLURAL_RULES = read_possible_plurals()
def read_plural_dict_aux(filename): def read_plural_dict_aux(filename):
fp = portalocker.LockedFile(filename, 'r') fp = portalocker.LockedFile(filename, 'r')
lang_text = fp.read().replace('\r\n', '\n') lang_text = fp.read().replace('\r\n', '\n')
fp.close() fp.close()
if not lang_text.strip():
return {}
try: try:
return eval(lang_text) return safe_eval(lang_text) or {}
except Exception, e: except Exception, e:
status='Syntax error in %s (%s)' % (filename, e) status='Syntax error in %s (%s)' % (filename, e)
logging.error(status) logging.error(status)
@@ -340,7 +292,6 @@ def read_plural_dict(filename):
return getcfs('plurals:'+filename, filename, return getcfs('plurals:'+filename, filename,
lambda: read_plural_dict_aux(filename)) lambda: read_plural_dict_aux(filename))
def write_plural_dict(filename, contents): def write_plural_dict(filename, contents):
if '__corrupted__' in contents: if '__corrupted__' in contents:
return return
@@ -536,32 +487,27 @@ class translator(object):
self.current_languages = languages self.current_languages = languages
self.force(self.http_accept_language) self.force(self.http_accept_language)
def set_plural(self, languages): def set_plural(self, language):
""" initialize plural forms subsystem """ initialize plural forms subsystem
invoked from self.force() invoked from self.force()
""" """
( self.plural_language, lang = language[:2]
self.plural_rules_file, (self.plural_language,
self.nplurals, self.nplurals,
self.get_plural_id, self.get_plural_id,
self.construct_plural_form, self.construct_plural_form,
self.plural_status ) = PLURAL_RULES.get(language,PLURAL_RULES['default'])
) = get_plural_rules(languages) filename = 'plural-%s.py' % self.plural_language
if filename in self.filenames:
if self.plural_language == 'unknown': self.plural_file = ospath.join(self.langpath,filename)
self.plural_dict = read_plural_dict(self.plural_file)
else:
self.plural_file = None self.plural_file = None
self.plural_dict = {} self.plural_dict = {}
else:
filename = 'plural-%s.py' % self.plural_language
if filename in self.filenames:
self.plural_file = ospath.join(self.langpath,filename)
self.plural_dict = read_plural_dict(self.plural_file)
else:
self.plural_file = None
self.plural_dict = {}
def plural(self, word, n): def plural(self, word, n):
""" get plural form of word for number *n* """
get plural form of word for number *n*
NOTE: *word" MUST be defined in current language NOTE: *word" MUST be defined in current language
(T.accepted_language) (T.accepted_language)
@@ -579,23 +525,21 @@ class translator(object):
if id > 0: if id > 0:
forms = self.plural_dict.get(word, []) forms = self.plural_dict.get(word, [])
if forms: if forms:
try: form = forms.get(id-1)
form = forms[id-1] if form:
except: return form
form = None
if form: return form
form = self.construct_plural_form(word, id) form = self.construct_plural_form(word, id)
if len(forms) < nplurals-1: if len(forms) < nplurals-1:
forms.extend('' for i in xrange(nplurals-len(forms)-1)) forms.extend('' for i in xrange(nplurals-len(forms)-1))
forms[id-1] = form forms[id-1] = form
self.plural_dict[word] = forms self.plural_dict[word] = forms
if (self.plural_file and if (self.plural_file and
not settings.global_settings.web2py_runtime_gae): not settings.global_settings.web2py_runtime_gae):
write_plural_dict(self.plural_file, self.plural_dict) write_plural_dict(self.plural_file,
self.plural_dict)
return form return form
return word return word
def get_possible_languages_info(self, lang=None): def get_possible_languages_info(self, lang=None):
""" """
return info for selected language or dictionary with all return info for selected language or dictionary with all
@@ -664,7 +608,7 @@ class translator(object):
self.language_file = None self.language_file = None
self.t = {} self.t = {}
self.cache = tcache[None] self.cache = tcache[None]
# self.set_plural(language) self.set_plural(language)
return languages return languages
def __call__(self, message, symbols={}, language=None, lazy=None): def __call__(self, message, symbols={}, language=None, lazy=None):
+13 -1
View File
@@ -1,6 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# portalocker.py - Cross-platform (posix/nt) API for flock-style file locking. # portalocker.py
# Cross-platform (posix/nt) API for flock-style file locking.
# Requires python 1.5.2 or better. # Requires python 1.5.2 or better.
""" """
@@ -141,6 +142,17 @@ class LockedFile(object):
def __del__(self): def __del__(self):
self.close() self.close()
def read_locked(filename):
fp = portalocker.LockedFile(file, 'r')
data = fp.read()
fp.close()
return data
def write_locked(filename,data):
fp = portalocker.LockedFile(file, 'w')
data = fp.write(data)
fp.close()
if __name__=='__main__': if __name__=='__main__':
f = LockedFile('test.txt',mode='wb') f = LockedFile('test.txt',mode='wb')
f.write('test ok') f.write('test ok')