kopia lustrzana https://github.com/inkstitch/inkstitch
replace DEBUG,PROFILE by DEVEL.ini
rodzic
fe323375e4
commit
f1f9d275a1
|
@ -1,31 +1,33 @@
|
||||||
|
__pycache__
|
||||||
*.swp
|
*.swp
|
||||||
*.kate-swp
|
*.kate-swp
|
||||||
*.pyc
|
*.pyc
|
||||||
*.spec
|
*.spec
|
||||||
*.zip
|
*.zip
|
||||||
*.tar.gz
|
*.tar.gz
|
||||||
|
*.po
|
||||||
dist/
|
dist/
|
||||||
build/
|
build/
|
||||||
locales/
|
locales/
|
||||||
/inx/
|
/inx/
|
||||||
*.po
|
|
||||||
/DEBUG
|
|
||||||
.pydevproject
|
.pydevproject
|
||||||
.project
|
.project
|
||||||
/debug.log
|
|
||||||
/debug.svg
|
|
||||||
/.idea
|
/.idea
|
||||||
|
/.vscode
|
||||||
/VERSION
|
/VERSION
|
||||||
/src/
|
/src/
|
||||||
.DS_STORE
|
.DS_STORE
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
flaskserverport.json
|
||||||
|
electron/yarn.lock
|
||||||
|
|
||||||
|
# debug and profile files
|
||||||
|
/DEVEL.ini
|
||||||
|
/DEBUG
|
||||||
/PROFILE
|
/PROFILE
|
||||||
|
/debug*
|
||||||
|
/.debug*
|
||||||
|
# old profile files
|
||||||
/profile_stats
|
/profile_stats
|
||||||
/profile_stats.html
|
/profile_stats.html
|
||||||
/profile_stats.prof
|
/profile_stats.prof
|
||||||
/.vscode
|
|
||||||
__pycache__
|
|
||||||
flaskserverport.json
|
|
||||||
electron/yarn.lock
|
|
||||||
.ink.sh
|
|
||||||
.ink.svg
|
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
[LIBRARY]
|
||||||
|
;;; use the pip installed version of inkex.py, default: True
|
||||||
|
; prefer_pip_inkex = False
|
||||||
|
|
||||||
|
[DEBUG]
|
||||||
|
;;; select one active debugger, default: none
|
||||||
|
; debugger = vscode
|
||||||
|
; debugger = pycharm
|
||||||
|
; debugger = pydev
|
||||||
|
|
||||||
|
;;; disable debugger when calling from inkscape, default: False
|
||||||
|
; disable_from_inkscape = True
|
||||||
|
|
||||||
|
;;; wait for debugger to attach (vscode), default: True
|
||||||
|
; wait_attach = False
|
||||||
|
|
||||||
|
;;; debug log file, default: debug.log
|
||||||
|
; debug_file = debug.log
|
||||||
|
|
||||||
|
;;; creation of bash script, default: False
|
||||||
|
; create_bash_script = True
|
||||||
|
|
||||||
|
;;; base name for bash script, default: debug_inkstitch
|
||||||
|
; bash_file_base = debug_inkstitch
|
||||||
|
|
||||||
|
[PROFILE]
|
||||||
|
;;; select one active profiler, default: none
|
||||||
|
; profiler = cprofile
|
||||||
|
; profiler = profile
|
||||||
|
; profiler = pyinstrument
|
||||||
|
|
||||||
|
;;; base name for profile output files, default: debug_profile
|
||||||
|
; profile_file_base = debug_profile
|
||||||
|
|
||||||
|
|
76
inkstitch.py
76
inkstitch.py
|
@ -5,53 +5,60 @@
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import lib.debug_utils as debug_utils
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
import configparser
|
||||||
|
import lib.debug_utils as debug_utils
|
||||||
|
|
||||||
SCRIPTDIR = Path(__file__).parent.absolute()
|
SCRIPTDIR = Path(__file__).parent.absolute()
|
||||||
|
|
||||||
if len(sys.argv) < 2:
|
if len(sys.argv) < 2:
|
||||||
exit(1) # no arguments - prevent accidentally running this script
|
# no arguments - prevent accidentally running this script
|
||||||
|
print("No arguments given, continue without arguments?")
|
||||||
prefere_pip_inkex = True # prefer pip installed inkex over inkscape bundled inkex
|
answer = input("Continue? [y/N] ")
|
||||||
|
if answer.lower() != 'y':
|
||||||
# define names of files used by offline Bash script
|
exit(1)
|
||||||
bash_name = ".ink.sh"
|
|
||||||
bash_svg = ".ink.svg"
|
|
||||||
|
|
||||||
running_as_frozen = getattr(sys, 'frozen', None) is not None # check if running from pyinstaller bundle
|
running_as_frozen = getattr(sys, 'frozen', None) is not None # check if running from pyinstaller bundle
|
||||||
# we assume that if arguments contain svg file (=.ink.svg) then we are running not from inkscape
|
|
||||||
running_from_inkscape = bash_svg not in sys.argv
|
ini = configparser.ConfigParser()
|
||||||
|
ini.read(SCRIPTDIR / "DEVEL.ini") # read DEVEL.ini file if exists
|
||||||
|
|
||||||
|
# prefer pip installed inkex over inkscape bundled inkex, pip version is bundled with Inkstitch
|
||||||
|
prefere_pip_inkex = ini.getboolean("LIBRARY","prefer_pip_inkex", fallback=True)
|
||||||
|
|
||||||
|
# check if running from inkscape, given by environment variable
|
||||||
|
if os.environ.get('INKSTITCH_OFFLINE_SCRIPT', '').lower() in ['true', '1', 'yes', 'y']:
|
||||||
|
running_from_inkscape = False
|
||||||
|
else:
|
||||||
|
running_from_inkscape = True
|
||||||
|
|
||||||
debug_active = bool((gettrace := getattr(sys, 'gettrace')) and gettrace()) # check if debugger is active on startup
|
debug_active = bool((gettrace := getattr(sys, 'gettrace')) and gettrace()) # check if debugger is active on startup
|
||||||
debug_file = SCRIPTDIR / "DEBUG"
|
|
||||||
debug_type = 'none'
|
debug_type = 'none'
|
||||||
|
|
||||||
profile_file = SCRIPTDIR / "PROFILE"
|
|
||||||
profile_type = 'none'
|
profile_type = 'none'
|
||||||
|
|
||||||
if not running_as_frozen: # debugging/profiling only in development mode
|
if not running_as_frozen: # debugging/profiling only in development mode
|
||||||
# parse debug file
|
# define names of files used by offline Bash script
|
||||||
# - if script was already started from debugger then don't read debug file
|
bash_file_base = ini.get("DEBUG","bash_file_base", fallback="debug_inkstitch")
|
||||||
if not debug_active and os.path.exists(debug_file):
|
bash_name = Path(bash_file_base).with_suffix(".sh") # Path object
|
||||||
debug_type = debug_utils.parse_file(debug_file) # read type of debugger from debug_file DEBUG
|
bash_svg = Path(bash_file_base).with_suffix(".svg") # Path object
|
||||||
if debug_type == 'none': # for better backward compatibility
|
|
||||||
print(f"Debug file exists but no debugger type found in '{debug_file.name}'", file=sys.stderr)
|
|
||||||
|
|
||||||
# parse profile file
|
# specify debugger type
|
||||||
if os.path.exists(profile_file):
|
# - if script was already started from debugger then don't read debug file
|
||||||
profile_type = debug_utils.parse_file(profile_file) # read type of profiler from profile_file PROFILE
|
if not debug_active:
|
||||||
if profile_type == 'none': # for better backward compatibility
|
debug_type = ini.get("DEBUG","debugger", fallback="none") # debugger type vscode, pycharm, pydevd, none
|
||||||
print(f"Profile file exists but no profiler type found in '{profile_file.name}'", file=sys.stderr)
|
|
||||||
|
# specify profiler type
|
||||||
|
profile_type = ini.get("PROFILE","profiler", fallback="none") # profiler type cprofile, profile, pyinstrument, none
|
||||||
|
|
||||||
# process creation of the Bash script
|
# process creation of the Bash script
|
||||||
if running_from_inkscape:
|
if running_from_inkscape:
|
||||||
if debug_type.endswith('-script'): # if offline debugging just create script for later debugging
|
if ini.getboolean("DEBUG","create_bash_script", fallback=False): # create script only if enabled in DEVEL.ini
|
||||||
debug_utils.write_offline_debug_script(SCRIPTDIR, bash_name, bash_svg)
|
debug_utils.write_offline_debug_script(SCRIPTDIR, bash_name, bash_svg)
|
||||||
|
|
||||||
|
# disable debugger when running from inkscape
|
||||||
|
disable_from_inkscape = ini.getboolean("DEBUG","disable_from_inkscape", fallback=False)
|
||||||
|
if disable_from_inkscape:
|
||||||
debug_type = 'none' # do not start debugger when running from inkscape
|
debug_type = 'none' # do not start debugger when running from inkscape
|
||||||
else: # not running from inkscape
|
|
||||||
if debug_type.endswith('-script'): # remove '-script' to propely initialize debugger packages for each editor
|
|
||||||
debug_type = debug_type.replace('-script', '')
|
|
||||||
|
|
||||||
if prefere_pip_inkex and 'PYTHONPATH' in os.environ:
|
if prefere_pip_inkex and 'PYTHONPATH' in os.environ:
|
||||||
# see static void set_extensions_env() in inkscape/src/inkscape-main.cpp
|
# see static void set_extensions_env() in inkscape/src/inkscape-main.cpp
|
||||||
|
@ -100,7 +107,9 @@ from lib.utils import restore_stderr, save_stderr
|
||||||
|
|
||||||
# file DEBUG exists next to inkstitch.py - enabling debug mode depends on value of debug_type in DEBUG file
|
# file DEBUG exists next to inkstitch.py - enabling debug mode depends on value of debug_type in DEBUG file
|
||||||
if debug_type != 'none':
|
if debug_type != 'none':
|
||||||
debug.enable(debug_type)
|
debug_file = ini.get("DEBUG","debug_file", fallback="debug.log")
|
||||||
|
wait_attach = ini.getboolean("DEBUG","wait_attach", fallback=True) # currently only for vscode
|
||||||
|
debug.enable(debug_type, debug_file, wait_attach)
|
||||||
# check if debugger is really activated
|
# check if debugger is really activated
|
||||||
debug_active = bool((gettrace := getattr(sys, 'gettrace')) and gettrace())
|
debug_active = bool((gettrace := getattr(sys, 'gettrace')) and gettrace())
|
||||||
|
|
||||||
|
@ -136,9 +145,8 @@ extension = extension_class() # create instance of extension class - call __ini
|
||||||
# - in debug or profile mode we run extension or profile extension
|
# - in debug or profile mode we run extension or profile extension
|
||||||
# - in normal mode we run extension in try/except block to catch all exceptions and hide GTK spam
|
# - in normal mode we run extension in try/except block to catch all exceptions and hide GTK spam
|
||||||
if debug_active or profile_type != "none": # if debug or profile mode
|
if debug_active or profile_type != "none": # if debug or profile mode
|
||||||
print(f"Extension:'{extension_name}' Debug active:{debug_active} type:'{debug_type}' "
|
profile_file_base = ini.get("PROFILE","profile_file_base", fallback="debug_profile")
|
||||||
f"Profile type:'{profile_type}'", file=sys.stderr)
|
profile_path = SCRIPTDIR / profile_file_base # Path object
|
||||||
profile_path = SCRIPTDIR / "profile_stats"
|
|
||||||
|
|
||||||
if profile_type == 'none':
|
if profile_type == 'none':
|
||||||
extension.run(args=remaining_args)
|
extension.run(args=remaining_args)
|
||||||
|
@ -156,7 +164,7 @@ if debug_active or profile_type != "none": # if debug or profile mode
|
||||||
stats = pstats.Stats(profiler, stream=stats_file)
|
stats = pstats.Stats(profiler, stream=stats_file)
|
||||||
stats.sort_stats(pstats.SortKey.CUMULATIVE)
|
stats.sort_stats(pstats.SortKey.CUMULATIVE)
|
||||||
stats.print_stats()
|
stats.print_stats()
|
||||||
print(f"profiling stats written to '{profile_path.name}' and '{profile_path.name}.prof'", file=sys.stderr)
|
print(f"profiling stats written to '{profile_path.name}' and '{profile_path.name}.prof'. Use snakeviz to see it.", file=sys.stderr)
|
||||||
|
|
||||||
elif profile_type == 'profile':
|
elif profile_type == 'profile':
|
||||||
import profile
|
import profile
|
||||||
|
@ -183,7 +191,7 @@ if debug_active or profile_type != "none": # if debug or profile mode
|
||||||
profile_path = SCRIPTDIR / "profile_stats.html"
|
profile_path = SCRIPTDIR / "profile_stats.html"
|
||||||
with open(profile_path, 'w') as stats_file:
|
with open(profile_path, 'w') as stats_file:
|
||||||
stats_file.write(profiler.output_html())
|
stats_file.write(profiler.output_html())
|
||||||
print(f"profiling stats written to '{profile_path.name}'", file=sys.stderr)
|
print(f"profiling stats written to '{profile_path.name}'. Use browser to see it.", file=sys.stderr)
|
||||||
|
|
||||||
else: # if not debug nor profile mode
|
else: # if not debug nor profile mode
|
||||||
save_stderr() # hide GTK spam
|
save_stderr() # hide GTK spam
|
||||||
|
|
21
lib/debug.py
21
lib/debug.py
|
@ -63,23 +63,25 @@ class Debug(object):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.debugger = None
|
self.debugger = None
|
||||||
|
self.wait_attach = True
|
||||||
self.enabled = False
|
self.enabled = False
|
||||||
self.last_log_time = None
|
self.last_log_time = None
|
||||||
self.current_layer = None
|
self.current_layer = None
|
||||||
self.group_stack = []
|
self.group_stack = []
|
||||||
|
|
||||||
|
|
||||||
def enable(self, debug_type):
|
def enable(self, debug_type, debug_file, wait_attach):
|
||||||
if debug_type == 'none':
|
if debug_type == 'none':
|
||||||
return
|
return
|
||||||
self.debugger = debug_type
|
self.debugger = debug_type
|
||||||
|
self.wait_attach = wait_attach
|
||||||
self.enabled = True
|
self.enabled = True
|
||||||
self.init_log()
|
self.init_log(debug_file)
|
||||||
self.init_debugger()
|
self.init_debugger()
|
||||||
self.init_svg()
|
self.init_svg()
|
||||||
|
|
||||||
def init_log(self):
|
def init_log(self, debug_file):
|
||||||
self.log_file = os.path.join(os.path.dirname(os.path.dirname(__file__)), "debug.log")
|
self.log_file = os.path.join(os.path.dirname(os.path.dirname(__file__)), debug_file)
|
||||||
# delete old content
|
# delete old content
|
||||||
with open(self.log_file, "w"):
|
with open(self.log_file, "w"):
|
||||||
pass
|
pass
|
||||||
|
@ -196,9 +198,10 @@ class Debug(object):
|
||||||
try:
|
try:
|
||||||
if self.debugger == 'vscode':
|
if self.debugger == 'vscode':
|
||||||
debugpy.listen(('localhost', 5678))
|
debugpy.listen(('localhost', 5678))
|
||||||
print("Waiting for debugger attach")
|
if self.wait_attach:
|
||||||
debugpy.wait_for_client() # wait for debugger to attach
|
print("Waiting for debugger attach")
|
||||||
debugpy.breakpoint() # stop here to start normal debugging
|
debugpy.wait_for_client() # wait for debugger to attach
|
||||||
|
debugpy.breakpoint() # stop here to start normal debugging
|
||||||
elif self.debugger == 'pycharm':
|
elif self.debugger == 'pycharm':
|
||||||
pydevd_pycharm.settrace('localhost', port=5678, stdoutToServer=True,
|
pydevd_pycharm.settrace('localhost', port=5678, stdoutToServer=True,
|
||||||
stderrToServer=True)
|
stderrToServer=True)
|
||||||
|
@ -360,5 +363,5 @@ class Debug(object):
|
||||||
debug = Debug()
|
debug = Debug()
|
||||||
|
|
||||||
|
|
||||||
def enable(debug_type):
|
def enable(debug_type, debug_file, wait_attach):
|
||||||
debug.enable(debug_type)
|
debug.enable(debug_type, debug_file, wait_attach)
|
||||||
|
|
|
@ -5,6 +5,12 @@
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
# this file is without: import inkex
|
||||||
|
# - so we can modify sys.path before importing inkex
|
||||||
|
|
||||||
|
# DEBUG and PROFILE are in DEVEL.ini file
|
||||||
|
|
||||||
# DEBUG file format:
|
# DEBUG file format:
|
||||||
# - first non-comment line is debugger type
|
# - first non-comment line is debugger type
|
||||||
|
@ -45,12 +51,24 @@ def parse_file(filename):
|
||||||
break
|
break
|
||||||
return value_type
|
return value_type
|
||||||
|
|
||||||
def write_offline_debug_script(SCRIPTDIR, bash_name, bash_svg):
|
def write_offline_debug_script(SCRIPTDIR : Path, bash_name : Path, bash_svg : Path):
|
||||||
# prepare script for offline debugging from console
|
# prepare script for offline debugging from console
|
||||||
# - only tested on linux
|
|
||||||
|
# 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(f"WARN: input svg file is same as output svg file. No script created in write debug script.", file=sys.stderr)
|
||||||
|
return
|
||||||
|
|
||||||
import shutil
|
import shutil
|
||||||
ink_file = os.path.join(SCRIPTDIR, bash_name)
|
bash_file = SCRIPTDIR / bash_name
|
||||||
with open(ink_file, 'w') as f:
|
|
||||||
|
with open(bash_file, 'w') as f: # "w" text mode, automatic conversion of \n to os.linesep
|
||||||
f.write(f"#!/usr/bin/env bash\n\n")
|
f.write(f"#!/usr/bin/env bash\n\n")
|
||||||
f.write(f"# python version: {sys.version}\n") # python version
|
f.write(f"# python version: {sys.version}\n") # python version
|
||||||
|
|
||||||
|
@ -67,13 +85,11 @@ def write_offline_debug_script(SCRIPTDIR, bash_name, bash_svg):
|
||||||
for p in os.environ.get('PYTHONPATH', '').split(os.pathsep): # PYTHONPATH to list
|
for p in os.environ.get('PYTHONPATH', '').split(os.pathsep): # PYTHONPATH to list
|
||||||
f.write(f"# {p}\n")
|
f.write(f"# {p}\n")
|
||||||
|
|
||||||
# take argument that not start with '-' as file name
|
|
||||||
svg_file = " ".join([arg for arg in sys.argv[1:] if not arg.startswith('-')])
|
|
||||||
f.write(f"# copy {svg_file} to {bash_svg}\n")
|
f.write(f"# copy {svg_file} to {bash_svg}\n")
|
||||||
# check if files are not the same
|
# check if files are not the same
|
||||||
if svg_file != bash_svg:
|
if svg_file != bash_svg:
|
||||||
shutil.copy(svg_file, SCRIPTDIR / bash_svg) # copy file to bash_svg
|
shutil.copy(svg_file, SCRIPTDIR / bash_svg) # copy file to bash_svg
|
||||||
myargs = myargs.replace(svg_file, bash_svg) # replace file name with 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
|
# see void Extension::set_environment() in inkscape/src/extension/extension.cpp
|
||||||
notexported = ["SELF_CALL"] # if an extension calls inkscape itself
|
notexported = ["SELF_CALL"] # if an extension calls inkscape itself
|
||||||
|
@ -86,5 +102,9 @@ def write_offline_debug_script(SCRIPTDIR, bash_name, bash_svg):
|
||||||
if k in os.environ:
|
if k in os.environ:
|
||||||
f.write(f'export {k}="{os.environ[k]}"\n')
|
f.write(f'export {k}="{os.environ[k]}"\n')
|
||||||
|
|
||||||
|
f.write('# signal inkstitch.py that we are running from offline script\n')
|
||||||
|
f.write(f'export INKSTITCH_OFFLINE_SCRIPT="True"\n')
|
||||||
|
|
||||||
|
f.write('# call inkstitch\n')
|
||||||
f.write(f"python3 inkstitch.py {myargs}\n")
|
f.write(f"python3 inkstitch.py {myargs}\n")
|
||||||
os.chmod(ink_file, 0o0755) # make file executable
|
bash_file.chmod(0o0755) # make file executable
|
||||||
|
|
Ładowanie…
Reference in New Issue