|
11 | 11 | import sys
|
12 | 12 | import types
|
13 | 13 | from pathlib import Path
|
14 |
| -from typing import Any, Iterable, NoReturn, Optional |
| 14 | +from typing import Any, Optional |
15 | 15 |
|
16 | 16 | import click
|
17 | 17 | import uvicorn
|
|
21 | 21 |
|
22 | 22 | from . import _autoreload, _hostenv, _static, _utils
|
23 | 23 | from ._docstring import no_example
|
24 |
| -from ._profiler import check_dependencies as check_profiler_dependencies |
25 |
| -from ._profiler import profiler |
| 24 | +from ._profiler import check_profiler_dependencies, profiler |
26 | 25 | from ._typing_extensions import NotRequired, TypedDict
|
27 | 26 | from .express import is_express_app
|
28 | 27 | from .express._utils import escape_to_var_name
|
@@ -697,144 +696,3 @@ def _verify_rsconnect_version() -> None:
|
697 | 696 | )
|
698 | 697 | except PackageNotFoundError:
|
699 | 698 | pass
|
700 |
| - |
701 |
| - |
702 |
| -def find_pyspy_path() -> str | None: |
703 |
| - import sysconfig |
704 |
| - |
705 |
| - schemes = [ |
706 |
| - sysconfig.get_default_scheme(), |
707 |
| - sysconfig.get_preferred_scheme("prefix"), |
708 |
| - sysconfig.get_preferred_scheme("home"), |
709 |
| - sysconfig.get_preferred_scheme("user"), |
710 |
| - ] |
711 |
| - |
712 |
| - for scheme in schemes: |
713 |
| - path = sysconfig.get_path("scripts", scheme=scheme) |
714 |
| - pyspy_path = os.path.join(path, "py-spy" + (".exe" if os.name == "nt" else "")) |
715 |
| - if os.path.exists(pyspy_path): |
716 |
| - return pyspy_path |
717 |
| - |
718 |
| - return None |
719 |
| - |
720 |
| - |
721 |
| -def get_current_argv() -> Iterable[str]: |
722 |
| - r""" |
723 |
| - ## Windows, `shiny run` |
724 |
| -
|
725 |
| - argv: C:\Users\jcheng\Development\posit-dev\py-shiny\.venv311\Scripts\shiny run app.py |
726 |
| - orig_argv: C:\Users\jcheng\AppData\Local\Programs\Python\Python311\python.exe C:\Users\jcheng\Development\posit-dev\py-shiny\.venv311\Scripts\shiny.exe run app.py |
727 |
| -
|
728 |
| - The argv is usable, the orig_argv is not because the Python path points to the |
729 |
| - physical python.exe instead of the python.exe inside of the venv. |
730 |
| -
|
731 |
| - ## Windows, `python -m shiny run` |
732 |
| -
|
733 |
| - argv: C:\Users\jcheng\Development\posit-dev\py-shiny\.venv311\Lib\site-packages\shiny\__main__.py run app.py |
734 |
| - orig_argv: C:\Users\jcheng\AppData\Local\Programs\Python\Python311\python.exe -m shiny run app.py |
735 |
| -
|
736 |
| - The argv is not usable because argv[0] is not executable. The orig_argv is not |
737 |
| - usable because it's the physical python.exe instead of the python.exe inside |
738 |
| - of the venv. |
739 |
| -
|
740 |
| - ## Mac, `shiny run` |
741 |
| -
|
742 |
| - argv: /Users/jcheng/Development/posit-dev/py-shiny/.venv/bin/shiny run app.py |
743 |
| - orig_argv: /Users/jcheng/Development/posit-dev/py-shiny/.venv/bin/python /Users/jcheng/Development/posit-dev/py-shiny/.venv/bin/shiny run app.py |
744 |
| -
|
745 |
| - Both are usable, nice. |
746 |
| -
|
747 |
| - ## Mac, `python -m shiny run` |
748 |
| -
|
749 |
| - argv: /Users/jcheng/Development/posit-dev/py-shiny/.venv/lib/python3.10/site-packages/shiny/__main__.py run app.py |
750 |
| - orig_argv: python -m shiny run app.py |
751 |
| -
|
752 |
| - The argv is not usable because argv[0] is not executable. The orig_argv is |
753 |
| - usable. |
754 |
| - """ |
755 |
| - |
756 |
| - # print("argv: " + " ".join(sys.argv)) |
757 |
| - # print("orig_argv: " + " ".join(sys.orig_argv)) |
758 |
| - |
759 |
| - args = sys.argv.copy() |
760 |
| - |
761 |
| - if Path(args[0]).suffix == ".py": |
762 |
| - args = [*sys.orig_argv] |
763 |
| - |
764 |
| - if os.name == "nt" and sys.prefix != sys.base_prefix: |
765 |
| - # In a virtualenv. Make sure we use the correct Python, the one from inside |
766 |
| - # the venv. |
767 |
| - args[0] = sys.executable |
768 |
| - |
769 |
| - return args |
770 |
| - |
771 |
| - |
772 |
| -def run_under_pyspy() -> NoReturn: |
773 |
| - import base64 |
774 |
| - import subprocess |
775 |
| - import time |
776 |
| - import webbrowser |
777 |
| - from urllib.parse import quote_plus |
778 |
| - |
779 |
| - pyspy_path = find_pyspy_path() |
780 |
| - if pyspy_path is None: |
781 |
| - print( |
782 |
| - "Error: Profiler is not installed. You can install it with " |
783 |
| - "'pip install shiny[profile]'.", |
784 |
| - file=sys.stderr, |
785 |
| - ) |
786 |
| - sys.exit(1) |
787 |
| - |
788 |
| - print(" ".join(get_current_argv())) |
789 |
| - # Strip out the --profile argument and launch again under py-spy |
790 |
| - new_argv = [x for x in get_current_argv() if x != "--profile"] |
791 |
| - |
792 |
| - # For some reason, on Windows, I see python.exe and shiny.exe as the first two |
793 |
| - # arguments |
794 |
| - # if os.name == "nt" and Path(new_argv[1]).suffix == ".exe": |
795 |
| - # new_argv.pop(0) |
796 |
| - |
797 |
| - # Create a filename based on "profile.json" but with a unique name based on the |
798 |
| - # current date/time |
799 |
| - epoch_time = int(time.time()) |
800 |
| - output_filename = f"profile-{epoch_time}.json" |
801 |
| - output_filename_abs = os.path.join(os.getcwd(), output_filename) |
802 |
| - |
803 |
| - try: |
804 |
| - # TODO: Print out command line that will be run, in case user wants to change it |
805 |
| - subprocess_args = [ |
806 |
| - pyspy_path, |
807 |
| - "record", |
808 |
| - "--format=speedscope", |
809 |
| - f"--output={output_filename}", |
810 |
| - "--idle", |
811 |
| - "--subprocesses", |
812 |
| - "--", |
813 |
| - *new_argv, |
814 |
| - ] |
815 |
| - |
816 |
| - print(" ".join(subprocess_args)) |
817 |
| - |
818 |
| - # Run a new process under py-spy |
819 |
| - proc = subprocess.run( |
820 |
| - subprocess_args, |
821 |
| - check=False, |
822 |
| - shell=False, |
823 |
| - stdin=sys.stdin, |
824 |
| - stdout=sys.stdout, |
825 |
| - stderr=sys.stderr, |
826 |
| - ) |
827 |
| - sys.exit(proc.returncode) |
828 |
| - finally: |
829 |
| - if os.path.exists(output_filename_abs): |
830 |
| - with open(output_filename_abs, "rb") as profile_file: |
831 |
| - b64_str = base64.b64encode(profile_file.read()).decode("utf-8") |
832 |
| - data_uri = f"data:application/json;base64,{b64_str}" |
833 |
| - full_url = ( |
834 |
| - "https://speedscope.app/#profileURL=" |
835 |
| - + quote_plus(data_uri) |
836 |
| - # + "&title=" |
837 |
| - # + quote_plus(output_filename) |
838 |
| - ) |
839 |
| - print(full_url) |
840 |
| - webbrowser.open(full_url) |
0 commit comments