| 722 | |
| 723 | |
| 724 | class AnalyzedCode: |
| 725 | __slots__ = ( |
| 726 | "track_closure_variables", |
| 727 | "track_bound_values", |
| 728 | "bindparam_trackers", |
| 729 | "closure_trackers", |
| 730 | "build_py_wrappers", |
| 731 | ) |
| 732 | _fns: weakref.WeakKeyDictionary[CodeType, AnalyzedCode] = ( |
| 733 | weakref.WeakKeyDictionary() |
| 734 | ) |
| 735 | |
| 736 | _generation_mutex = threading.RLock() |
| 737 | |
| 738 | @classmethod |
| 739 | def get(cls, fn, lambda_element, lambda_kw, **kw): |
| 740 | try: |
| 741 | # TODO: validate kw haven't changed? |
| 742 | return cls._fns[fn.__code__] |
| 743 | except KeyError: |
| 744 | pass |
| 745 | |
| 746 | with cls._generation_mutex: |
| 747 | # check for other thread already created object |
| 748 | if fn.__code__ in cls._fns: |
| 749 | return cls._fns[fn.__code__] |
| 750 | |
| 751 | analyzed: AnalyzedCode |
| 752 | cls._fns[fn.__code__] = analyzed = AnalyzedCode( |
| 753 | fn, lambda_element, lambda_kw, **kw |
| 754 | ) |
| 755 | return analyzed |
| 756 | |
| 757 | def __init__(self, fn, lambda_element, opts): |
| 758 | if inspect.ismethod(fn): |
| 759 | raise exc.ArgumentError( |
| 760 | "Method %s may not be passed as a SQL expression" % fn |
| 761 | ) |
| 762 | closure = fn.__closure__ |
| 763 | |
| 764 | self.track_bound_values = ( |
| 765 | opts.track_bound_values and opts.global_track_bound_values |
| 766 | ) |
| 767 | enable_tracking = opts.enable_tracking |
| 768 | track_on = opts.track_on |
| 769 | track_closure_variables = opts.track_closure_variables |
| 770 | |
| 771 | self.track_closure_variables = track_closure_variables and not track_on |
| 772 | |
| 773 | # a list of callables generated from _bound_parameter_getter_* |
| 774 | # functions. Each of these uses a PyWrapper object to retrieve |
| 775 | # a parameter value |
| 776 | self.bindparam_trackers = [] |
| 777 | |
| 778 | # a list of callables generated from _cache_key_getter_* functions |
| 779 | # these callables work to generate a cache key for the lambda |
| 780 | # based on what's inside its closure variables. |
| 781 | self.closure_trackers = [] |