From f51951c8211e54f2ec334123b29b5d266e07bac8 Mon Sep 17 00:00:00 2001 From: le codeur rapide Date: Sun, 8 Jun 2025 12:20:49 +0200 Subject: [PATCH] setup docs + add more robustness --- .github/workflows/mkdocs.yml | 2 +- .gitignore | 1 + lblprof/custom_sysmon.py | 21 ++++++++++------ lblprof/line_stats_tree.py | 2 +- lblprof/tests/demo_example_script.py | 14 +++++------ lblprof/tests/example_scripts/double_zip.py | 8 ++++++ .../example_scripts/generator_function.py | 25 +++++++++++++++++++ pyproject.toml | 2 +- 8 files changed, 57 insertions(+), 18 deletions(-) create mode 100644 lblprof/tests/example_scripts/double_zip.py create mode 100644 lblprof/tests/example_scripts/generator_function.py diff --git a/.github/workflows/mkdocs.yml b/.github/workflows/mkdocs.yml index c900973..258a208 100644 --- a/.github/workflows/mkdocs.yml +++ b/.github/workflows/mkdocs.yml @@ -14,7 +14,7 @@ permissions: jobs: build_mkdocs: runs-on: ubuntu-latest - + steps: - name: Checkout code uses: actions/checkout@v4 diff --git a/.gitignore b/.gitignore index 114007f..d42c86e 100644 --- a/.gitignore +++ b/.gitignore @@ -9,5 +9,6 @@ uv.lock *.csv *.json *.txt +*.ipynb tests_examples/ site/ \ No newline at end of file diff --git a/lblprof/custom_sysmon.py b/lblprof/custom_sysmon.py index 10596f6..243ad4b 100644 --- a/lblprof/custom_sysmon.py +++ b/lblprof/custom_sysmon.py @@ -69,6 +69,8 @@ def _handle_call(self, code, instruction_offset): logging.debug( f"handle call: filename: {file_name}, func_name: {func_name}, line_no: {line_no}" ) + if "" in func_name: + return # We get info on who called the function # Using the tempo line infos instead of frame.f_back allows us to # get information about last parent that is from user code and not @@ -83,6 +85,7 @@ def _handle_call(self, code, instruction_offset): # Update call stack # Until we return from the function, all lines executed will have # the caller line as parent + self.call_stack.append(caller_key) def _handle_line(self, code, line_number): @@ -130,16 +133,18 @@ def _handle_return(self, code, instruction_offset, retval): # In case the stop_tracing is called from a lower frame than start_tracing, # we need to activate monitoring for the returned frame - current_frame = sys._getframe().f_back.f_back + current_frame = sys._getframe().f_back if not sys.monitoring.get_tool(self.tool_id): sys.monitoring.use_tool_id(self.tool_id, "lblprof-monitor") - sys.monitoring.set_local_events( - self.tool_id, - current_frame.f_code, - sys.monitoring.events.LINE - | sys.monitoring.events.PY_RETURN - | sys.monitoring.events.PY_START, - ) + # We check if the returned frame already exists, if yes we activate monitoring for it + if current_frame and current_frame.f_back and current_frame.f_back.f_code: + sys.monitoring.set_local_events( + self.tool_id, + current_frame.f_code, + sys.monitoring.events.LINE + | sys.monitoring.events.PY_RETURN + | sys.monitoring.events.PY_START, + ) # Adding a END_OF_FRAME event to the tree to mark the end of the frame # This is used to compute the duration of the last line of the frame diff --git a/lblprof/line_stats_tree.py b/lblprof/line_stats_tree.py index efe553c..b57c249 100644 --- a/lblprof/line_stats_tree.py +++ b/lblprof/line_stats_tree.py @@ -349,7 +349,7 @@ def _save_events(self) -> None: with open("events.csv", "w") as f: for event in self.raw_events_list: f.write( - f"{event['id']},{event['file_name']},{event['function_name']},{event['line_no']},{event['start_time']}\n" + f"{event['id']},{event['file_name']},{event['function_name']},{event['line_no']},{event['start_time']},{event['stack_trace']}\n" ) def _save_events_index(self) -> None: diff --git a/lblprof/tests/demo_example_script.py b/lblprof/tests/demo_example_script.py index 4361879..9533ed1 100644 --- a/lblprof/tests/demo_example_script.py +++ b/lblprof/tests/demo_example_script.py @@ -5,13 +5,9 @@ import runpy sys.path.append(os.getcwd()) -from lblprof import ( - show_interactive_tree, - start_tracing, - stop_tracing, -) +from lblprof import show_interactive_tree, start_tracing, stop_tracing, tracer -logging.basicConfig(level=logging.INFO) +logging.basicConfig(level=logging.DEBUG) path_example_folder = os.path.join(os.path.dirname(__file__), "example_scripts") @@ -21,6 +17,8 @@ script_name = "import_pandas.py" # script_name = "list_comprehension.py" # script_name = "try_except.py" +script_name = "double_zip.py" +# script_name = "generator_function.py" script_path = os.path.join(path_example_folder, script_name) @@ -56,4 +54,6 @@ def main(): stop_tracing() # print the tree # show_tree() -show_interactive_tree(min_time_s=0.01) +show_interactive_tree(min_time_s=0.0) +tracer.tree._save_events() +tracer.tree._save_events_index() diff --git a/lblprof/tests/example_scripts/double_zip.py b/lblprof/tests/example_scripts/double_zip.py new file mode 100644 index 0000000..5a0dbf3 --- /dev/null +++ b/lblprof/tests/example_scripts/double_zip.py @@ -0,0 +1,8 @@ +def doublezip(): + rows = [(1, 2, None), (3, 4, None), (5, 6, None), (7, 8, None)] + _ = list(zip(*[col for col in zip(*rows) if any(cell is not None for cell in col)])) + _ = any(cell is not None for cell in rows[0]) + + +if __name__ == "__main__": + doublezip() diff --git a/lblprof/tests/example_scripts/generator_function.py b/lblprof/tests/example_scripts/generator_function.py new file mode 100644 index 0000000..ec1b5d8 --- /dev/null +++ b/lblprof/tests/example_scripts/generator_function.py @@ -0,0 +1,25 @@ +# import time +# def generator(): +# for i in range(10): +# time.sleep(0.05) +# yield i + +# if __name__ == "__main__": +# for i in generator(): +# print(i) + +# gene = list(generator()) + +# pure_gene = list(time.sleep(0.1) for i in range(10)) + +# double_gen = list( +# time.sleep(0.1) for i in range(2) for j in range(2) if True +# ) + +# # rows = [(1, 2, None), (3, 4, None), (5, 6, None)] +# # filtered = list( +# # zip(*[ +# # col for col in zip(*rows) +# # if any(cell is not None for cell in col) +# # ]) +# # ) diff --git a/pyproject.toml b/pyproject.toml index c1bac26..f2ab3f0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "lblprof" -version = "0.1.5" +version = "0.1.7" description = "Line by line terminal based profiler" authors = [ { name="le-codeur-rapide", email="paul.vezia@gmail.com" }