| import random | |
| import unittest | |
| from unittest import TestCase | |
| from test.support import threading_helper | |
| threading_helper.requires_working_threading(module=True) | |
| NUM_THREADS = 8 | |
| ITERS = 200 | |
| def random_string(): | |
| return ''.join(random.choice('0123456789ABCDEF') for _ in range(10)) | |
| def template_a(): pass | |
| def template_b(): pass | |
| class TestFTFunctionAttributes(TestCase): | |
| def stress_attribute(self, attr, make_value): | |
| def target(x=1): | |
| return x | |
| def writer(): | |
| for _ in range(ITERS): | |
| setattr(target, attr, make_value()) | |
| getattr(target, attr) | |
| threading_helper.run_concurrently(writer, NUM_THREADS) | |
| def test_name(self): | |
| self.stress_attribute("__name__", random_string) | |
| def test_qualname(self): | |
| self.stress_attribute("__qualname__", random_string) | |
| def test_code(self): | |
| codes = (template_a.__code__, template_b.__code__) | |
| self.stress_attribute("__code__", lambda: random.choice(codes)) | |
| def test_defaults(self): | |
| self.stress_attribute("__defaults__", lambda: (random_string(),)) | |
| def test_kwdefaults(self): | |
| self.stress_attribute("__kwdefaults__", lambda: {"x": random_string()}) | |
| def test_annotations(self): | |
| self.stress_attribute("__annotations__", | |
| lambda: {"x": random_string()}) | |
| def test_annotate(self): | |
| self.stress_attribute("__annotate__", | |
| lambda: (lambda format: {"x": str})) | |
| def test_type_params(self): | |
| self.stress_attribute("__type_params__", lambda: (random_string(),)) | |
| def test_doc(self): | |
| self.stress_attribute("__doc__", random_string) | |
| def test_module(self): | |
| self.stress_attribute("__module__", random_string) | |
| def test_annotations_and_annotate(self): | |
| # The __annotations__ and __annotate__ setters clear each other. | |
| def target(): pass | |
| def set_annotations(): | |
| for _ in range(ITERS): | |
| target.__annotations__ = {"x": random_string()} | |
| target.__annotations__ | |
| def set_annotate(): | |
| for _ in range(ITERS): | |
| target.__annotate__ = lambda format: {"x": str} | |
| target.__annotate__ | |
| threading_helper.run_concurrently( | |
| [set_annotations, set_annotate] * (NUM_THREADS // 2)) | |
| def test_call_while_replacing_defaults(self): | |
| # The eval loop reads __defaults__ and __kwdefaults__ without holding | |
| # a lock while pushing a frame. | |
| def target(x="init", *, y="init"): | |
| return x, y | |
| def writer(): | |
| for _ in range(ITERS): | |
| target.__defaults__ = (random_string(),) | |
| target.__kwdefaults__ = {"y": random_string()} | |
| def caller(): | |
| for _ in range(ITERS): | |
| target() | |
| threading_helper.run_concurrently( | |
| [writer, caller] * (NUM_THREADS // 2)) | |
| if __name__ == "__main__": | |
| unittest.main() |