Unified use of the TOML format instead of INI [no ci]

karnigen 2024-03-20 14:55:11 +01:00
rodzic 5f6989886b
commit 1080eceb14
8 zmienionych plików z 140 dodań i 113 usunięć

6
.gitignore vendored
Wyświetl plik

@ -23,12 +23,14 @@ flaskserverport.json
electron/yarn.lock
# debug and profile files
/DEBUG.ini
/DEBUG.toml
/LOGGING.toml
/LOGGING[0-9]*.toml
/debug*
/.debug*
# old debug files
# old debug files - to be removed
/DEBUG*.ini
/DEBUG
/PROFILE
/profile*

Wyświetl plik

@ -1,59 +0,0 @@
[LIBRARY]
;;; use the pip installed version of inkex.py, default: True
; prefer_pip_inkex = False
[LOGGING]
;;; logging configuration file, default: none - use implicit DEBUG logging to inkstitch.log
;;; we may have multiple configurations: LOGGING.toml, LOGGING1.toml, LOGGING2.toml, etc.
; log_config_file = LOGGING.toml
;;; disable globally logging: default: False - using logging.disable()
;;; reenable logging.disable(0)
; disable_logging = True
[DEBUG]
;;; simulate frozen mode, overwrite running_as_frozen in inkstitch.py, default: False
; force_frozen = True
;;; select one active debug_type, default: none
; debug_type = vscode
; debug_type = pycharm
; debug_type = pydev
;;; enable debugger, see cmd line arg -d, default: False
; debug_enable = True
;;; debug log output to file even if debugger is not enabled, default: False
; debug_to_file = True
;;; 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_log_file = debug.log
;;; debug file for graph related things, default: debug.svg
; debug_svg_file = debug.svg
;;; 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_type, default: none
; profiler_type = cprofile
; profiler_type = profile
; profiler_type = pyinstrument
;;; enable profiler, see cmd line arg -p, default: False
; profile_enable = True
;;; base name for profile output files, default: debug_profile
; profile_file_base = debug_profile

Wyświetl plik

@ -0,0 +1,57 @@
[LIBRARY]
### use the pip installed version of inkex.py, default: True
# prefer_pip_inkex = false
[LOGGING]
### logging configuration file, default: none - use implicit DEBUG logging to inkstitch.log
### we may have multiple configurations: LOGGING.toml, LOGGING1.toml, LOGGING2.toml, etc.
# log_config_file = "LOGGING.toml"
### disable globally logging: default: False - using logging.disable()
### reenable logging.disable(0)
# disable_logging = true
[DEBUG]
### simulate frozen mode, overwrite running_as_frozen in inkstitch.py, default: False
# force_frozen = true
### select one active debug_type, default: none
# debug_type = "vscode"
# debug_type = "pycharm"
# debug_type = "pydev"
### enable debugger, see cmd line arg -d, default: False
# debug_enable = true
### debug log output to file even if debugger is not enabled, default: False
# debug_to_file = true
### 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_log_file = "debug.log"
### debug file for graph related things, default: debug.svg
# debug_svg_file = "debug.svg"
### 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_type, default: none
# profiler_type = "cprofile"
# profiler_type = "profile"
# profiler_type = "pyinstrument"
### enable profiler, see cmd line arg -p, default: False
# profile_enable = true
### base name for profile output files, default: debug_profile
# profile_file_base = "debug_profile"

Wyświetl plik

@ -1,6 +1,6 @@
# logging/warning template for inkstitch
# format: toml
# enable config file in DEBUG.ini: log_config_file
# enable config file in DEBUG.toml: log_config_file
# warnings.simplefilter(action), default: "default"
# - possible values: "error", "ignore", "always", "default", "module", "once"

Wyświetl plik

@ -8,28 +8,39 @@ import sys
from pathlib import Path # to work with paths as objects
from argparse import ArgumentParser # to parse arguments and remove --extension
import configparser # to read DEBUG.ini
import toml # to read logging configuration from toml file
import warnings
import logging
import logging.config
import toml # to read logging configuration from toml file
import warnings # to control python warnings
import logging # to configure logging
import logging.config # to configure logging from dict
import lib.debug_utils as debug_utils
import lib.debug_logging as debug_logging
from lib.debug_utils import safe_get # mimic get method of dict with default value
SCRIPTDIR = Path(__file__).parent.absolute()
logger = logging.getLogger("inkstitch") # create module logger with name 'inkstitch'
ini = configparser.ConfigParser()
ini.read(SCRIPTDIR / "DEBUG.ini") # read DEBUG.ini file if exists, otherwise use default values in ini object
# temporary - catch old DEBUG.ini file and inform user to reformat it to DEBUG.toml
old_debug_ini = SCRIPTDIR / "DEBUG.ini"
if old_debug_ini.exists():
print("ERROR: old DEBUG.ini exists, please reformat it to DEBUG.toml and remove DEBUG.ini file")
exit(1)
debug_toml = SCRIPTDIR / "DEBUG.toml"
if debug_toml.exists():
ini = toml.load(SCRIPTDIR / "DEBUG.toml") # read DEBUG.toml file if exists, otherwise use default values in ini object
else:
ini = {}
print(ini) # TODO remove this line after DEBUG.ini is not used anymore
# --------------------------------------------------------------------------------------------
running_as_frozen = getattr(sys, 'frozen', None) is not None # check if running from pyinstaller bundle
if not running_as_frozen: # override running_as_frozen from DEBUG.ini - for testing
if ini.getboolean("DEBUG", "force_frozen", fallback=False):
if not running_as_frozen: # override running_as_frozen from DEBUG.toml - for testing
if safe_get(ini, "DEBUG", "force_frozen", default=False):
running_as_frozen = True
if len(sys.argv) < 2:
# no arguments - prevent accidentally running this script
msg = "No arguments given, exiting!" # without gettext localization see _()
@ -57,7 +68,7 @@ if running_as_frozen: # in release mode
docpath = os.environ.get('DOCUMENT_PATH') # read document path from environment variable (set by inkscape) or None
if docpath is not None and loglevel is not None and loglevel.upper() in ['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL']:
# enable logging-warning and redirect output to input_svg.inkstitch.log
# end user enabled logging&warnings and redirect output to input_svg.inkstitch.log
logfilename = Path(docpath).with_suffix('.inkstitch.log') # log file is created in document path
loglevel = loglevel.upper()
@ -69,7 +80,7 @@ if running_as_frozen: # in release mode
else:
# in development mode we want to use configuration from some LOGGING.toml file
logging_config_file = ini.get("LOGGING", "log_config_file", fallback=None)
logging_config_file = safe_get(ini, "LOGGING", "log_config_file", default=None)
if logging_config_file is not None:
logging_config_file = Path(logging_config_file)
if logging_config_file.exists():
@ -107,21 +118,21 @@ if not running_as_frozen: # debugging/profiling only in development mode
if running_from_inkscape:
# process creation of the Bash script - should be done before sys.path is modified, see below in prefere_pip_inkex
if ini.getboolean("DEBUG", "create_bash_script", fallback=False): # create script only if enabled in DEBUG.ini
if safe_get(ini, "DEBUG", "create_bash_script", default=False): # create script only if enabled in DEBUG.toml
debug_utils.write_offline_debug_script(SCRIPTDIR, ini)
# disable debugger when running from inkscape
disable_from_inkscape = ini.getboolean("DEBUG", "disable_from_inkscape", fallback=False)
disable_from_inkscape = safe_get(ini, "DEBUG", "disable_from_inkscape", default=False)
if disable_from_inkscape:
debug_type = 'none' # do not start debugger when running from inkscape
# prefer pip installed inkex over inkscape bundled inkex, pip version is bundled with Inkstitch
# - must be be done before importing inkex
prefere_pip_inkex = ini.getboolean("LIBRARY", "prefer_pip_inkex", fallback=True)
prefere_pip_inkex = safe_get(ini, "LIBRARY", "prefer_pip_inkex", default=True)
if prefere_pip_inkex and 'PYTHONPATH' in os.environ:
debug_utils.reorder_sys_path()
# enabling of debug depends on value of debug_type in DEBUG.ini file
# enabling of debug depends on value of debug_type in DEBUG.toml file
if debug_type != 'none':
from lib.debug import debug # import global variable debug - don't import whole module
debug.enable(debug_type, SCRIPTDIR, ini)

Wyświetl plik

@ -11,8 +11,8 @@ import time # to measure time of code block, use time.monotonic() instead of
from datetime import datetime
from contextlib import contextmanager # to measure time of with block
import configparser # to read DEBUG.ini
from pathlib import Path # to work with paths as objects
from .debug_utils import safe_get # mimic get method of dict with default value
import inkex
from lxml import etree # to create svg file
@ -79,12 +79,12 @@ class Debug(object):
self.current_layer = None
self.group_stack = []
def enable(self, debug_type, debug_dir: Path, ini: configparser.ConfigParser):
# initilize file names and other parameters from DEBUG.ini file
def enable(self, debug_type, debug_dir: Path, ini: dict):
# initilize file names and other parameters from DEBUG.toml file
self.debug_dir = debug_dir # directory where debug files are stored
self.debug_log_file = ini.get("DEBUG", "debug_log_file", fallback="debug.log")
self.debug_svg_file = ini.get("DEBUG", "debug_svg_file", fallback="debug.svg")
self.wait_attach = ini.getboolean("DEBUG", "wait_attach", fallback=True) # currently only for vscode
self.debug_log_file = safe_get(ini, "DEBUG", "debug_log_file", default="debug.log")
self.debug_svg_file = safe_get(ini, "DEBUG", "debug_svg_file", default="debug.svg")
self.wait_attach = safe_get(ini, "DEBUG", "wait_attach", default=True) # currently only for vscode
if debug_type == 'none':
return
@ -107,11 +107,11 @@ class Debug(object):
# flake8: noqa: C901
def init_debugger(self):
# ### General debugging notes:
# 1. to enable debugging or profiling copy DEBUG_template.ini to DEBUG.ini and edit it
# 1. to enable debugging or profiling copy DEBUG_template.toml to DEBUG.toml and edit it
# ### How create bash script for offline debugging from console
# 1. in DEBUG.ini set create_bash_script = True
# 2. call inkstitch.py extension from inkscape to create bash script named by bash_file_base in DEBUG.ini
# 1. in DEBUG.toml set create_bash_script = true
# 2. call inkstitch.py extension from inkscape to create bash script named by bash_file_base in DEBUG.toml
# 3. run bash script from console
# ### Enable debugging
@ -119,7 +119,7 @@ class Debug(object):
# debug_type = vscode - 'debugpy' for vscode editor
# debug_type = pycharm - 'pydevd-pycharm' for pycharm editor
# debug_type = pydev - 'pydevd' for eclipse editor
# 2. set debug_enable = True in DEBUG.ini
# 2. set debug_enable = true in DEBUG.toml
# or use command line argument -d in bash script
# or set environment variable INKSTITCH_DEBUG_ENABLE = True or 1 or yes or y
@ -128,16 +128,16 @@ class Debug(object):
# profiler_type = cprofile - 'cProfile' profiler
# profiler_type = profile - 'profile' profiler
# profiler_type = pyinstrument- 'pyinstrument' profiler
# 2. set profile_enable = True in DEBUG.ini
# 2. set profile_enable = true in DEBUG.toml
# or use command line argument -p in bash script
# or set environment variable INKSTITCH_PROFILE_ENABLE = True or 1 or yes or y
# ### Miscelaneous notes:
# - to disable debugger when running from inkscape set disable_from_inkscape = True in DEBUG.ini
# - to write debug output to file set debug_to_file = True in DEBUG.ini
# - to change various output file names see DEBUG.ini
# - to disable waiting for debugger to attach (vscode editor) set wait_attach = False in DEBUG.ini
# - to prefer inkscape version of inkex module over pip version set prefer_pip_inkex = False in DEBUG.ini
# - to disable debugger when running from inkscape set disable_from_inkscape = true in DEBUG.toml
# - to write debug output to file set debug_to_file = true in DEBUG.toml
# - to change various output file names see DEBUG.toml
# - to disable waiting for debugger to attach (vscode editor) set wait_attach = false in DEBUG.toml
# - to prefer inkscape version of inkex module over pip version set prefer_pip_inkex = false in DEBUG.toml
# ###
@ -146,7 +146,7 @@ class Debug(object):
# 1. Install LiClipse (liclipse.com) -- no need to install Eclipse first
# 2. Start debug server as described here: http://www.pydev.org/manual_adv_remote_debugger.html
# * follow the "Note:" to enable the debug server menu item
# 3. Copy and edit a file named "DEBUG.ini" from "DEBUG_template.ini" next to inkstitch.py in your git clone
# 3. Copy and edit a file named "DEBUG.toml" from "DEBUG_template.toml" next to inkstitch.py in your git clone
# and set debug_type = pydev
# 4. Run any extension and PyDev will start debugging.
@ -173,7 +173,7 @@ class Debug(object):
# configuration. Set "IDE host name:" to "localhost" and "Port:" to 5678.
# You can leave the default settings for all other choices.
#
# 3. Touch a file named "DEBUG.ini" at the top of your git repo, as above
# 3. Touch a file named "DEBUG.toml" at the top of your git repo, as above
# set debug_type = pycharm
#
# 4. Create a symbolic link in the Inkscape extensions directory to the
@ -217,7 +217,7 @@ class Debug(object):
# }
# }
# ]
# 3. Touch a file named "DEBUG.ini" at the top of your git repo, as above
# 3. Touch a file named "DEBUG.toml" at the top of your git repo, as above
# set debug_type = vscode
# 4. Start the debug server in VS Code by clicking on the debug icon in the left pane
# select "Python: Attach" from the dropdown menu and click on the green arrow.

Wyświetl plik

@ -67,6 +67,8 @@
import logging
import warnings
from .debug_utils import safe_get # mimic get method of dict with default value
logger = logging.getLogger('inkstitch')
# example of logger configuration for release mode:
@ -152,17 +154,20 @@ def configure_logging(config, ini, SCRIPTDIR):
logging.captureWarnings(warnings_capture) # capture warnings to log file with level WARNING
warnings_action = config.get('warnings_action', 'default').lower()
warnings.simplefilter(warnings_action) # set action for warnings: 'error', 'ignore', 'always', ...
disable_logging = ini.getboolean("LOGGING", "disable_logging", fallback=False)
disable_logging = safe_get(ini, "LOGGING", "disable_logging", default=False)
if disable_logging:
logger.warning("Logging is disabled by configuration in ini file.")
logging.disable() # globally disable all logging of all loggers
# Evaluate filenames in logging configuration using myvars dictionary:
# Evaluate filenames in logging configuration using myvars dictionary argument.
# - for external configuration file (eg. LOGGING.toml) we cannot pass parameters such as the current directory.
# - we do that by replacing %(SCRIPTDIR)s -> script path in filenames
# - example of usage:
# "handlers": {
# "file": {
# "class": "logging.FileHandler",
# "filename": "%(SCRIPTDIR)s/xxx.log", # replace %(SCRIPTDIR)s -> script path
# "filename": "%(SCRIPTDIR)s/xxx.log", # <--- replace %(SCRIPTDIR)s -> script path
# }
# }
# config - logging configuration

Wyświetl plik

@ -6,23 +6,34 @@
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):
# 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
# example: safe_get({'a': {'b': 1}}, 'a', 'b') -> 1
# safe_get({'a': {'b': 1}}, 'a', 'c', default=2) -> 2
def safe_get(dictionary:dict, *keys, default=None):
for key in keys:
if key not in dictionary:
return default
dictionary = dictionary[key]
return dictionary
def write_offline_debug_script(debug_script_dir: Path, ini: dict):
'''
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
- ini - see DEBUG.toml
'''
# define names of files used by offline Bash script
bash_file_base = ini.get("DEBUG", "bash_file_base", fallback="debug_inkstitch")
bash_file_base = safe_get(ini, "DEBUG", "bash_file_base", default="debug_inkstitch")
bash_name = Path(bash_file_base).with_suffix(".sh") # Path object
bash_svg = Path(bash_file_base).with_suffix(".svg") # Path object
@ -147,18 +158,18 @@ def reorder_sys_path():
# -----------------------------------------------------------------------------
# try to resolve debugger type from ini file or cmd line of bash
def resolve_debug_type(ini: configparser.ConfigParser):
def resolve_debug_type(ini: dict):
# 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_enable = safe_get(ini, "DEBUG", "debug_enable", default=False) # enable debugger on startup from ini
debug_type = ini.get("DEBUG", "debug_type", fallback="none") # debugger type vscode, pycharm, pydevd
debug_type = safe_get(ini, "DEBUG", "debug_type", default="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
debug_to_file = safe_get(ini, "DEBUG", "debug_to_file", default=False) # write debug output to file
if debug_to_file and debug_type == 'none':
debug_type = 'file'
@ -166,15 +177,15 @@ def resolve_debug_type(ini: configparser.ConfigParser):
# try to resolve profiler type from ini file or cmd line of bash
def resolve_profile_type(ini: configparser.ConfigParser):
def resolve_profile_type(ini: dict):
# 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
profile_enable = safe_get(ini, "PROFILE", "profile_enable", default=False) # read from ini
# specify profiler type
profiler_type = ini.get("PROFILE", "profiler_type", fallback="none") # profiler type cprofile, profile, pyinstrument
profiler_type = safe_get(ini, "PROFILE", "profiler_type", default="none") # profiler type cprofile, profile, pyinstrument
if not profile_enable:
profiler_type = 'none'
@ -189,11 +200,11 @@ def resolve_profile_type(ini: configparser.ConfigParser):
# - pyinstrument - profiler with nice html output
def profile(profiler_type, profile_dir: Path, ini: configparser.ConfigParser, extension, remaining_args):
def profile(profiler_type, profile_dir: Path, ini: dict, extension, remaining_args):
'''
profile with cProfile, profile or pyinstrument
'''
profile_file_base = ini.get("PROFILE", "profile_file_base", fallback="debug_profile")
profile_file_base = safe_get(ini, "PROFILE", "profile_file_base", default="debug_profile")
profile_file_path = profile_dir / profile_file_base # Path object
if profiler_type == 'cprofile':