diff --git a/tests/test_parser.py b/tests/test_parser.py index 7c4fd7f..cb51a71 100644 --- a/tests/test_parser.py +++ b/tests/test_parser.py @@ -3,6 +3,7 @@ import threading import pytest + from thriftpy2.thrift import TType from thriftpy2.parser import load, load_fp from thriftpy2.parser.exc import ThriftParserError, ThriftGrammarError @@ -43,7 +44,23 @@ def test_cpp_include(): load('parser-cases/cpp_include.thrift') -def test_load_in_sub_thread(reraise): +@pytest.fixture +def reset_parser_threadlocal(): + def delattr_no_error(o, name): + try: + delattr(o, name) + except AttributeError: + pass + + from thriftpy2.parser.parser import threadlocal + delattr_no_error(threadlocal, 'thrift_stack') + delattr_no_error(threadlocal, 'include_dirs_') + delattr_no_error(threadlocal, 'thrift_cache') + delattr_no_error(threadlocal, 'incomplete_type') + delattr_no_error(threadlocal, 'initialized') + + +def test_load_in_sub_thread(reraise, reset_parser_threadlocal): @reraise.wrap def f(): load('addressbook.thrift') @@ -53,6 +70,17 @@ def f(): t.join() +def test_load_fp_in_sub_thread(reraise, reset_parser_threadlocal): + @reraise.wrap + def f(): + with open('container.thrift') as fp: + load_fp(fp, 'container_thrift') + + t = threading.Thread(target=f) + t.start() + t.join() + + def test_tutorial(): thrift = load('parser-cases/tutorial.thrift', include_dirs=[ './parser-cases']) diff --git a/thriftpy2/parser/parser.py b/thriftpy2/parser/parser.py index bf6c525..9ad2ebd 100644 --- a/thriftpy2/parser/parser.py +++ b/thriftpy2/parser/parser.py @@ -621,6 +621,15 @@ def parse_fp(source, module_name, lexer=None, parser=None, enable_cache=True): :param enable_cache: if this is set to be `True`, parsed module will be cached by `module_name`, this is enabled by default. """ + # threadlocal should be initialized in every threads + initialized = getattr(threadlocal, 'initialized', None) + if initialized is None: + threadlocal.thrift_stack = [] + threadlocal.include_dirs_ = ['.'] + threadlocal.thrift_cache = {} + threadlocal.incomplete_type = CurrentIncompleteType() + threadlocal.initialized = True + if not module_name.endswith('_thrift'): raise ThriftParserError('thriftpy2 can only generate module with ' '\'_thrift\' suffix')