summaryrefslogtreecommitdiff
path: root/lib/debug
diff options
context:
space:
mode:
Diffstat (limited to 'lib/debug')
-rw-r--r--lib/debug/debugger.py10
-rw-r--r--lib/debug/logging.py7
-rw-r--r--lib/debug/utils.py32
3 files changed, 41 insertions, 8 deletions
diff --git a/lib/debug/debugger.py b/lib/debug/debugger.py
index 11293c8a..c58ddb3e 100644
--- a/lib/debug/debugger.py
+++ b/lib/debug/debugger.py
@@ -125,6 +125,10 @@
# to see flask server url routes:
# - comment out the line self.disable_logging() in run() of lib/api/server.py
+# We have some ignores so you don't see errors if you don't have one or more of the debugger libraries installed.
+# But in turn those ignores will cause unused-ignore errors if those libraries aren't installed...
+# mypy: disable-error-code="unused-ignore"
+
import os
import sys
@@ -148,11 +152,11 @@ def init_debugger(debug_type:str, ini: dict):
try:
if debugger == 'vscode':
- import debugpy
+ import debugpy # type: ignore[import-untyped, import-not-found]
elif debugger == 'pycharm':
- import pydevd_pycharm
+ import pydevd_pycharm # type: ignore[import-untyped, import-not-found]
elif debugger == 'pydev':
- import pydevd
+ import pydevd # type: ignore[import-untyped, import-not-found]
elif debugger == 'file':
pass
else:
diff --git a/lib/debug/logging.py b/lib/debug/logging.py
index fa474348..c46140ec 100644
--- a/lib/debug/logging.py
+++ b/lib/debug/logging.py
@@ -69,6 +69,7 @@
import os
import sys
from pathlib import Path
+from typing import Dict, Any
if sys.version_info >= (3, 11):
import tomllib # built-in in Python 3.11+
@@ -139,7 +140,7 @@ def disable_warnings():
# in development mode we want to use configuration from some LOGGING.toml file
def activate_for_development(ini: dict, SCRIPTDIR: Path):
logging_config_file = safe_get(ini, "LOGGING", "log_config_file", default=None)
- vars = {'SCRIPTDIR': SCRIPTDIR} # dynamic data for logging configuration
+ vars: Dict[str, Any] = {'SCRIPTDIR': SCRIPTDIR} # dynamic data for logging configuration
if logging_config_file is not None:
logging_config_file = Path(logging_config_file)
@@ -157,7 +158,7 @@ def activate_for_development(ini: dict, SCRIPTDIR: Path):
logger.info("Running in development mode")
logger.info(f"Using logging configuration from file: {logging_config_file}")
- logger.debug(f"Logging configuration: {devel_config = }")
+ logger.debug(f"Logging configuration: {devel_config=}")
# --------------------------------------------------------------------------------------------
@@ -177,7 +178,7 @@ def configure_logging(config: dict, ini: dict, vars: dict):
disable_logging = safe_get(ini, "LOGGING", "disable_logging", default=False)
if disable_logging:
- logger.warning(f"Logging is disabled by configuration in ini file. {disable_logging = }")
+ logger.warning(f"Logging is disabled by configuration in ini file. {disable_logging=}")
logging.disable() # globally disable all logging of all loggers
diff --git a/lib/debug/utils.py b/lib/debug/utils.py
index 10d840d9..a758ab3b 100644
--- a/lib/debug/utils.py
+++ b/lib/debug/utils.py
@@ -14,6 +14,10 @@ import logging
logger = logging.getLogger("inkstitch")
+# We have some ignores so you don't see errors if you don't have one or more of the profiling libraries installed.
+# But in turn those ignores will cause unused-ignore errors if those libraries aren't installed...
+# mypy: disable-error-code="unused-ignore"
+
# safe_get - get value from nested dictionary, return default if key does not exist
# - to read nested values from dict - mimic get method of dict with default value
@@ -67,7 +71,7 @@ def write_offline_debug_script(debug_script_dir: Path, ini: dict):
# environment PATH
f.write('# PATH:\n')
- f.write(f'# {os.environ.get("PATH","")}\n')
+ f.write(f'# {os.environ.get("PATH", "")}\n')
# for p in os.environ.get("PATH", '').split(os.pathsep): # PATH to list
# f.write(f'# {p}\n')
@@ -217,6 +221,8 @@ def profile(profiler_type, profile_dir: Path, ini: dict, extension, remaining_ar
with_profile(extension, remaining_args, profile_file_path)
elif profiler_type == 'pyinstrument':
with_pyinstrument(extension, remaining_args, profile_file_path)
+ elif profiler_type == 'monkeytype':
+ with_monkeytype(extension, remaining_args, profile_file_path)
else:
raise ValueError(f"unknown profiler type: '{profiler_type}'")
@@ -265,7 +271,7 @@ def with_pyinstrument(extension, remaining_args, profile_file_path: Path):
'''
profile with pyinstrument
'''
- import pyinstrument
+ import pyinstrument # type: ignore[import-untyped,import-not-found]
profiler = pyinstrument.Profiler()
profiler.start()
@@ -276,3 +282,25 @@ def with_pyinstrument(extension, remaining_args, profile_file_path: Path):
with open(profile_file_path, 'w') as stats_file:
stats_file.write(profiler.output_html())
print(f"Profiler: pyinstrument, stats written to '{profile_file_path.name}'. Use browser to see it.", file=sys.stderr)
+
+
+def with_monkeytype(extension, remaining_args, profile_file_path: Path) -> None:
+ '''
+ 'profile' with monkeytype to get type information. This may be handy for anyone who wants to
+ add type annotations to older parts of our code that don't have them.
+
+ See https://monkeytype.readthedocs.io/en/stable/generation.html for usage instructions.
+ '''
+ import monkeytype # type: ignore[import-not-found]
+
+ # Monkeytype will use these environment variables for the db path and to filter the modules respectively.
+ # This is easier than using monkeytype's actual config API, anyway.
+ dbpath = profile_file_path.with_suffix('.sqlite')
+ os.environ["MT_DB_PATH"] = str(dbpath)
+ os.environ["MONKEYTYPE_TRACE_MODULES"] = str(Path(__file__).parents[2].name)
+
+ with monkeytype.trace():
+ extension.run(args=remaining_args)
+
+ print(f"Profiler: monkeytype, db written to '{dbpath}'.\n\n" +
+ f"Run 'MT_DB_PATH={dbpath} monkeytype ...' from the inkstitch repo directory.", file=sys.stderr)