UnboundLocalError when called a template within block helper
Affects | Status | Importance | Assigned to | Milestone | |
---|---|---|---|---|---|
pybars |
New
|
Undecided
|
Unassigned |
Bug Description
The error is intermittent, a few occurences up to now.
It seems to be an error in parser-generated code, so I'm submitting it.
Relevant part of stacktrace:
```
File "mails/hbs.py", line 391, in render
html = unicode(
File "/pymeta_
result.
File "/pymeta_
value = value(this, options, )
File "mails/hbs.py", line 102, in subject
subject_html = options['fn'](this)
File "/pymeta_
if callable(value):
UnboundLocalError: local variable 'value' referenced before assignment
```
the error occured in 'subject' block helper which is defined like below:
```
def subject(self, this, options):
return ""
```
the relevant template fragment is as following:
{{#subject}} {{trans "[AppName] Activity in the project:" }} {{ project.
I've found the root cause. Is there anyone who could checkin the fix?
The bug is caused by Compiler thread unsafety.
pybars. _compiler. Compiler docstring says "The compiler is not threadsafe: you need one per thread".
It is not true - even one instance per thread is not threadsafe, because class-level fields are initialized in module load time
so creating separate instances won't do anyway:
class Compiler: ar(handlebars_ grammar, {}, 'handlebars') ar(compile_ grammar, {'builder': _builder})
"""A handlebars template compiler.
The compiler is not threadsafe: you need one per thread because of the
state in CodeBuilder.
"""
_handlebars = OMeta.makeGramm
_builder = CodeBuilder()
_compiler = OMeta.makeGramm
# ...
Here is the fixed version of the above code fragment which works fine in multithreading code:
class Compiler:
"""The really thread-safe handlebars template compiler."""
_local = threading.local()
@property self._local, 'handlebars', None) is None:
self. _local. handlebars = OMeta.makeGramm ar(handlebars_ grammar, {}, 'handlebars') handlebars
def _handlebars(self):
if getattr(
return self._local.
@property self._local, 'builder', None) is None:
self. _local. builder = CodeBuilder()
def _builder(self):
if getattr(
return self._local.builder
@property self._local, 'compiler', None) is None:
self. _local. compiler = OMeta.makeGramm ar(compile_ grammar, {'builder': self._builder}) compiler
def _compiler(self):
if getattr(
return self._local.
# ...