|
22 | 22 | Optional, |
23 | 23 | OrderedDict, |
24 | 24 | Set, |
25 | | - Tuple, |
26 | 25 | Union, |
27 | 26 | ) |
28 | 27 | from weakref import WeakSet |
|
40 | 39 | "get_function", |
41 | 40 | "to_thread", |
42 | 41 | "check_recursion", |
| 42 | + "debounce", |
43 | 43 | ] |
44 | 44 |
|
45 | 45 |
|
@@ -893,32 +893,32 @@ def calculate_and_print_stats(self, func_name: str): |
893 | 893 | def line_profiler(func: Callable) -> Callable: |
894 | 894 | """Decorator to profile a function line-by-line. |
895 | 895 |
|
896 | | - Demo usage: |
897 | | - >>> import sys, io |
898 | | - >>> LineProfiler.stdout = io.StringIO() # Redirect stdout to capture print output |
899 | | - >>> @line_profiler |
900 | | - ... def example_function(): |
901 | | - ... result = 0 |
902 | | - ... for i in range(10): |
903 | | - ... result += i # Simulate some work |
904 | | - ... return result |
905 | | - >>> example_function() |
906 | | - 45 |
907 | | - >>> output = LineProfiler.stdout.getvalue() |
908 | | - >>> output.splitlines()[0].startswith("=" * 95) and "`example_function` profiling report:" in output |
909 | | - True |
910 | | - >>> LineProfiler.stdout = sys.stdout # Restore original stdout |
911 | | -
|
912 | | -=============================================================================================== |
913 | | -`example_function` profiling report: |
914 | | -Start at 2025-07-26 17:09:58 | Total: 1.122 ms |
915 | | -=============================================================================================== |
916 | | - Line % Total(ms) Count Avg(ms) Source Code |
917 | | ------------------------------------------------------------------------------------------------ |
918 | | - 3 73 0.825 1 0.825 - |
919 | | - 4 3 0.040 11 0.004 - |
920 | | - 5 4 0.050 10 0.005 - |
921 | | -=============================================================================================== |
| 896 | + Demo usage: |
| 897 | + >>> import sys, io |
| 898 | + >>> LineProfiler.stdout = io.StringIO() # Redirect stdout to capture print output |
| 899 | + >>> @line_profiler |
| 900 | + ... def example_function(): |
| 901 | + ... result = 0 |
| 902 | + ... for i in range(10): |
| 903 | + ... result += i # Simulate some work |
| 904 | + ... return result |
| 905 | + >>> example_function() |
| 906 | + 45 |
| 907 | + >>> output = LineProfiler.stdout.getvalue() |
| 908 | + >>> output.splitlines()[0].startswith("=" * 95) and "`example_function` profiling report:" in output |
| 909 | + True |
| 910 | + >>> LineProfiler.stdout = sys.stdout # Restore original stdout |
| 911 | +
|
| 912 | + =============================================================================================== |
| 913 | + `example_function` profiling report: |
| 914 | + Start at 2025-07-26 17:09:58 | Total: 1.122 ms |
| 915 | + =============================================================================================== |
| 916 | + Line % Total(ms) Count Avg(ms) Source Code |
| 917 | + ----------------------------------------------------------------------------------------------- |
| 918 | + 3 73 0.825 1 0.825 - |
| 919 | + 4 3 0.040 11 0.004 - |
| 920 | + 5 4 0.050 10 0.005 - |
| 921 | + =============================================================================================== |
922 | 922 | """ |
923 | 923 |
|
924 | 924 | @wraps(func) |
@@ -946,6 +946,52 @@ def wrapper(*args, **kwargs): |
946 | 946 | return wrapper |
947 | 947 |
|
948 | 948 |
|
| 949 | +def debounce(wait: float): |
| 950 | + """Debounce a function, delaying its execution until after a specified wait time. |
| 951 | +
|
| 952 | + Args: |
| 953 | + wait (float): The amount of time to wait before executing the function. |
| 954 | +
|
| 955 | + Demo:: |
| 956 | +
|
| 957 | + >>> @debounce(0.1) |
| 958 | + ... def test(): |
| 959 | + ... print("Function executed") |
| 960 | + >>> test() |
| 961 | + Function executed |
| 962 | + >>> test() |
| 963 | + >>> time.sleep(0.1) |
| 964 | + >>> test() |
| 965 | + Function executed |
| 966 | + >>> test() |
| 967 | + """ |
| 968 | + def decorator(fn): |
| 969 | + last_call = 0 |
| 970 | + |
| 971 | + async def async_wrapper(*args, **kwargs): |
| 972 | + nonlocal last_call |
| 973 | + current_time = time.time() |
| 974 | + if current_time - last_call < wait: |
| 975 | + return |
| 976 | + last_call = current_time |
| 977 | + return await fn(*args, **kwargs) |
| 978 | + |
| 979 | + def sync_wrapper(*args, **kwargs): |
| 980 | + nonlocal last_call |
| 981 | + current_time = time.time() |
| 982 | + if current_time - last_call < wait: |
| 983 | + return |
| 984 | + last_call = current_time |
| 985 | + return fn(*args, **kwargs) |
| 986 | + |
| 987 | + if asyncio.iscoroutinefunction(fn): |
| 988 | + return async_wrapper |
| 989 | + else: |
| 990 | + return sync_wrapper |
| 991 | + |
| 992 | + return decorator |
| 993 | + |
| 994 | + |
949 | 995 | def test_bg_task(): |
950 | 996 | async def _test_bg_task(): |
951 | 997 | async def coro(): |
|
0 commit comments