summaryrefslogtreecommitdiff
path: root/lib/debug_utils.py
diff options
context:
space:
mode:
authorkarnigen <karnigen@gmail.com>2024-05-03 01:34:58 +0200
committerGitHub <noreply@github.com>2024-05-03 01:34:58 +0200
commitbf5c2dfd67fac98868f86276504715ecfe1c369a (patch)
tree3b6bd611f452156fab48201fe7c868536dcb3e2d /lib/debug_utils.py
parentad2914284e8ef5f59c410018415dbb8d574586f8 (diff)
Kgn/logging revamp (#2720)
* update config files * rebase after electron remove * added toml to requirements * logging update * Unified use of the TOML format instead of INI [no ci] * Unified use of the TOML format instead of INI [no ci] * moving debug*.py to debug dir, moving some part for debugger [no ci] * use of alternate logging in some cases * updated debug logger [no ci] * logging update * updated notes * updated notes about logging * style check
Diffstat (limited to 'lib/debug_utils.py')
-rw-r--r--lib/debug_utils.py263
1 files changed, 0 insertions, 263 deletions
diff --git a/lib/debug_utils.py b/lib/debug_utils.py
deleted file mode 100644
index ef8b364d..00000000
--- a/lib/debug_utils.py
+++ /dev/null
@@ -1,263 +0,0 @@
-# Authors: see git history
-#
-# Copyright (c) 2010 Authors
-# Licensed under the GNU GPL version 3.0 or later. See the file LICENSE for details.
-
-import os
-import sys
-from pathlib import Path # to work with paths as objects
-import configparser # to read DEBUG.ini
-
-# this file is without: import inkex
-# - we need dump argv and sys.path as is on startup from inkscape
-# - later sys.path may be modified that influences importing inkex (see prefere_pip_inkex)
-
-
-def write_offline_debug_script(debug_script_dir: Path, ini: configparser.ConfigParser):
- '''
- prepare Bash script for offline debugging from console
- arguments:
- - debug_script_dir - Path object, absolute path to directory of inkstitch.py
- - ini - see DEBUG.ini
- '''
-
- # define names of files used by offline Bash script
- bash_file_base = ini.get("DEBUG", "bash_file_base", fallback="debug_inkstitch")
- bash_name = Path(bash_file_base).with_suffix(".sh") # Path object
- bash_svg = Path(bash_file_base).with_suffix(".svg") # Path object
-
- # check if input svg file exists in arguments, take argument that not start with '-' as file name
- svgs = [arg for arg in sys.argv[1:] if not arg.startswith('-')]
- if len(svgs) != 1:
- print(f"WARN: {len(svgs)} svg files found, expected 1, [{svgs}]. No script created in write debug script.", file=sys.stderr)
- return
-
- svg_file = Path(svgs[0])
- if svg_file.exists() and bash_svg.exists() and bash_svg.samefile(svg_file):
- print("WARN: input svg file is same as output svg file. No script created in write debug script.", file=sys.stderr)
- return
-
- import shutil # to copy svg file
- bash_file = debug_script_dir / bash_name
-
- with open(bash_file, 'w') as f: # "w" text mode, automatic conversion of \n to os.linesep
- f.write('#!/usr/bin/env bash\n')
-
- # cmd line arguments for debugging and profiling
- f.write(bash_parser()) # parse cmd line arguments: -d -p
-
- f.write(f'# python version: {sys.version}\n') # python version
-
- myargs = " ".join(sys.argv[1:])
- f.write(f'# script: {sys.argv[0]} arguments: {myargs}\n') # script name and arguments
-
- # environment PATH
- f.write('# 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')
-
- # python module path
- f.write('# python sys.path:\n')
- for p in sys.path:
- f.write(f'# {p}\n')
-
- # see static void set_extensions_env() in inkscape/src/inkscape-main.cpp
- f.write('# PYTHONPATH:\n')
- for p in os.environ.get('PYTHONPATH', '').split(os.pathsep): # PYTHONPATH to list
- f.write(f'# {p}\n')
-
- f.write(f'# copy {svg_file} to {bash_svg}\n#\n')
- shutil.copy(svg_file, debug_script_dir / bash_svg) # copy file to bash_svg
- myargs = myargs.replace(str(svg_file), str(bash_svg)) # replace file name with bash_svg
-
- # see void Extension::set_environment() in inkscape/src/extension/extension.cpp
- f.write('# Export inkscape environment variables:\n')
- notexported = ['SELF_CALL'] # if an extension calls inkscape itself
- exported = ['INKEX_GETTEXT_DOMAIN', 'INKEX_GETTEXT_DIRECTORY',
- 'INKSCAPE_PROFILE_DIR', 'DOCUMENT_PATH', 'PYTHONPATH']
- for k in notexported:
- if k in os.environ:
- f.write(f'# export {k}="{os.environ[k]}"\n')
- for k in exported:
- if k in os.environ:
- f.write(f'export {k}="{os.environ[k]}"\n')
-
- f.write('# signal inkstitch.py that we are running from offline script\n')
- f.write('export INKSTITCH_OFFLINE_SCRIPT="True"\n')
-
- f.write('# call inkstitch\n')
- f.write(f'python3 inkstitch.py {myargs}\n')
- bash_file.chmod(0o0755) # make file executable, hopefully ignored on Windows
-
-
-def bash_parser():
- return r'''
-set -e # exit on error
-
-# parse cmd line arguments:
-# -d enable debugging
-# -p enable profiling
-# ":..." - silent error reporting
-while getopts ":dp" opt; do
- case $opt in
- d)
- export INKSTITCH_DEBUG_ENABLE="True"
- ;;
- p)
- export INKSTITCH_PROFILE_ENABLE="True"
- ;;
- \?)
- echo "Invalid option: -$OPTARG" >&2
- exit 1
- ;;
- :)
- echo "Option -$OPTARG requires an argument." >&2
- exit 1
- ;;
- esac
-done
-
-'''
-
-
-def reorder_sys_path():
- '''
- change sys.path to prefer pip installed inkex over inkscape bundled inkex
- '''
-
- # see static void set_extensions_env() in inkscape/src/inkscape-main.cpp
- # what we do:
- # - move inkscape extensions path to the end of sys.path
- # - we compare PYTHONPATH with sys.path and move PYTHONPATH to the end of sys.path
- # - also user inkscape extensions path is moved to the end of sys.path - may cause problems?
- # - path for deprecated-simple are removed from sys.path, will be added later by importing inkex
-
- # PYTHONPATH to list
- pythonpath = os.environ.get('PYTHONPATH', '').split(os.pathsep)
- # remove pythonpath from sys.path
- sys.path = [p for p in sys.path if p not in pythonpath]
- # remove deprecated-simple, it will be added later by importing inkex
- pythonpath = [p for p in pythonpath if not p.endswith('deprecated-simple')]
- # remove nonexisting paths
- pythonpath = [p for p in pythonpath if os.path.exists(p)]
- # add pythonpath to the end of sys.path
- sys.path.extend(pythonpath)
-
-
-# -----------------------------------------------------------------------------
-# try to resolve debugger type from ini file or cmd line of bash
-def resole_debug_type(ini: configparser.ConfigParser):
- # enable/disable debugger from bash: -d
- if os.environ.get('INKSTITCH_DEBUG_ENABLE', '').lower() in ['true', '1', 'yes', 'y']:
- debug_enable = True
- else:
- debug_enable = ini.getboolean("DEBUG", "debug_enable", fallback=False) # enable debugger on startup from ini
-
- debug_type = ini.get("DEBUG", "debug_type", fallback="none") # debugger type vscode, pycharm, pydevd
- if not debug_enable:
- debug_type = 'none'
-
- debug_to_file = ini.getboolean("DEBUG", "debug_to_file", fallback=False) # write debug output to file
- if debug_to_file and debug_type == 'none':
- debug_type = 'file'
-
- return debug_type
-
-
-# try to resolve profiler type from ini file or cmd line of bash
-def resole_profile_type(ini: configparser.ConfigParser):
- # enable/disable profiling from bash: -p
- if os.environ.get('INKSTITCH_PROFILE_ENABLE', '').lower() in ['true', '1', 'yes', 'y']:
- profile_enable = True
- else:
- profile_enable = ini.getboolean("PROFILE", "profile_enable", fallback=False) # read from ini
-
- # specify profiler type
- profiler_type = ini.get("PROFILE", "profiler_type", fallback="none") # profiler type cprofile, profile, pyinstrument
- if not profile_enable:
- profiler_type = 'none'
-
- return profiler_type
-
-# -----------------------------------------------------------------------------
-
-# Profilers:
-# currently supported profilers:
-# - cProfile - standard python profiler
-# - profile - standard python profiler
-# - pyinstrument - profiler with nice html output
-
-
-def profile(profiler_type, profile_dir: Path, ini: configparser.ConfigParser, extension, remaining_args):
- '''
- profile with cProfile, profile or pyinstrument
- '''
- profile_file_base = ini.get("PROFILE", "profile_file_base", fallback="debug_profile")
- profile_file_path = profile_dir / profile_file_base # Path object
-
- if profiler_type == 'cprofile':
- with_cprofile(extension, remaining_args, profile_file_path)
- elif profiler_type == 'profile':
- with_profile(extension, remaining_args, profile_file_path)
- elif profiler_type == 'pyinstrument':
- with_pyinstrument(extension, remaining_args, profile_file_path)
- else:
- raise ValueError(f"unknown profiler type: '{profiler_type}'")
-
-
-def with_cprofile(extension, remaining_args, profile_file_path):
- '''
- profile with cProfile
- '''
- import cProfile
- import pstats
- profiler = cProfile.Profile()
-
- profiler.enable()
- extension.run(args=remaining_args)
- profiler.disable()
-
- profiler.dump_stats(profile_file_path.with_suffix(".prof")) # can be read by 'snakeviz -s' or 'pyprof2calltree'
- with open(profile_file_path, 'w') as stats_file:
- stats = pstats.Stats(profiler, stream=stats_file)
- stats.sort_stats(pstats.SortKey.CUMULATIVE)
- stats.print_stats()
- print(f"Profiler: cprofile, stats written to '{profile_file_path.name}' and '{profile_file_path.name}.prof'. Use snakeviz to see it.",
- file=sys.stderr)
-
-
-def with_profile(extension, remaining_args, profile_file_path):
- '''
- profile with profile
- '''
- import profile
- import pstats
- profiler = profile.Profile()
-
- profiler.run('extension.run(args=remaining_args)')
-
- profiler.dump_stats(profile_file_path.with_suffix(".prof")) # can be read by 'snakeviz' or 'pyprof2calltree' - seems broken
- with open(profile_file_path, 'w') as stats_file:
- stats = pstats.Stats(profiler, stream=stats_file)
- stats.sort_stats(pstats.SortKey.CUMULATIVE)
- stats.print_stats()
- print(f"'Profiler: profile, stats written to '{profile_file_path.name}' and '{profile_file_path.name}.prof'. Use of snakeviz is broken.",
- file=sys.stderr)
-
-
-def with_pyinstrument(extension, remaining_args, profile_file_path):
- '''
- profile with pyinstrument
- '''
- import pyinstrument
- profiler = pyinstrument.Profiler()
-
- profiler.start()
- extension.run(args=remaining_args)
- profiler.stop()
-
- profile_file_path = profile_file_path.with_suffix(".html")
- 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)