From b6f8c142d4ea6491ffedaae63b1a6ae083fe7ea7 Mon Sep 17 00:00:00 2001 From: Quintijn Hoogenboom Date: Sun, 28 Apr 2024 14:59:53 +0200 Subject: [PATCH 01/25] minor adjustment natlinkstatus.py --- src/natlinkcore/natlinkstatus.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/natlinkcore/natlinkstatus.py b/src/natlinkcore/natlinkstatus.py index dfffe41..c980770 100644 --- a/src/natlinkcore/natlinkstatus.py +++ b/src/natlinkcore/natlinkstatus.py @@ -604,6 +604,7 @@ def getVocolaGrammarsDirectory(self): key = 'vocolagrammarsdirectory' value = self.natlinkmain.getconfigsetting(section='directories', option=key) if not value: + self.VocolaGrammarsDirectory = "" return "" voc_grammars_dir = natlinkcore.config.expand_path(value) self.VocolaGrammarsDirectory = voc_grammars_dir From d2bbd17179b30940077b83bf0a9c680256cebca4 Mon Sep 17 00:00:00 2001 From: Quintijn Hoogenboom Date: Sun, 28 Apr 2024 18:32:26 +0200 Subject: [PATCH 02/25] working on convert NATLINK_USERDIR to NATLINK_SETTINGSDIR (environment variable) --- src/natlinkcore/config.py | 30 ++++++++++++- src/natlinkcore/loader.py | 90 ++++++++++++++++++++++----------------- 2 files changed, 80 insertions(+), 40 deletions(-) diff --git a/src/natlinkcore/config.py b/src/natlinkcore/config.py index 3ac4aff..b5bb8ba 100644 --- a/src/natlinkcore/config.py +++ b/src/natlinkcore/config.py @@ -144,7 +144,9 @@ def expand_path(input_path: str) -> str: Paths can be: - the name of a python package, or a sub directory of a python package - - natlink_userdir/...: the directory where natlink.ini is is searched for, either %(NATLINK_USERDIR) or ~/.natlink + - Obsolete: natlink_userdir/...: the directory where natlink.ini is is searched for, either %(NATLINK_USERDIR) or ~/.natlink + - ~/...: the home directory + - Now: natlink_settingsdir/...: the directory where natlink.ini is is searched for, either %(NATLINK_SETTINGSDIR) or ~/.natlink - ~/...: the home directory - some environment variable: this environment variable is expanded. @@ -168,6 +170,7 @@ def expand_path(input_path: str) -> str: # print(f'expand_path: "{input_path}" include "~": expanded: "{env_expanded}"') return normpath(env_expanded) + ## "natlink_userdir" will go obsolete, to be replaced with "natlink_settingsdir" below: if input_path.startswith('natlink_userdir/') or input_path.startswith('natlink_userdir\\'): nud = expand_natlink_userdir() if isdir(nud): @@ -179,6 +182,18 @@ def expand_path(input_path: str) -> str: return dir_path print(f'natlink_userdir does not expand to a valid directory: "{nud}"') return normpath(nud) + + if input_path.startswith('natlink_settingsdir/') or input_path.startswith('natlink_settingsdir\\'): + nsd = expand_natlink_settingsdir() + if isdir(nsd): + dir_path = input_path.replace('natlink_settingsdir', nsd) + dir_path = normpath(dir_path) + if isdir(dir_path): + return dir_path + print(f'no valid directory found with "natlink_settingsdir": "{dir_path}"') + return dir_path + print(f'natlink_settingsdir does not expand to a valid directory: "{nsd}"') + return normpath(nsd) # try if package: @@ -216,3 +231,16 @@ def expand_natlink_userdir(): if not nud.endswith('.natlink'): raise ValueError(f'expand_natlink_userdir: directory "{nud}" should end with ".natlink"\n\tprobably you did not set the windows environment variable "NATLINK_USERDIR" incorrect, let it end with ".natlink".\n\tNote: if this ".natlink" directory does not exist yet, it will be created there.') return nud + +def expand_natlink_settingsdir(): + """not with envvariables, but special: + + if NATLINK_SETTINGsDIR is set: return this, but... it should end with ".natlink" + if NATLINK_SETTINGSDIR is NOT set: return Path.home()/'.natlink' + """ + normpath = os.path.normpath + nsd = os.getenv('natlink_settingsdir') or str(Path.home()/'.natlink') + nsd = normpath(expand_path(nsd)) + if not nsd.endswith('.natlink'): + raise ValueError(f'expand_natlink_settingsdir: directory "{nsd}" should end with ".natlink"\n\tprobably you did not set the windows environment variable "NATLINK_SETTINGSDIR" incorrect, let it end with ".natlink".\n\tNote: if this ".natlink" directory does not exist yet, it will be created there.') + return nsd diff --git a/src/natlinkcore/loader.py b/src/natlinkcore/loader.py index fe51e41..5071422 100644 --- a/src/natlinkcore/loader.py +++ b/src/natlinkcore/loader.py @@ -1,13 +1,11 @@ -#pylint:disable=C0114, C0115, C0116, R1705, R0902, R0904, R0911, R0912, R0915, W0703, E1101 +#pylint:disable=C0114, C0115, C0116, R1705, R0902, R0904, R0911, R0912, R0915, W0703, E1101, W1203 import importlib import importlib.machinery import importlib.util import logging -from pydebugstring import outputDebugString,OutputDebugStringHandler import os import copy import sys -import sys import time import traceback import winreg @@ -15,6 +13,7 @@ from pathlib import Path from types import ModuleType from typing import List, Dict, Set, Iterable, Any, Tuple, Callable +from pydebugstring import outputDebugString,OutputDebugStringHandler import debugpy import natlink @@ -621,49 +620,62 @@ def config_locations() -> Iterable[str]: fallback_config_file = join(get_natlinkcore_dirname(), "DefaultConfig", natlink_inifile) if not isfile(fallback_config_file): raise OSError(f'fallback_config_file does not exist: "{fallback_config_file}"') - # try NATLINKUSERDIR setting: - natlink_userdir_from_env = getenv("NATLINK_USERDIR") - if natlink_userdir_from_env: - nl_user_dir = expand_path(natlink_userdir_from_env) - nl_user_file = join(nl_user_dir, natlink_inifile) - return [nl_user_file, fallback_config_file] + # try NATLINK_USERDIR setting (obsolete) and NATLINK_SETTINGSDIR (new): + natlink_settingsdir_from_env = getenv("NATLINK_SETTINGSDIR") + natlink_userdir_from_env_obsolete = getenv("NATLINK_USERDIR") + if natlink_userdir_from_env_obsolete: + if natlink_settingsdir_from_env and natlink_userdir_from_env_obsolete: + pass + elif natlink_settingsdir_from_env: + logging.warning('You defined env variable "NATLINK_SETTINGSDIR", but different from the obsolete env variable "NATLINK_USERDIR"...') + logging.warning('"NATLINK_SETTINGSDIR (valid): "%s"', natlink_settingsdir_from_env) + logging.warning('"NATLINK_USERDIR (obsolete): "%s"', natlink_userdir_from_env_obsolete) + else: + ## natlink_settingsdir_from_env is not set, but natlink_userdir_from_env_obsolete IS + logging.warning('You have set env variable "NATLINK_USERDIR", but this variable is obsolete.') + logging.warning('Please specify the env variable "NATLINK_SETTINGSDIR" to "%s", and restart Dragon', natlink_userdir_from_env_obsolete) + + if natlink_settingsdir_from_env: + nl_settings_dir = expand_path(natlink_settingsdir_from_env) + nl_settings_file = join(nl_settings_dir, natlink_inifile) + return [nl_settings_file, fallback_config_file] # choose between .natlink/natlink.ini in home or the fallback_directory: return [join(home, config_sub_dir, natlink_inifile), fallback_config_file] def startDap(config : NatlinkConfig) -> bool: - """ - Starts DAP (Debug Adapter Protocol) if there a DAP port specified in the config object. - returns True if the dap was started. + """ + Starts DAP (Debug Adapter Protocol) if there a DAP port specified in the config object. + returns True if the dap was started. - Natlink will startDap automatically if configured in the run method below. - If you need to start the DAP sooner, edit your code to make a call to startDap. - Similarly, if you want to start the DAP later, call startDap. You can call it from your grammar or - anywhere else. - """ + Natlink will startDap automatically if configured in the run method below. + If you need to start the DAP sooner, edit your code to make a call to startDap. + Similarly, if you want to start the DAP later, call startDap. You can call it from your grammar or + anywhere else. + """ - dap_started=False - logging.debug(f"testing dap , enabled {config.dap_enabled} port {config.dap_port}") - try: - logging.debug("Debugpy.configure ...") - debugpy.configure(python=f"{python_exec}") - logging.debug("Debugpy.listen ...") - - debugpy.listen(config.dap_port) - dap_started=True - - logging.debug(f"DAP Started on Port {config.dap_port} in {__file__}") - if config.dap_wait_for_debugger_attach_on_startup: - #use info level logging, the user will need to know as natlink and dragon will hang here. - #unti debuger is attached. - logging.info(f"waiting for debugger to attach using DAP in {__file__} ") - debugpy.wait_for_client() - return dap_started - - except Exception as ee: - logging.info(f""" - Exception {ee} while starting DAP in {__file__}. Possible cause is incorrect python executable specified {python_exec} - """ ) + dap_started=False + logging.debug(f"testing dap , enabled {config.dap_enabled} port {config.dap_port}") + try: + logging.debug("Debugpy.configure ...") + debugpy.configure(python=f"{python_exec}") + logging.debug("Debugpy.listen ...") + + debugpy.listen(config.dap_port) + dap_started=True + + logging.debug(f"DAP Started on Port {config.dap_port} in {__file__}") + if config.dap_wait_for_debugger_attach_on_startup: + #use info level logging, the user will need to know as natlink and dragon will hang here. + #unti debuger is attached. + logging.info(f"waiting for debugger to attach using DAP in {__file__} ") + debugpy.wait_for_client() + return dap_started + + except Exception as ee: + logging.info(f""" + Exception {ee} while starting DAP in {__file__}. Possible cause is incorrect python executable specified {python_exec} + """ ) def run() -> None: From 2b09ef9c0216427e86ae59ea31321d23d0594fd6 Mon Sep 17 00:00:00 2001 From: Quintijn Hoogenboom Date: Wed, 1 May 2024 15:01:34 +0200 Subject: [PATCH 03/25] loader.py anticipating on change from NATLINK_USERDIR to NATLINK_SETTINGSDIR --- src/natlinkcore/loader.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/natlinkcore/loader.py b/src/natlinkcore/loader.py index 5071422..5b8c87b 100644 --- a/src/natlinkcore/loader.py +++ b/src/natlinkcore/loader.py @@ -603,10 +603,15 @@ def get_config_info_from_registry(key_name: str) -> str: result, _ = winreg.QueryValueEx(natlink_key, key_name) return result + +msg_error = False +msg_warning = False + def config_locations() -> Iterable[str]: """give two possible locations, the wanted and the "fallback" location - wanted: in the '.natlink' subdirectory of `home` or in "NATLINK_USERDIR". + wanted: in the '.natlink' subdirectory of `home` or in "NATLINK_USERDIR", this variable is + going to be replaced by "NATLINK_SETTINGSDIR". name is always 'natlink.ini' the fallback location is in the installed files, and provides the frame for the config file. @@ -623,6 +628,7 @@ def config_locations() -> Iterable[str]: # try NATLINK_USERDIR setting (obsolete) and NATLINK_SETTINGSDIR (new): natlink_settingsdir_from_env = getenv("NATLINK_SETTINGSDIR") natlink_userdir_from_env_obsolete = getenv("NATLINK_USERDIR") + ## issue warnings if old setting is still there and conflicts with new setting: if natlink_userdir_from_env_obsolete: if natlink_settingsdir_from_env and natlink_userdir_from_env_obsolete: pass From 51e161326057cbcbb677c13b4b7c7a0a71adbcd2 Mon Sep 17 00:00:00 2001 From: Quintijn Hoogenboom Date: Wed, 1 May 2024 17:07:06 +0200 Subject: [PATCH 04/25] changing in loader check for and in natlinkconfigfunctions change from NATLINK_USERDIR into NATLINK_SETTINGSDIR. Must be tested, but seems to work all right.... --- .../configure/natlinkconfigfunctions.py | 17 ++++++++++++++- src/natlinkcore/loader.py | 21 ++++++++++++------- 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/src/natlinkcore/configure/natlinkconfigfunctions.py b/src/natlinkcore/configure/natlinkconfigfunctions.py index e1b2e81..b2f524e 100644 --- a/src/natlinkcore/configure/natlinkconfigfunctions.py +++ b/src/natlinkcore/configure/natlinkconfigfunctions.py @@ -69,6 +69,7 @@ def __init__(self): self.natlinkconfig_path = config.expand_natlink_userdir() def get_check_config_locations(self): + """check the location/locations as given by the loader """ config_path, fallback_path = loader.config_locations() @@ -84,6 +85,20 @@ def check_config(self): """check config_file for possibly unwanted settings """ self.config_remove(section='directories', option='default_config') + + # change default unimacrogrammarsdirectory: + section = 'directories' + option = 'unimacrogrammarsdirectory' + old_prefix = 'natlink_user' + new_prefix = 'unimacro' + value = self.Config[section][option] + if value and value.find('natlink_user') == 0: + value = value.replace(old_prefix,new_prefix) + self.config_set(section, option, value) + logging.info(f'changed in "natlink.ini", section "directories", unimacro setting "{option}" to value: "{value}"') + pass + # for key, value in self.Config[section].items(): + # print(f'key: {key}, value: {value}') def getConfig(self): """return the config instance @@ -309,7 +324,7 @@ def enable_unimacro(self, arg): unimacro_user_dir = self.config_get('unimacro', 'unimacrouserdirectory') if not unimacro_user_dir: return - uniGrammarsDir = r'natlink_userdir\unimacrogrammars' + uniGrammarsDir = r'unimacro\unimacrogrammars' self.setDirectory('unimacrodirectory','unimacro') #always unimacro self.setDirectory('unimacrogrammarsdirectory', uniGrammarsDir) diff --git a/src/natlinkcore/loader.py b/src/natlinkcore/loader.py index 5b8c87b..172e1a3 100644 --- a/src/natlinkcore/loader.py +++ b/src/natlinkcore/loader.py @@ -604,8 +604,8 @@ def get_config_info_from_registry(key_name: str) -> str: return result -msg_error = False -msg_warning = False +had_msg_error = False +had_msg_warning = False def config_locations() -> Iterable[str]: """give two possible locations, the wanted and the "fallback" location @@ -618,6 +618,7 @@ def config_locations() -> Iterable[str]: with the configurenatlink (natlinkconfigfunction.py or configfurenatlink.pyw) the fallback version of the config file is copied into the wanted location. """ + global had_msg_warning, had_msg_error join, expanduser, getenv, isfile = os.path.join, os.path.expanduser, os.getenv, os.path.isfile home = expanduser('~') config_sub_dir = '.natlink' @@ -633,14 +634,18 @@ def config_locations() -> Iterable[str]: if natlink_settingsdir_from_env and natlink_userdir_from_env_obsolete: pass elif natlink_settingsdir_from_env: - logging.warning('You defined env variable "NATLINK_SETTINGSDIR", but different from the obsolete env variable "NATLINK_USERDIR"...') - logging.warning('"NATLINK_SETTINGSDIR (valid): "%s"', natlink_settingsdir_from_env) - logging.warning('"NATLINK_USERDIR (obsolete): "%s"', natlink_userdir_from_env_obsolete) + if not had_msg_error: + logging.warning('You defined env variable "NATLINK_SETTINGSDIR", but different from the obsolete env variable "NATLINK_USERDIR"...') + logging.warning('"NATLINK_SETTINGSDIR (valid): "%s"', natlink_settingsdir_from_env) + logging.warning('"NATLINK_USERDIR (obsolete): "%s"', natlink_userdir_from_env_obsolete) + had_msg_error = True else: ## natlink_settingsdir_from_env is not set, but natlink_userdir_from_env_obsolete IS - logging.warning('You have set env variable "NATLINK_USERDIR", but this variable is obsolete.') - logging.warning('Please specify the env variable "NATLINK_SETTINGSDIR" to "%s", and restart Dragon', natlink_userdir_from_env_obsolete) - + if not had_msg_warning: + logging.warning('You have set env variable "NATLINK_USERDIR", but this variable is obsolete.') + logging.warning('Please specify the env variable "NATLINK_SETTINGSDIR" to "%s", and restart Dragon', natlink_userdir_from_env_obsolete) + had_msg_warning = True + if natlink_settingsdir_from_env: nl_settings_dir = expand_path(natlink_settingsdir_from_env) nl_settings_file = join(nl_settings_dir, natlink_inifile) From 1c86f1a1ed59a490c0d25b6b2a4c8ed5b9fbb437 Mon Sep 17 00:00:00 2001 From: Quintijn Hoogenboom Date: Wed, 1 May 2024 17:33:27 +0200 Subject: [PATCH 05/25] some tidying up things --- src/natlinkcore/config.py | 6 ++-- .../configure/natlinkconfig_cli.py | 10 ++++--- .../configure/natlinkconfigfunctions.py | 28 +++++++++++++------ 3 files changed, 28 insertions(+), 16 deletions(-) diff --git a/src/natlinkcore/config.py b/src/natlinkcore/config.py index b5bb8ba..c804bc9 100644 --- a/src/natlinkcore/config.py +++ b/src/natlinkcore/config.py @@ -172,7 +172,7 @@ def expand_path(input_path: str) -> str: ## "natlink_userdir" will go obsolete, to be replaced with "natlink_settingsdir" below: if input_path.startswith('natlink_userdir/') or input_path.startswith('natlink_userdir\\'): - nud = expand_natlink_userdir() + nud = expand_natlink_settingsdir() if isdir(nud): dir_path = input_path.replace('natlink_userdir', nud) dir_path = normpath(dir_path) @@ -219,7 +219,7 @@ def expand_path(input_path: str) -> str: # print(f'env_expanded: "{env_expanded}", from envvar: "{input_path}"') return normpath(env_expanded) -def expand_natlink_userdir(): +def expand_natlink_settingsdir(): """not with envvariables, but special: if NATLINK_USERDIR is set: return this, but... it should end with ".natlink" @@ -229,7 +229,7 @@ def expand_natlink_userdir(): nud = os.getenv('natlink_userdir') or str(Path.home()/'.natlink') nud = normpath(expand_path(nud)) if not nud.endswith('.natlink'): - raise ValueError(f'expand_natlink_userdir: directory "{nud}" should end with ".natlink"\n\tprobably you did not set the windows environment variable "NATLINK_USERDIR" incorrect, let it end with ".natlink".\n\tNote: if this ".natlink" directory does not exist yet, it will be created there.') + raise ValueError(f'expand_natlink_settingsdir: directory "{nud}" should end with ".natlink"\n\tprobably you did not set the windows environment variable "NATLINK_USERDIR" incorrect, let it end with ".natlink".\n\tNote: if this ".natlink" directory does not exist yet, it will be created there.') return nud def expand_natlink_settingsdir(): diff --git a/src/natlinkcore/configure/natlinkconfig_cli.py b/src/natlinkcore/configure/natlinkconfig_cli.py index 9d3a44b..559f633 100644 --- a/src/natlinkcore/configure/natlinkconfig_cli.py +++ b/src/natlinkcore/configure/natlinkconfig_cli.py @@ -4,14 +4,16 @@ import cmd import os import os.path -from natlinkcore.configure import extensions_and_folders -from platformdirs import user_log_dir +import logging from pathlib import Path +from natlinkcore.configure import extensions_and_folders from natlinkcore.configure import natlinkconfigfunctions -import logging +from platformdirs import user_log_dir + + appname="natlink" logdir = Path(user_log_dir(appname=appname,ensure_exists=True)) -logfilename=logdir/f"cli_log.txt" +logfilename=logdir/"cli_log.txt" file_handler = logging.FileHandler(logfilename) formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') file_handler.setFormatter(formatter) diff --git a/src/natlinkcore/configure/natlinkconfigfunctions.py b/src/natlinkcore/configure/natlinkconfigfunctions.py index b2f524e..b831926 100644 --- a/src/natlinkcore/configure/natlinkconfigfunctions.py +++ b/src/natlinkcore/configure/natlinkconfigfunctions.py @@ -8,7 +8,7 @@ # Quintijn Hoogenboom, January 2008 (...), August 2022 # -#pylint:disable=C0302, W0702, R0904, C0116, W0613, R0914, R0912, R1732, W1514, W0107 +#pylint:disable=C0302, W0702, R0904, C0116, W0613, R0914, R0912, R1732, W1514, W0107, W1203 """With the functions in this module Natlink can be configured. These functions are called in different ways: @@ -23,6 +23,7 @@ from pprint import pformat from pathlib import Path import configparser +import logging from natlinkcore import natlinkstatus from natlinkcore import config @@ -30,8 +31,6 @@ from natlinkcore import readwritefile from natlinkcore import tkinter_dialogs -import logging - isfile, isdir, join = os.path.isfile, os.path.isdir, os.path.join @@ -66,7 +65,8 @@ def __init__(self): # for convenience in other places: self.home_path = str(Path.home()) self.documents_path = str(Path.home()/'Documents') - self.natlinkconfig_path = config.expand_natlink_userdir() + self.natlinkconfig_path = config.expand_natlink_settingsdir() + pass def get_check_config_locations(self): @@ -97,6 +97,16 @@ def check_config(self): self.config_set(section, option, value) logging.info(f'changed in "natlink.ini", section "directories", unimacro setting "{option}" to value: "{value}"') pass + + if loader.had_msg_error: + logging.error('The environment variable "NATLINK_USERDIR" has been changed to "NATLINK_SETTINGSDIR" by the user, but has a conclicting value') + logging.error('Please remove "NATLINK_USERDIR", in the windows environment variables, dialog User variables, and restart your program') + + if loader.had_msg_warning: + logging.error('The key of the environment variable "NATLINK_USERDIR" should be changed to "NATLINK_SETTINGSDIR"') + logging.error('You can do so in "windows environment variables", dialog "User variables". Then your program') + + # for key, value in self.Config[section].items(): # print(f'key: {key}, value: {value}') @@ -435,16 +445,16 @@ def copyUnimacroIncludeFile(self): toFolder = Path(self.status.getVocolaUserDirectory()) if not unimacroDir.is_dir(): mess = f'copyUnimacroIncludeFile: unimacroDir "{str(unimacroDir)}" is not a directory' - logging.warn(mess) + logging.warning(mess) return fromFile = fromFolder/uscFile if not fromFile.is_file(): mess = f'copyUnimacroIncludeFile: file "{str(fromFile)}" does not exist (is not a valid file)' - logging.warn(mess) + logging.warning(mess) return if not toFolder.is_dir(): mess = f'copyUnimacroIncludeFile: vocolaUserDirectory does not exist "{str(toFolder)}" (is not a directory)' - logging.warn(mess) + logging.warning(mess) return toFile = toFolder/uscFile @@ -460,7 +470,7 @@ def copyUnimacroIncludeFile(self): logging.info(f'copied "{uscFile}" from "{str(fromFolder)}" to "{str(toFolder)}"') except: mess = f'Could not copy new version of "{uscFile}", from "{str(fromFolder)}" to "{str(toFolder)}"' - logging.warn(mess) + logging.warning(mess) return return @@ -473,7 +483,7 @@ def removeUnimacroIncludeFile(self): toFolder = Path(self.status.getVocolaUserDirectory()) if not toFolder.is_dir(): mess = f'removeUnimacroIncludeFile: vocolaUserDirectory does not exist "{str(toFolder)}" (is not a directory)' - logging.warn(mess) + logging.warning(mess) return toFile = toFolder/uscFile From b88dcae2505a56eecfc57a074b743b8ebd04e34e Mon Sep 17 00:00:00 2001 From: Quintijn Hoogenboom Date: Wed, 1 May 2024 19:15:27 +0200 Subject: [PATCH 06/25] bump to (release) 5.3.11 --- src/natlinkcore/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/natlinkcore/__init__.py b/src/natlinkcore/__init__.py index 7953869..9cafd48 100644 --- a/src/natlinkcore/__init__.py +++ b/src/natlinkcore/__init__.py @@ -1,6 +1,6 @@ '''Python portion of Natlink, a compatibility module for Dragon Naturally Speaking The python stuff including test modules''' -__version__="5.3.10" +__version__="5.3.11" #pylint:disable= from pathlib import Path From 0e2ecff66c0c49db6948e7fcf4ae48c679390ad7 Mon Sep 17 00:00:00 2001 From: Quintijn Hoogenboom Date: Thu, 2 May 2024 11:49:49 +0200 Subject: [PATCH 07/25] remove natlink from the dependencies of natlinkcore... update dtactions dependency --- pyproject.toml | 4 ++-- src/natlinkcore/__init__.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 3d59cd2..61c2716 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,10 +9,10 @@ dynamic = ["version", "description"] requires-python = ">=3.9" readme = "readme.md" dependencies= [ - "natlink>=5.3.4", +## "natlink>=5.3.4", "pysimplegui>=4.60.3", "pydebugstring >= 1.0.0.1", - "dtactions>=1.5.7", + "dtactions>=1.6.1", "platformdirs >= 4.2.0" ] classifiers=[ diff --git a/src/natlinkcore/__init__.py b/src/natlinkcore/__init__.py index 9cafd48..71f1259 100644 --- a/src/natlinkcore/__init__.py +++ b/src/natlinkcore/__init__.py @@ -1,6 +1,6 @@ '''Python portion of Natlink, a compatibility module for Dragon Naturally Speaking The python stuff including test modules''' -__version__="5.3.11" +__version__="5.3.12" #pylint:disable= from pathlib import Path From 118df97669485f7b3d24c9f945ddd7602cb5dae2 Mon Sep 17 00:00:00 2001 From: Quintijn Hoogenboom Date: Mon, 10 Jun 2024 12:31:14 +0200 Subject: [PATCH 08/25] checking edge cases of configuration files --- src/natlinkcore/config.py | 11 +++-- .../configure/natlinkconfig_cli.py | 11 +++-- .../configure/natlinkconfigfunctions.py | 43 ++++++++++++++----- src/natlinkcore/loader.py | 4 +- src/natlinkcore/natlinkstatus.py | 2 + 5 files changed, 53 insertions(+), 18 deletions(-) diff --git a/src/natlinkcore/config.py b/src/natlinkcore/config.py index c804bc9..2ecb69f 100644 --- a/src/natlinkcore/config.py +++ b/src/natlinkcore/config.py @@ -133,8 +133,13 @@ def from_first_found_file(cls, files: Iterable[str]) -> 'NatlinkConfig': for fn in files: if not isfile(fn): continue - if config.read(fn): - return cls.from_config_parser(config, config_path=fn) + try: + if config.read(fn): + return cls.from_config_parser(config, config_path=fn) + except Exception as exc: + mess = 'Error reading config file, %s\nPlease try to correct'% exc + os.startfile(fn) + raise OSError(mess) from exc # should not happen, because of DefaultConfig (was InstallTest) raise NoGoodConfigFoundException('No natlink config file found, please run configure natlink program\n\t(***configurenatlink***)') @@ -235,7 +240,7 @@ def expand_natlink_settingsdir(): def expand_natlink_settingsdir(): """not with envvariables, but special: - if NATLINK_SETTINGsDIR is set: return this, but... it should end with ".natlink" + if NATLINK_SETTINGSDIR is set: return this, but... it should end with ".natlink" if NATLINK_SETTINGSDIR is NOT set: return Path.home()/'.natlink' """ normpath = os.path.normpath diff --git a/src/natlinkcore/configure/natlinkconfig_cli.py b/src/natlinkcore/configure/natlinkconfig_cli.py index 559f633..5182ccb 100644 --- a/src/natlinkcore/configure/natlinkconfig_cli.py +++ b/src/natlinkcore/configure/natlinkconfig_cli.py @@ -5,6 +5,7 @@ import os import os.path import logging +import configparser from pathlib import Path from natlinkcore.configure import extensions_and_folders from natlinkcore.configure import natlinkconfigfunctions @@ -165,9 +166,13 @@ def usage(self): # info---------------------------------------------------------- def do_i(self, arg): self.Config.status.__init__() - S = self.Config.status.getNatlinkStatusString() - S = S + '\n\nIf you changed things, you must restart Dragon' - print(S) + try: + S = self.Config.status.getNatlinkStatusString() + S = S + '\n\nIf you changed things, you must restart Dragon' + print(S) + except configparser.NoSectionError: + print('No directories specified (yet). \nPlease specify one or more directories that Natlink should visit for grammar files') + def do_I(self, arg): # inifile natlinkstatus.ini settings: self.Config.status.__init__() diff --git a/src/natlinkcore/configure/natlinkconfigfunctions.py b/src/natlinkcore/configure/natlinkconfigfunctions.py index b831926..03d6848 100644 --- a/src/natlinkcore/configure/natlinkconfigfunctions.py +++ b/src/natlinkcore/configure/natlinkconfigfunctions.py @@ -25,7 +25,10 @@ import configparser import logging -from natlinkcore import natlinkstatus +try: + from natlinkcore import natlinkstatus +except OSError: + print('error when starting natlinkconfigfunctions') from natlinkcore import config from natlinkcore import loader from natlinkcore import readwritefile @@ -84,18 +87,38 @@ def get_check_config_locations(self): def check_config(self): """check config_file for possibly unwanted settings """ + # ensure the [directories] section is present: + try: + sect = self.Config['directories'] + except KeyError: + self.Config.add_section('directories') + self.config_write() + + self.config_remove(section='directories', option='default_config') + # check for default options missing: + # ret = config.NatlinkConfig.get_default_config() + # for ret_sect in ret.sections(): + # if self.Config.has_section(ret_sect): + # continue + # for ret_opt in self.Config[section].keys(): + # ret_value = ret[ret_sect][ret_opt] + # print(f'fix default section/key: "ret_sect", "ret_opt" to "ret_value"') + # change default unimacrogrammarsdirectory: section = 'directories' option = 'unimacrogrammarsdirectory' old_prefix = 'natlink_user' new_prefix = 'unimacro' - value = self.Config[section][option] - if value and value.find('natlink_user') == 0: - value = value.replace(old_prefix,new_prefix) - self.config_set(section, option, value) - logging.info(f'changed in "natlink.ini", section "directories", unimacro setting "{option}" to value: "{value}"') + try: + value = self.Config[section][option] + if value and value.find('natlink_user') == 0: + value = value.replace(old_prefix,new_prefix) + self.config_set(section, option, value) + logging.info(f'changed in "natlink.ini", section "directories", unimacro setting "{option}" to value: "{value}"') + pass + except KeyError: pass if loader.had_msg_error: @@ -440,11 +463,11 @@ def copyUnimacroIncludeFile(self): """ uscFile = 'Unimacro.vch' # also remove usc.vch from VocolaUserDirectory - unimacroDir = Path(self.status.getUnimacroDirectory()) - fromFolder = Path(unimacroDir)/'Vocola_compatibility' + dtactionsDir = Path(self.status.getDtactionsDirectory()) + fromFolder = Path(dtactionsDir)/'Vocola_compatibility' toFolder = Path(self.status.getVocolaUserDirectory()) - if not unimacroDir.is_dir(): - mess = f'copyUnimacroIncludeFile: unimacroDir "{str(unimacroDir)}" is not a directory' + if not dtactionsDir.is_dir(): + mess = f'copyUnimacroIncludeFile: dtactionsDir "{str(dtactionsDir)}" is not a directory' logging.warning(mess) return fromFile = fromFolder/uscFile diff --git a/src/natlinkcore/loader.py b/src/natlinkcore/loader.py index 172e1a3..ad60f6b 100644 --- a/src/natlinkcore/loader.py +++ b/src/natlinkcore/loader.py @@ -506,10 +506,10 @@ def set_user_language(self, args: Any = None): if args: self.user, self.profile = args self.language = self.get_user_language(self.profile) - self.logger.debug(f'set_user_language, user: "{self.user}", profile: "{self.profile}", language: "{self.language}"') + # self.logger.debug(f'set_user_language, user: "{self.user}", profile: "{self.profile}", language: "{self.language}"') else: self.user, self.profile = '', '' - self.logger.warning('set_user_language, cannot get input for get_user_language, set to "enx",\n\tprobably Dragon is not running or you are preforming pytests') + # self.logger.warning('set_user_language, cannot get input for get_user_language, set to "enx",\n\tprobably Dragon is not running or you are preforming pytests') self.language = 'enx' def start(self) -> None: diff --git a/src/natlinkcore/natlinkstatus.py b/src/natlinkcore/natlinkstatus.py index c980770..7ee9755 100644 --- a/src/natlinkcore/natlinkstatus.py +++ b/src/natlinkcore/natlinkstatus.py @@ -435,6 +435,8 @@ def getUnimacroGrammarsDirectory(self): key = 'unimacrogrammarsdirectory' value = self.natlinkmain.getconfigsetting(section='directories', option=key) + if not value: + return "" um_grammars_dir = natlinkcore.config.expand_path(value) self.UnimacroGrammarsDirectory = um_grammars_dir From 381639fd6ded4bfe1404ed81442c520d17c40748 Mon Sep 17 00:00:00 2001 From: Quintijn Hoogenboom Date: Mon, 10 Jun 2024 16:32:54 +0200 Subject: [PATCH 09/25] improved some details, but foremost includeUnimacroVchLineInVocolaFiles and removeUnimacroVchLineInVocolaFiles, making them more stable. --- .../configure/natlinkconfigfunctions.py | 63 ++++++++++--------- 1 file changed, 35 insertions(+), 28 deletions(-) diff --git a/src/natlinkcore/configure/natlinkconfigfunctions.py b/src/natlinkcore/configure/natlinkconfigfunctions.py index 03d6848..b9a208b 100644 --- a/src/natlinkcore/configure/natlinkconfigfunctions.py +++ b/src/natlinkcore/configure/natlinkconfigfunctions.py @@ -518,7 +518,7 @@ def removeUnimacroIncludeFile(self): mess = f'copyUnimacroIncludeFile: Could not remove previous version of "{str(toFile)}"' logging.warning(mess) - def includeUnimacroVchLineInVocolaFiles(self, subDirectory=None): + def includeUnimacroVchLineInVocolaFiles(self, toFolder=None): """include the Unimacro wrapper support line into all Vocola command files as a side effect, set the variable for Unimacro in Vocola support: @@ -528,55 +528,66 @@ def includeUnimacroVchLineInVocolaFiles(self, subDirectory=None): oldUscFile = 'usc.vch' ## reInclude = re.compile(r'^include\s+.*unimacro.vch;$', re.MULTILINE) ## reOldInclude = re.compile(r'^include\s+.*usc.vch;$', re.MULTILINE) - + # also remove includes of usc.vch - toFolder = self.status.getVocolaUserDirectory() + vocUserDir = self.status.getVocolaUserDirectory() + toFolder = toFolder or vocUserDir + subDirectory = toFolder != vocUserDir if subDirectory: - toFolder = os.path.join(toFolder, subDirectory) includeLine = f'include ..\\{uscFile};\n' + oldIncludeLines = [f'include {oldUscFile};', + f'include ..\\{oldUscFile};', + f'include {uscFile};' + ] else: includeLine = f'include {uscFile};\n' - oldIncludeLines = [f'include {oldUscFile};', - f'include ..\\{oldUscFile};', - f'include {uscFile.lower()};', - f'include ..\\{uscFile.lower()};', - ] + oldIncludeLines = [f'include {oldUscFile};', + f'include ..\\{oldUscFile};', + f'include ..\\{uscFile};' + ] if not os.path.isdir(toFolder): - mess = f'cannot find Vocola command files directory, not a valid path: {toFolder}' + if subDirectory: + mess = f'cannot find Vocola command files in sub directory, not a valid path: {toFolder}' + else: + mess = f'cannot find Vocola command files in irectory, not a valid path: {toFolder}' logging.warning(mess) return mess + nFiles = 0 for f in os.listdir(toFolder): - F = os.path.join(toFolder, f) if f.endswith(".vcl"): + F = os.path.join(toFolder, f) changed = 0 correct = 0 Output = [] for line in open(F, 'r'): - if line.strip() == includeLine.strip(): + if line.strip().lower() == includeLine.strip().lower(): correct = 1 for oldLine in oldIncludeLines: - if line.strip() == oldLine: - changed = 1 + if line.strip().lower() == oldLine.lower(): + changed += 1 break else: Output.append(line) if changed or not correct: - # changes were made: + # print(f'{F}: wrong lines: {changed}, had correct line: {bool(correct)}') # changes were made: if not correct: + # print(f'\tinclude: "{includeLine.strip()}"') Output.insert(0, includeLine) open(F, 'w').write(''.join(Output)) nFiles += 1 - elif len(f) == 3 and os.path.isdir(F): + elif len(f) == 3: # subdirectory, recursive - self.includeUnimacroVchLineInVocolaFiles(F) + self.includeUnimacroVchLineInVocolaFiles(toFolder=os.path.join(toFolder, f)) mess = f'changed {nFiles} files in {toFolder}' logging.warning(mess) return True - def removeUnimacroVchLineInVocolaFiles(self, subDirectory=None): + def removeUnimacroVchLineInVocolaFiles(self, toFolder=None): """remove the Unimacro wrapper support line into all Vocola command files + + toFolder set with recursive calls... """ uscFile = 'Unimacro.vch' oldUscFile = 'usc.vch' @@ -584,9 +595,8 @@ def removeUnimacroVchLineInVocolaFiles(self, subDirectory=None): ## reOldInclude = re.compile(r'^include\s+.*usc.vch;$', re.MULTILINE) # also remove includes of usc.vch - if subDirectory: - # for recursive call language subfolders: - toFolder = subDirectory + if toFolder: + pass # for recursive call language subfolders: else: toFolder = self.status.getVocolaUserDirectory() @@ -596,9 +606,6 @@ def removeUnimacroVchLineInVocolaFiles(self, subDirectory=None): f'include ..\\{uscFile};', f'include ../{oldUscFile};', f'include ../{uscFile};', - f'include {uscFile.lower()};', - f'include ..\\{uscFile.lower()};', - f'include ../{uscFile.lower()};' ] @@ -614,7 +621,7 @@ def removeUnimacroVchLineInVocolaFiles(self, subDirectory=None): Output = [] for line in open(F, 'r'): for oldLine in oldIncludeLines: - if line.strip() == oldLine: + if line.strip().lower() == oldLine.lower(): changed = 1 break else: @@ -623,9 +630,9 @@ def removeUnimacroVchLineInVocolaFiles(self, subDirectory=None): # had break, so changes were made: open(F, 'w').write(''.join(Output)) nFiles += 1 - elif len(f) == 3 and os.path.isdir(F): - self.removeUnimacroVchLineInVocolaFiles(F) - self.disableVocolaTakesUnimacroActions() + elif len(f) == 3: + self.removeUnimacroVchLineInVocolaFiles(toFolder=os.path.join(toFolder, f)) + # self.disableVocolaTakesUnimacroActions() mess = f'removed include lines from {nFiles} files in {toFolder}' logging.warning(mess) From 66afc9f5a6dec8996be356142073365809a47a88 Mon Sep 17 00:00:00 2001 From: Doug Ransom Date: Thu, 29 Feb 2024 13:10:26 -0800 Subject: [PATCH 10/25] added entry point for loggers --- pyproject.toml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 163d7f1..c852637 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,7 +9,7 @@ dynamic = ["version", "description"] requires-python = ">=3.9" readme = "readme.md" dependencies= [ -## "natlink>=5.3.4", + "natlink>=5.3.4", "FreeSimpleGUI>=5.1.0", "pydebugstring >= 1.0.0.1", "dtactions>=1.6.1", @@ -59,6 +59,9 @@ natlinkconfig_gui = "natlinkcore.configure.natlinkconfig_gui:main_gui" [project.entry-points."dt.loggers"] natlink ="natlinkcore:logname" +[project.entry-points."natlink.loggers"] + natlink ="natlinkcore:logname" + [project.entry-points."natlink.extensions"] natlink_sample_macros = "natlinkcore.SampleMacros:locateme" From adb8c360eb9fcd8b1e937468de2c7008d13cddf0 Mon Sep 17 00:00:00 2001 From: Doug Ransom Date: Sat, 2 Mar 2024 06:27:10 -0800 Subject: [PATCH 11/25] added build in the dev tools. changed entry points group for loggers to dt.loggers --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index c852637..db00af3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -59,7 +59,7 @@ natlinkconfig_gui = "natlinkcore.configure.natlinkconfig_gui:main_gui" [project.entry-points."dt.loggers"] natlink ="natlinkcore:logname" -[project.entry-points."natlink.loggers"] +[project.entry-points."dt.loggers"] natlink ="natlinkcore:logname" [project.entry-points."natlink.extensions"] From 47c0a3eb694844148451fa3ab0cb55de6b61c335 Mon Sep 17 00:00:00 2001 From: Quintijn Hoogenboom Date: Mon, 10 Jun 2024 12:31:14 +0200 Subject: [PATCH 12/25] checking edge cases of configuration files --- src/natlinkcore/config.py | 11 +++-- .../configure/natlinkconfig_cli.py | 11 +++-- .../configure/natlinkconfigfunctions.py | 43 ++++++++++++++----- src/natlinkcore/loader.py | 4 +- src/natlinkcore/natlinkstatus.py | 2 + 5 files changed, 53 insertions(+), 18 deletions(-) diff --git a/src/natlinkcore/config.py b/src/natlinkcore/config.py index c804bc9..2ecb69f 100644 --- a/src/natlinkcore/config.py +++ b/src/natlinkcore/config.py @@ -133,8 +133,13 @@ def from_first_found_file(cls, files: Iterable[str]) -> 'NatlinkConfig': for fn in files: if not isfile(fn): continue - if config.read(fn): - return cls.from_config_parser(config, config_path=fn) + try: + if config.read(fn): + return cls.from_config_parser(config, config_path=fn) + except Exception as exc: + mess = 'Error reading config file, %s\nPlease try to correct'% exc + os.startfile(fn) + raise OSError(mess) from exc # should not happen, because of DefaultConfig (was InstallTest) raise NoGoodConfigFoundException('No natlink config file found, please run configure natlink program\n\t(***configurenatlink***)') @@ -235,7 +240,7 @@ def expand_natlink_settingsdir(): def expand_natlink_settingsdir(): """not with envvariables, but special: - if NATLINK_SETTINGsDIR is set: return this, but... it should end with ".natlink" + if NATLINK_SETTINGSDIR is set: return this, but... it should end with ".natlink" if NATLINK_SETTINGSDIR is NOT set: return Path.home()/'.natlink' """ normpath = os.path.normpath diff --git a/src/natlinkcore/configure/natlinkconfig_cli.py b/src/natlinkcore/configure/natlinkconfig_cli.py index 559f633..5182ccb 100644 --- a/src/natlinkcore/configure/natlinkconfig_cli.py +++ b/src/natlinkcore/configure/natlinkconfig_cli.py @@ -5,6 +5,7 @@ import os import os.path import logging +import configparser from pathlib import Path from natlinkcore.configure import extensions_and_folders from natlinkcore.configure import natlinkconfigfunctions @@ -165,9 +166,13 @@ def usage(self): # info---------------------------------------------------------- def do_i(self, arg): self.Config.status.__init__() - S = self.Config.status.getNatlinkStatusString() - S = S + '\n\nIf you changed things, you must restart Dragon' - print(S) + try: + S = self.Config.status.getNatlinkStatusString() + S = S + '\n\nIf you changed things, you must restart Dragon' + print(S) + except configparser.NoSectionError: + print('No directories specified (yet). \nPlease specify one or more directories that Natlink should visit for grammar files') + def do_I(self, arg): # inifile natlinkstatus.ini settings: self.Config.status.__init__() diff --git a/src/natlinkcore/configure/natlinkconfigfunctions.py b/src/natlinkcore/configure/natlinkconfigfunctions.py index b831926..03d6848 100644 --- a/src/natlinkcore/configure/natlinkconfigfunctions.py +++ b/src/natlinkcore/configure/natlinkconfigfunctions.py @@ -25,7 +25,10 @@ import configparser import logging -from natlinkcore import natlinkstatus +try: + from natlinkcore import natlinkstatus +except OSError: + print('error when starting natlinkconfigfunctions') from natlinkcore import config from natlinkcore import loader from natlinkcore import readwritefile @@ -84,18 +87,38 @@ def get_check_config_locations(self): def check_config(self): """check config_file for possibly unwanted settings """ + # ensure the [directories] section is present: + try: + sect = self.Config['directories'] + except KeyError: + self.Config.add_section('directories') + self.config_write() + + self.config_remove(section='directories', option='default_config') + # check for default options missing: + # ret = config.NatlinkConfig.get_default_config() + # for ret_sect in ret.sections(): + # if self.Config.has_section(ret_sect): + # continue + # for ret_opt in self.Config[section].keys(): + # ret_value = ret[ret_sect][ret_opt] + # print(f'fix default section/key: "ret_sect", "ret_opt" to "ret_value"') + # change default unimacrogrammarsdirectory: section = 'directories' option = 'unimacrogrammarsdirectory' old_prefix = 'natlink_user' new_prefix = 'unimacro' - value = self.Config[section][option] - if value and value.find('natlink_user') == 0: - value = value.replace(old_prefix,new_prefix) - self.config_set(section, option, value) - logging.info(f'changed in "natlink.ini", section "directories", unimacro setting "{option}" to value: "{value}"') + try: + value = self.Config[section][option] + if value and value.find('natlink_user') == 0: + value = value.replace(old_prefix,new_prefix) + self.config_set(section, option, value) + logging.info(f'changed in "natlink.ini", section "directories", unimacro setting "{option}" to value: "{value}"') + pass + except KeyError: pass if loader.had_msg_error: @@ -440,11 +463,11 @@ def copyUnimacroIncludeFile(self): """ uscFile = 'Unimacro.vch' # also remove usc.vch from VocolaUserDirectory - unimacroDir = Path(self.status.getUnimacroDirectory()) - fromFolder = Path(unimacroDir)/'Vocola_compatibility' + dtactionsDir = Path(self.status.getDtactionsDirectory()) + fromFolder = Path(dtactionsDir)/'Vocola_compatibility' toFolder = Path(self.status.getVocolaUserDirectory()) - if not unimacroDir.is_dir(): - mess = f'copyUnimacroIncludeFile: unimacroDir "{str(unimacroDir)}" is not a directory' + if not dtactionsDir.is_dir(): + mess = f'copyUnimacroIncludeFile: dtactionsDir "{str(dtactionsDir)}" is not a directory' logging.warning(mess) return fromFile = fromFolder/uscFile diff --git a/src/natlinkcore/loader.py b/src/natlinkcore/loader.py index 172e1a3..ad60f6b 100644 --- a/src/natlinkcore/loader.py +++ b/src/natlinkcore/loader.py @@ -506,10 +506,10 @@ def set_user_language(self, args: Any = None): if args: self.user, self.profile = args self.language = self.get_user_language(self.profile) - self.logger.debug(f'set_user_language, user: "{self.user}", profile: "{self.profile}", language: "{self.language}"') + # self.logger.debug(f'set_user_language, user: "{self.user}", profile: "{self.profile}", language: "{self.language}"') else: self.user, self.profile = '', '' - self.logger.warning('set_user_language, cannot get input for get_user_language, set to "enx",\n\tprobably Dragon is not running or you are preforming pytests') + # self.logger.warning('set_user_language, cannot get input for get_user_language, set to "enx",\n\tprobably Dragon is not running or you are preforming pytests') self.language = 'enx' def start(self) -> None: diff --git a/src/natlinkcore/natlinkstatus.py b/src/natlinkcore/natlinkstatus.py index c980770..7ee9755 100644 --- a/src/natlinkcore/natlinkstatus.py +++ b/src/natlinkcore/natlinkstatus.py @@ -435,6 +435,8 @@ def getUnimacroGrammarsDirectory(self): key = 'unimacrogrammarsdirectory' value = self.natlinkmain.getconfigsetting(section='directories', option=key) + if not value: + return "" um_grammars_dir = natlinkcore.config.expand_path(value) self.UnimacroGrammarsDirectory = um_grammars_dir From ac8da4218568fa131502783640b606c891e28992 Mon Sep 17 00:00:00 2001 From: Quintijn Hoogenboom Date: Mon, 10 Jun 2024 16:32:54 +0200 Subject: [PATCH 13/25] improved some details, but foremost includeUnimacroVchLineInVocolaFiles and removeUnimacroVchLineInVocolaFiles, making them more stable. --- .../configure/natlinkconfigfunctions.py | 63 ++++++++++--------- 1 file changed, 35 insertions(+), 28 deletions(-) diff --git a/src/natlinkcore/configure/natlinkconfigfunctions.py b/src/natlinkcore/configure/natlinkconfigfunctions.py index 03d6848..b9a208b 100644 --- a/src/natlinkcore/configure/natlinkconfigfunctions.py +++ b/src/natlinkcore/configure/natlinkconfigfunctions.py @@ -518,7 +518,7 @@ def removeUnimacroIncludeFile(self): mess = f'copyUnimacroIncludeFile: Could not remove previous version of "{str(toFile)}"' logging.warning(mess) - def includeUnimacroVchLineInVocolaFiles(self, subDirectory=None): + def includeUnimacroVchLineInVocolaFiles(self, toFolder=None): """include the Unimacro wrapper support line into all Vocola command files as a side effect, set the variable for Unimacro in Vocola support: @@ -528,55 +528,66 @@ def includeUnimacroVchLineInVocolaFiles(self, subDirectory=None): oldUscFile = 'usc.vch' ## reInclude = re.compile(r'^include\s+.*unimacro.vch;$', re.MULTILINE) ## reOldInclude = re.compile(r'^include\s+.*usc.vch;$', re.MULTILINE) - + # also remove includes of usc.vch - toFolder = self.status.getVocolaUserDirectory() + vocUserDir = self.status.getVocolaUserDirectory() + toFolder = toFolder or vocUserDir + subDirectory = toFolder != vocUserDir if subDirectory: - toFolder = os.path.join(toFolder, subDirectory) includeLine = f'include ..\\{uscFile};\n' + oldIncludeLines = [f'include {oldUscFile};', + f'include ..\\{oldUscFile};', + f'include {uscFile};' + ] else: includeLine = f'include {uscFile};\n' - oldIncludeLines = [f'include {oldUscFile};', - f'include ..\\{oldUscFile};', - f'include {uscFile.lower()};', - f'include ..\\{uscFile.lower()};', - ] + oldIncludeLines = [f'include {oldUscFile};', + f'include ..\\{oldUscFile};', + f'include ..\\{uscFile};' + ] if not os.path.isdir(toFolder): - mess = f'cannot find Vocola command files directory, not a valid path: {toFolder}' + if subDirectory: + mess = f'cannot find Vocola command files in sub directory, not a valid path: {toFolder}' + else: + mess = f'cannot find Vocola command files in irectory, not a valid path: {toFolder}' logging.warning(mess) return mess + nFiles = 0 for f in os.listdir(toFolder): - F = os.path.join(toFolder, f) if f.endswith(".vcl"): + F = os.path.join(toFolder, f) changed = 0 correct = 0 Output = [] for line in open(F, 'r'): - if line.strip() == includeLine.strip(): + if line.strip().lower() == includeLine.strip().lower(): correct = 1 for oldLine in oldIncludeLines: - if line.strip() == oldLine: - changed = 1 + if line.strip().lower() == oldLine.lower(): + changed += 1 break else: Output.append(line) if changed or not correct: - # changes were made: + # print(f'{F}: wrong lines: {changed}, had correct line: {bool(correct)}') # changes were made: if not correct: + # print(f'\tinclude: "{includeLine.strip()}"') Output.insert(0, includeLine) open(F, 'w').write(''.join(Output)) nFiles += 1 - elif len(f) == 3 and os.path.isdir(F): + elif len(f) == 3: # subdirectory, recursive - self.includeUnimacroVchLineInVocolaFiles(F) + self.includeUnimacroVchLineInVocolaFiles(toFolder=os.path.join(toFolder, f)) mess = f'changed {nFiles} files in {toFolder}' logging.warning(mess) return True - def removeUnimacroVchLineInVocolaFiles(self, subDirectory=None): + def removeUnimacroVchLineInVocolaFiles(self, toFolder=None): """remove the Unimacro wrapper support line into all Vocola command files + + toFolder set with recursive calls... """ uscFile = 'Unimacro.vch' oldUscFile = 'usc.vch' @@ -584,9 +595,8 @@ def removeUnimacroVchLineInVocolaFiles(self, subDirectory=None): ## reOldInclude = re.compile(r'^include\s+.*usc.vch;$', re.MULTILINE) # also remove includes of usc.vch - if subDirectory: - # for recursive call language subfolders: - toFolder = subDirectory + if toFolder: + pass # for recursive call language subfolders: else: toFolder = self.status.getVocolaUserDirectory() @@ -596,9 +606,6 @@ def removeUnimacroVchLineInVocolaFiles(self, subDirectory=None): f'include ..\\{uscFile};', f'include ../{oldUscFile};', f'include ../{uscFile};', - f'include {uscFile.lower()};', - f'include ..\\{uscFile.lower()};', - f'include ../{uscFile.lower()};' ] @@ -614,7 +621,7 @@ def removeUnimacroVchLineInVocolaFiles(self, subDirectory=None): Output = [] for line in open(F, 'r'): for oldLine in oldIncludeLines: - if line.strip() == oldLine: + if line.strip().lower() == oldLine.lower(): changed = 1 break else: @@ -623,9 +630,9 @@ def removeUnimacroVchLineInVocolaFiles(self, subDirectory=None): # had break, so changes were made: open(F, 'w').write(''.join(Output)) nFiles += 1 - elif len(f) == 3 and os.path.isdir(F): - self.removeUnimacroVchLineInVocolaFiles(F) - self.disableVocolaTakesUnimacroActions() + elif len(f) == 3: + self.removeUnimacroVchLineInVocolaFiles(toFolder=os.path.join(toFolder, f)) + # self.disableVocolaTakesUnimacroActions() mess = f'removed include lines from {nFiles} files in {toFolder}' logging.warning(mess) From ae037e793b5f786bf12e411230afeb7536c27323 Mon Sep 17 00:00:00 2001 From: Quintijn Hoogenboom Date: Mon, 10 Jun 2024 19:04:20 +0200 Subject: [PATCH 14/25] with Aaron, changed natlinkcore.toml --- pyproject.toml | 3 --- 1 file changed, 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index db00af3..ee0d06f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -56,9 +56,6 @@ natlink_extensions = "natlinkcore.configure.natlink_extensions:main" [project.gui-scripts] natlinkconfig_gui = "natlinkcore.configure.natlinkconfig_gui:main_gui" -[project.entry-points."dt.loggers"] - natlink ="natlinkcore:logname" - [project.entry-points."dt.loggers"] natlink ="natlinkcore:logname" From bf0d32153a89dcb1a23c9d24c2a04f9794520dff Mon Sep 17 00:00:00 2001 From: Quintijn Hoogenboom Date: Wed, 26 Jun 2024 18:06:16 +0200 Subject: [PATCH 15/25] changes because of the NATLINK_SETTINGSDIR setting (change from NATLINK_USERDIR) --- .../DefaultConfig/_config_instructions.py | 71 ++++++++++++------- src/natlinkcore/config.py | 17 +---- .../configure/natlinkconfigfunctions.py | 2 +- src/natlinkcore/natlinkstatus.py | 24 +++---- 4 files changed, 59 insertions(+), 55 deletions(-) diff --git a/src/natlinkcore/DefaultConfig/_config_instructions.py b/src/natlinkcore/DefaultConfig/_config_instructions.py index 1aa564e..b7dff8b 100644 --- a/src/natlinkcore/DefaultConfig/_config_instructions.py +++ b/src/natlinkcore/DefaultConfig/_config_instructions.py @@ -4,20 +4,41 @@ """ import os import os.path -from natlinkcore import getThisDir +from natlinkcore import config join, expanduser, getenv = os.path.join, os.path.expanduser, os.getenv isfile, isdir = os.path.isfile, os.path.isdir home = expanduser('~') -thisFile = __file__ -_this_dir, this_filename = __file__.rsplit('\\', 1) -thisDir = getThisDir(__file__) -if _this_dir != thisDir: - print(f'Working with symlinks! Point to the sitepackages directory: "{_this_dir}", but edit in "{thisDir}"') -this_dir = thisDir +this_dir, this_filename = __file__.rsplit('\\', 1) +if this_dir.find('\\site-packages\\') == -1: + print(f'Working with symlinks! Working from directory: "{this_dir}"\n') + +natlink_settingsdir = getenv("NATLINK_SETTINGSDIR") +natlink_userdir = getenv("NATLINK_USERDIR") + +if natlink_settingsdir: + natlink_settings_path = config.expand_path(natlink_settingsdir) + if os.path.isdir(natlink_settings_path): + if natlink_settingsdir == natlink_settings_path: + print(f'You specified for NATLINK_SETTINGSDIR: "{natlink_settingsdir}"') + else: + print(f'You specified for NATLINK_SETTINGSDIR: "{natlink_settingsdir}", which expands to: "{natlink_settings_path}".') + +if natlink_userdir: + natlink_user_path = config.expand_path(natlink_userdir) + + if natlink_settingsdir: + print(f'WARNING: You also specified NATLINK_USERDIR to "{natlink_userdir}", this setting is ignored.') + else: + print(f'WARNING: The setting of environment variable NATLINK_USERDIR (to "{natlink_userdir}") is obsolete,') + print('please change this setting to NATLINK_SETTINGSDIR') + + + + print(f'\n\n' - f'\nThis is the file "{this_filename}" from directory "{this_dir}"' + f'\nThis is the file "{this_filename}" from directory "{this_dir}".' f'\nThis directory holds the default "natlink.ini" file, when it is not found the default or configured directory.' f'\n\n' rf'The default directory is: "~\.natlink", with "~" being your HOME directory: "{home}".' @@ -25,9 +46,9 @@ f"\n" f'\nThere is also a custom way to configure the directory of your "natlink.ini" file:' f'\n' - f'\nSpecify the environment variable "NATLINK_USERDIR", which should point to an existing directory.' + f'\nSpecify the environment variable "NATLINK_SETTINGSDIR", which should point to an existing directory.' f'\nNote: this directory may NOT be a shared directory, like Dropbox or OneDrive.' - f'\nseveral directories to be configured may be shared however, but others must be local, which is hopefully ' + f'\nSeveral directories to be configured may be shared however, but others must be local, which is hopefully ' f'\nensured well enough in the config program.' f'\n' f'\nWhen this directory does not hold the file "natlink.ini",\nyou can copy it from "{this_dir}",' @@ -38,27 +59,23 @@ f'\n\tthe additional options in order to get started with using Natlink.' f'\n' ) -natlink_userdir = getenv("NATLINK_USERDIR") -ysfnu=f'You specified "NATLINK_USERDIR" to "{natlink_userdir}"' -msg="" -if natlink_userdir: - if isdir(natlink_userdir): - msg=f'{ysfnu}".' - f'\nSo Natlink should not startup with these messages. ' - f'\nProbably you do not have a proper "natlink.ini" file into this path.' - f'\nPlease run the configure program of Natlink:' +if natlink_settingsdir: + if os.path.isdir(natlink_settings_path): + if natlink_settingsdir == natlink_settings_path: + print(f'You specified for NATLINK_SETTINGSDIR: "{natlink_settingsdir}"') + else: + print(f'You specified for NATLINK_SETTINGSDIR: "{natlink_settingsdir}", which expands to: "{natlink_settings_path}".') else: - msg=f'{ysfnu}, but this is not a valid directory path' + print(f'You specified for NATLINK_SETTINGSDIR: "{natlink_settingsdir}", which does not expand to a valid directory: "{natlink_settings_path}".') + print('The NATLINK_SETTINGSDIR should hold a valid config file "natlink.ini"') else: - msg=f'\nYou did not set "NATLINK_USERDIR" on your windows system' - f'\nThe config file "natlink.ini" should now be in "{home}\\.natlink\\natlink.ini"\n' - f'\nSo... please copy the file "{this_dir}\\natlink.ini" into this location, or (BETTER)' - f'\nrun the configure program of Natlink:' + print('The default config directory NATLINK_SETTINGSDIR should hold a valid config file "natlink.ini"') -msg+= '\n' -'\nPlease try to run the config program (Command Line Interface) by running ***"natlinkconfig"***' +msg = '\n' +'\nPlease try to run the config program (Command Line Interface) by running' +'\n***"Configure Natlink via GUI"*** or ***"Configure Natlink via CLI"***' '\n\tfrom the Windows command prompt.' -"\n" +'\n' '\nAfter all these steps, (re)start Dragon and good luck...\n\n\n' print(msg) diff --git a/src/natlinkcore/config.py b/src/natlinkcore/config.py index 2ecb69f..d65d20a 100644 --- a/src/natlinkcore/config.py +++ b/src/natlinkcore/config.py @@ -183,9 +183,9 @@ def expand_path(input_path: str) -> str: dir_path = normpath(dir_path) if isdir(dir_path): return dir_path - print(f'no valid directory found with "natlink_userdir": "{dir_path}"') + print(f'no valid directory found with "natlink_userdir": "{dir_path}"\nbut "natlink_userdir" should be replaced by "natlink_settingsdir" anyway') return dir_path - print(f'natlink_userdir does not expand to a valid directory: "{nud}"') + print(f'natlink_userdir does not expand to a valid directory: "{nud}"\nbut "natlink_userdir" should be replaced by "natlink_settingsdir" anyway') return normpath(nud) if input_path.startswith('natlink_settingsdir/') or input_path.startswith('natlink_settingsdir\\'): @@ -224,19 +224,6 @@ def expand_path(input_path: str) -> str: # print(f'env_expanded: "{env_expanded}", from envvar: "{input_path}"') return normpath(env_expanded) -def expand_natlink_settingsdir(): - """not with envvariables, but special: - - if NATLINK_USERDIR is set: return this, but... it should end with ".natlink" - if NATLINK_USERDIR is NOT set: return Path.home()/'.natlink' - """ - normpath = os.path.normpath - nud = os.getenv('natlink_userdir') or str(Path.home()/'.natlink') - nud = normpath(expand_path(nud)) - if not nud.endswith('.natlink'): - raise ValueError(f'expand_natlink_settingsdir: directory "{nud}" should end with ".natlink"\n\tprobably you did not set the windows environment variable "NATLINK_USERDIR" incorrect, let it end with ".natlink".\n\tNote: if this ".natlink" directory does not exist yet, it will be created there.') - return nud - def expand_natlink_settingsdir(): """not with envvariables, but special: diff --git a/src/natlinkcore/configure/natlinkconfigfunctions.py b/src/natlinkcore/configure/natlinkconfigfunctions.py index b9a208b..b848c77 100644 --- a/src/natlinkcore/configure/natlinkconfigfunctions.py +++ b/src/natlinkcore/configure/natlinkconfigfunctions.py @@ -442,7 +442,7 @@ def enable_vocola(self, arg): if not vocola_user_dir: return # vocGrammarsDir = self.status.getVocolaGrammarsDirectory() - vocGrammarsDir = r'natlink_userdir\vocolagrammars' + vocGrammarsDir = r'natlink_settings\vocolagrammars' self.setDirectory('vocoladirectory','vocola2') #always vocola2 self.setDirectory('vocolagrammarsdirectory', vocGrammarsDir) self.copyUnimacroIncludeFile() diff --git a/src/natlinkcore/natlinkstatus.py b/src/natlinkcore/natlinkstatus.py index 7ee9755..efcbd96 100644 --- a/src/natlinkcore/natlinkstatus.py +++ b/src/natlinkcore/natlinkstatus.py @@ -73,10 +73,9 @@ the Unimacro user directory getUnimacroDataDirectory: get the directory where Unimacro grammars can store data, this should be per computer, and is set - into the natlink_user area + into the natlink_settingsdir area -getUnimacroGrammarsDirectory: get the directory where Unimacro grammars are (by default) located in a sub directory 'UnimacroGrammars' of the - UnimacroDirectory +getUnimacroGrammarsDirectory: get the directory where Unimacro grammars are (by default) located in the python site-packagers directory 'unimacro' getVocolaDirectory: get the directory where the Vocola system is. When cloned from git, in Vocola, relative to the Core directory. Otherwise (when pipped) in some site-packages directory. It holds (and should hold) the @@ -88,7 +87,7 @@ getVocolaGrammarsDirectory: get the directory, where the compiled Vocola grammars are/will be. This will be the `CompiledGrammars` subdirectory of `~/.vocolaGrammars` or - `%NATLINK_USERDIR%/.vocola`. + `%NATLINK_SETTINGSDIR%/.vocola`. getVocolaTakesLanguages: additional settings for Vocola @@ -363,11 +362,11 @@ def getNatlinkIni(self): raise OSError(f'getNatlinkIni: not a valid file: "{path}"') return path - def getNatlink_Userdir(self): + def getNatlink_Settingsdir(self): """get the directory where "natlink.ini" should be stored This must be a local directory, default `~`, but can be changed by - setting `NATLINK_USERDIR` to for example `~/Documents`. + setting `NATLINK_SETTINGSDIR` to for example `~/Documents`. Other directories that are created and checked by packages, and should be local, can be stored here, for example `VocolaGrammarsDirectory` (VocolaGrammars) and @@ -375,8 +374,9 @@ def getNatlink_Userdir(self): """ natlink_ini_path = Path(self.getNatlinkIni()) - natlink_user_dir = natlink_ini_path.parent - return str(natlink_user_dir) + natlink_settings_dir = natlink_ini_path.parent.parent + + return str(natlink_settings_dir) def getUnimacroUserDirectory(self): isdir, abspath = os.path.isdir, os.path.abspath @@ -452,9 +452,9 @@ def getUnimacroDataDirectory(self): if self.UnimacroDataDirectory is not None: return self.UnimacroDataDirectory - natlink_user_dir = self.getNatlink_Userdir() + natlink_settings_dir = self.getNatlink_Settingsdir() - um_data_dir = Path(natlink_user_dir)/'UnimacroData' + um_data_dir = Path(natlink_settings_dir)/'UnimacroData' if not um_data_dir.is_dir(): um_data_dir.mkdir() um_data_dir = str(um_data_dir) @@ -755,7 +755,7 @@ def getNatlinkStatusDict(self): for key in ['DNSIniDir', 'WindowsVersion', 'DNSVersion', 'PythonVersion', - 'DNSName', 'NatlinkIni', 'Natlink_Userdir', + 'DNSName', 'NatlinkIni', 'Natlink_Settingsdir', 'UnimacroDirectory', 'UnimacroUserDirectory', 'UnimacroGrammarsDirectory', 'UnimacroDataDirectory', 'VocolaDirectory', 'VocolaUserDirectory', 'VocolaGrammarsDirectory', 'VocolaTakesLanguages', 'VocolaTakesUnimacroActions', @@ -799,7 +799,7 @@ def getNatlinkStatusString(self): # Natlink:: L.append('') - for key in ['NatlinkDirectory', 'NatlinkcoreDirectory', 'InstallVersion', 'NatlinkIni', 'Natlink_Userdir']: + for key in ['NatlinkDirectory', 'NatlinkcoreDirectory', 'InstallVersion', 'NatlinkIni', 'Natlink_Settingsdir']: self.appendAndRemove(L, D, key) ## Dragonfly: From 65a93a1af1a6e2f31af772e62ff6b76641f8ed4f Mon Sep 17 00:00:00 2001 From: Quintijn Hoogenboom Date: Thu, 27 Jun 2024 18:41:46 +0200 Subject: [PATCH 16/25] add an assert statement in def openConfigFile of natlinkconfigfunctions.py --- src/natlinkcore/configure/natlinkconfigfunctions.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/natlinkcore/configure/natlinkconfigfunctions.py b/src/natlinkcore/configure/natlinkconfigfunctions.py index b848c77..28798cd 100644 --- a/src/natlinkcore/configure/natlinkconfigfunctions.py +++ b/src/natlinkcore/configure/natlinkconfigfunctions.py @@ -675,6 +675,9 @@ def disableVocolaTakesUnimacroActions(self): def openConfigFile(self): """open the natlink.ini config file """ + assert self.config_path and os.path.isfile(self.config_path) + # logging.warning(f'openConfigFile, no valid config_path specified: "{self.config_path}"') + # return False os.startfile(self.config_path) logging.info(f'opened "{self.config_path}" in a separate window') return True From 2b545d1a8d15257e45379645027fd33b2f441b62 Mon Sep 17 00:00:00 2001 From: Quintijn Hoogenboom Date: Mon, 22 Jul 2024 16:07:14 +0200 Subject: [PATCH 17/25] fixed a few tests and tidied up config things and user messages NALINK_SETTINGSDIR should point to the correct .natlink directory (if used) (change in natlinkstatus.py --- .../DefaultConfig/_config_instructions.py | 25 ++++++------ src/natlinkcore/config.py | 39 ++++++++++++------- .../configure/natlinkconfigfunctions.py | 8 ++-- src/natlinkcore/natlinkstatus.py | 4 +- tests/test_readwritefile.py | 25 ++++++------ 5 files changed, 58 insertions(+), 43 deletions(-) diff --git a/src/natlinkcore/DefaultConfig/_config_instructions.py b/src/natlinkcore/DefaultConfig/_config_instructions.py index b7dff8b..3dbf035 100644 --- a/src/natlinkcore/DefaultConfig/_config_instructions.py +++ b/src/natlinkcore/DefaultConfig/_config_instructions.py @@ -6,7 +6,7 @@ import os.path from natlinkcore import config -join, expanduser, getenv = os.path.join, os.path.expanduser, os.getenv +join, expanduser, getenv, normpath = os.path.join, os.path.expanduser, os.getenv, os.path.normpath isfile, isdir = os.path.isfile, os.path.isdir home = expanduser('~') @@ -18,6 +18,7 @@ natlink_userdir = getenv("NATLINK_USERDIR") if natlink_settingsdir: + natlink_settingsdir = normpath(natlink_settingsdir) natlink_settings_path = config.expand_path(natlink_settingsdir) if os.path.isdir(natlink_settings_path): if natlink_settingsdir == natlink_settings_path: @@ -39,7 +40,7 @@ print(f'\n\n' f'\nThis is the file "{this_filename}" from directory "{this_dir}".' - f'\nThis directory holds the default "natlink.ini" file, when it is not found the default or configured directory.' + f'\nThis directory holds the default "natlink.ini" file, when it is not found in the default or configured directory.' f'\n\n' rf'The default directory is: "~\.natlink", with "~" being your HOME directory: "{home}".' f'\tSo: "{home}\\.natlink"' @@ -47,6 +48,8 @@ f'\nThere is also a custom way to configure the directory of your "natlink.ini" file:' f'\n' f'\nSpecify the environment variable "NATLINK_SETTINGSDIR", which should point to an existing directory.' + f'\nthat ends with ".natlink".' + f'\n' f'\nNote: this directory may NOT be a shared directory, like Dropbox or OneDrive.' f'\nSeveral directories to be configured may be shared however, but others must be local, which is hopefully ' f'\nensured well enough in the config program.' @@ -60,22 +63,22 @@ f'\n' ) if natlink_settingsdir: - if os.path.isdir(natlink_settings_path): + if isdir(natlink_settings_path): if natlink_settingsdir == natlink_settings_path: print(f'You specified for NATLINK_SETTINGSDIR: "{natlink_settingsdir}"') else: print(f'You specified for NATLINK_SETTINGSDIR: "{natlink_settingsdir}", which expands to: "{natlink_settings_path}".') else: - print(f'You specified for NATLINK_SETTINGSDIR: "{natlink_settingsdir}", which does not expand to a valid directory: "{natlink_settings_path}".') - print('The NATLINK_SETTINGSDIR should hold a valid config file "natlink.ini"') + print(f'You specified for NATLINK_SETTINGSDIR: "{natlink_settingsdir}"') + print('This directory should exist! Please create manually or run the config program ') else: print('The default config directory NATLINK_SETTINGSDIR should hold a valid config file "natlink.ini"') -msg = '\n' -'\nPlease try to run the config program (Command Line Interface) by running' -'\n***"Configure Natlink via GUI"*** or ***"Configure Natlink via CLI"***' -'\n\tfrom the Windows command prompt.' -'\n' -'\nAfter all these steps, (re)start Dragon and good luck...\n\n\n' +msg = '\n'.join(['', +'Please try to run the config program (Command Line Interface) by running', +'***"Configure Natlink via GUI"*** or ***"Configure Natlink via CLI"***', +'\tfrom the Windows command prompt.', +'', +'After all these steps, (re)start Dragon and good luck...', '', '']) print(msg) diff --git a/src/natlinkcore/config.py b/src/natlinkcore/config.py index d65d20a..d4c2cd1 100644 --- a/src/natlinkcore/config.py +++ b/src/natlinkcore/config.py @@ -209,16 +209,19 @@ def expand_path(input_path: str) -> str: else: package_trunk, rest = input_path, '' # find path for package. not an alternative way without loading the package is to use importlib.util.findspec. - try: - pack = __import__(package_trunk) - package_path = pack.__path__[-1] - if rest: - dir_expanded = str(Path(package_path)/rest) - return dir_expanded - return package_path - - except ModuleNotFoundError: - pass + + # first check for exclude "C:" as trunk: + if package_trunk and package_trunk[-1] != ":": + try: + pack = __import__(package_trunk) + package_path = pack.__path__[-1] + if rest: + dir_expanded = str(Path(package_path)/rest) + return dir_expanded + return package_path + + except (ModuleNotFoundError, OSError): + pass env_expanded = expandvars(input_path) # print(f'env_expanded: "{env_expanded}", from envvar: "{input_path}"') @@ -231,8 +234,18 @@ def expand_natlink_settingsdir(): if NATLINK_SETTINGSDIR is NOT set: return Path.home()/'.natlink' """ normpath = os.path.normpath - nsd = os.getenv('natlink_settingsdir') or str(Path.home()/'.natlink') + nsd = os.getenv('natlink_settingsdir') + if nsd: + if not os.path.isdir(nsd): + # this one should not happen, because .natlink is automatically created when it does not exist yet... + raise OSError(f'Environment variable "NATLINK_SETTINGSDIR" should hold a valid directory, ending with ".natlink", not: "{nsd}"\n\tCreate your directory likewise or remove this environment variable, and go back to the default directory (~\\.natlink)\n') + + if not normpath(nsd).endswith('.natlink'): + raise ValueError(f'Environment variable "NATLINK_SETTINGSDIR" should end with ".natlink", not: "{nsd}"\n\tCreate your directory likewise or remove this environment variable, returning to the default directory (~\\.natlink)\n') + else: + nsd = str(Path.home()/'.natlink') + nsd = normpath(expand_path(nsd)) - if not nsd.endswith('.natlink'): - raise ValueError(f'expand_natlink_settingsdir: directory "{nsd}" should end with ".natlink"\n\tprobably you did not set the windows environment variable "NATLINK_SETTINGSDIR" incorrect, let it end with ".natlink".\n\tNote: if this ".natlink" directory does not exist yet, it will be created there.') + # if not nsd.endswith('.natlink'): + # raise ValueError(f'expand_natlink_settingsdir: directory "{nsd}" should end with ".natlink"\n\tprobably you did not set the windows environment variable "NATLINK_SETTINGSDIR" incorrect, let it end with ".natlink".\n\tNote: if this ".natlink" directory does not exist yet, it will be created there.') return nsd diff --git a/src/natlinkcore/configure/natlinkconfigfunctions.py b/src/natlinkcore/configure/natlinkconfigfunctions.py index 28798cd..be6a243 100644 --- a/src/natlinkcore/configure/natlinkconfigfunctions.py +++ b/src/natlinkcore/configure/natlinkconfigfunctions.py @@ -75,7 +75,7 @@ def get_check_config_locations(self): """check the location/locations as given by the loader """ - config_path, fallback_path = loader.config_locations() + config_path, fallback_path = loader.config_locations() if not isfile(config_path): config_dir = Path(config_path).parent @@ -123,11 +123,11 @@ def check_config(self): if loader.had_msg_error: logging.error('The environment variable "NATLINK_USERDIR" has been changed to "NATLINK_SETTINGSDIR" by the user, but has a conclicting value') - logging.error('Please remove "NATLINK_USERDIR", in the windows environment variables, dialog User variables, and restart your program') + logging.error('Please remove "NATLINK_USERDIR", in the windows "environment variables", dialog User variables, and restart your program') if loader.had_msg_warning: - logging.error('The key of the environment variable "NATLINK_USERDIR" should be changed to "NATLINK_SETTINGSDIR"') - logging.error('You can do so in "windows environment variables", dialog "User variables". Then your program') + logging.error('The key of the environment variable "NATLINK_USERDIR" should be changed to "NATLINK_SETTINGSDIR".') + logging.error('You can do so in windows "environment variables", dialog "User variables".') # for key, value in self.Config[section].items(): diff --git a/src/natlinkcore/natlinkstatus.py b/src/natlinkcore/natlinkstatus.py index efcbd96..8cd2512 100644 --- a/src/natlinkcore/natlinkstatus.py +++ b/src/natlinkcore/natlinkstatus.py @@ -366,7 +366,7 @@ def getNatlink_Settingsdir(self): """get the directory where "natlink.ini" should be stored This must be a local directory, default `~`, but can be changed by - setting `NATLINK_SETTINGSDIR` to for example `~/Documents`. + setting `NATLINK_SETTINGSDIR` to for example `~/Documents/.natlink`. Other directories that are created and checked by packages, and should be local, can be stored here, for example `VocolaGrammarsDirectory` (VocolaGrammars) and @@ -374,7 +374,7 @@ def getNatlink_Settingsdir(self): """ natlink_ini_path = Path(self.getNatlinkIni()) - natlink_settings_dir = natlink_ini_path.parent.parent + natlink_settings_dir = natlink_ini_path.parent return str(natlink_settings_dir) diff --git a/tests/test_readwritefile.py b/tests/test_readwritefile.py index 408483e..6923d48 100644 --- a/tests/test_readwritefile.py +++ b/tests/test_readwritefile.py @@ -93,21 +93,20 @@ def test_other_encodings_write_file(tmp_path): rwfile = ReadWriteFile(encodings=['latin1']) # optional encoding text = rwfile.readAnything(oldFile) assert text == 'latin1 café' - - - +# def test_latin1_cp1252_write_file(tmp_path): +# """ TODO (QH) to be done, these encodings do not take all characters, +# and need special attention. latin1 and cp1252 are hard to be distinguished +# For now, cp1252 (holding more (some special characters like the euro sign and quotes)) +# is favored over latin1. +# (as long as the "fallback" is utf-8, all write files should go well!) +# """ +# testDir = tmp_path / testFolderName +# testDir.mkdir() +# _newFile = testDir/ 'latin1.txt' +# _newFile = testDir/'cp1252.txt' +# assert False, "QH TODO" -def test_latin1_cp1252_write_file(tmp_path): - testDir = tmp_path / testFolderName - testDir.mkdir() - _newFile = testDir/ 'latin1.txt' - _newFile = testDir/'cp1252.txt' - assert False, "QH TODO" - - # TODO (QH) to be done, these encodings do not take all characters, - # and need special attention. - # (as long as the "fallback" is utf-8, all write files should go well!) def test_read_write_file(tmp_path): listdir, join, splitext = os.listdir, os.path.join, os.path.splitext From eea6641c03c13fb79aa18d1df05949ff060522a4 Mon Sep 17 00:00:00 2001 From: Quintijn Hoogenboom Date: Mon, 22 Jul 2024 16:09:41 +0200 Subject: [PATCH 18/25] fixed the getting of repository names as directory (especially when entering "C:" as (start of) path.) --- tests/test_config.py | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/tests/test_config.py b/tests/test_config.py index 098bacd..73d5a59 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -18,7 +18,7 @@ def sample_config(sample_name) -> 'NatlinkConfig': """ load a config file from the config files subfolder """ - sample_ini= (p.Path(__file__).parent) / "config_files" / sample_name + sample_ini= str((p.Path(__file__).parent) / "config_files" / sample_name ) test_config = NatlinkConfig.from_file(sample_ini) return test_config @@ -55,7 +55,7 @@ def mock_syspath(monkeypatch): def mock_userdir(monkeypatch): mock_folder=p.WindowsPath(os.path.dirname(__file__)) / "mock_userdir" / ".natlink" print(f"Mock Userdir Folder {mock_folder}") - monkeypatch.setenv("natlink_userdir",str(mock_folder)) + monkeypatch.setenv("natlink_settingsdir",str(mock_folder)) def test_settings_1(mock_syspath,settings1): @@ -148,11 +148,11 @@ def test_expand_path(mock_syspath,mock_userdir): assert not os.path.isdir(result) # assume FakeGrammars is a valid directory: - result = expand_path('natlink_userdir/FakeGrammars') + result = expand_path('natlink_settingsdir/FakeGrammars') assert os.path.isdir(result) # invalid directory - result = expand_path('natlink_userdir/invalid_dir') + result = expand_path('natlink_settingsdir/invalid_dir') assert not os.path.isdir(result) # try package @@ -174,12 +174,6 @@ def test_expand_path(mock_syspath,mock_userdir): result = expand_path('/natlinkcore') assert not os.path.isdir(result) - result = expand_path('unimacro') - assert os.path.isdir(result) - - result = expand_path('unimacro/unimacrogrammars') - assert os.path.isdir(result) - def test_config_locations(): From 4855feeddec7756aac0d0ed7e0fb0dca813f0496 Mon Sep 17 00:00:00 2001 From: Quintijn Hoogenboom Date: Wed, 7 Aug 2024 16:24:00 +0200 Subject: [PATCH 19/25] played a bit with testing, renamed mock_userdir to mock_settingsdir --- src/natlinkcore/nsformat.py | 29 --------------- tests/conftest.py | 2 +- .../.natlink/FakeGrammars/blankt.txt | 0 .../.natlink/natlink.ini | 0 tests/test_config.py | 36 ++++++++++--------- 5 files changed, 20 insertions(+), 47 deletions(-) rename tests/{mock_userdir => mock_settingsdir}/.natlink/FakeGrammars/blankt.txt (100%) rename tests/{mock_userdir => mock_settingsdir}/.natlink/natlink.ini (100%) diff --git a/src/natlinkcore/nsformat.py b/src/natlinkcore/nsformat.py index 8eea88c..ddc4662 100644 --- a/src/natlinkcore/nsformat.py +++ b/src/natlinkcore/nsformat.py @@ -480,37 +480,8 @@ def showStateFlags(state): #--------------------------------------------------------------------------- -def testSubroutine(state, Input, Output): - - words = Input.split() - for i, _word in enumerate(words): - words[i] = words[i].replace('_', ' ') - actual,state = formatWords(words,state) - if actual != Output: - print(f'Expected {"Output"}') - print(f'Actually {"actual"}') - raise ValueError("test error") - return state #--------------------------------------------------------------------------- -def testFormatting(): - - state=None - # assume english, two spaces after .: - # note _ is converted into a space, inside a word () - - state=testSubroutine(state, - r'first .\period\period next', - 'First. Next') - # continuing the previous: - state=testSubroutine(state, - r'this is a second sentence .\period\period', - ' this is a second sentence.') - state=testSubroutine(state, - r'\caps-on\Caps-On as you can see ,\comma\comma this yours_truly works \caps-off\caps_off well', - ' As You Can See, This Yours Truly Works well') - - print('Example Formatting tests (11) passed, more in unittestNsformat (in PyTest directory)') if __name__=='__main__': import doctest diff --git a/tests/conftest.py b/tests/conftest.py index 7944f5b..2fd8038 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,2 +1,2 @@ # this is a special file of pytest, the name is confusing since we have our own test_config.py -# it has a purpose you can read about in the pytest documentation. \ No newline at end of file +# it has a purpose you can read about in the pytest documentation. diff --git a/tests/mock_userdir/.natlink/FakeGrammars/blankt.txt b/tests/mock_settingsdir/.natlink/FakeGrammars/blankt.txt similarity index 100% rename from tests/mock_userdir/.natlink/FakeGrammars/blankt.txt rename to tests/mock_settingsdir/.natlink/FakeGrammars/blankt.txt diff --git a/tests/mock_userdir/.natlink/natlink.ini b/tests/mock_settingsdir/.natlink/natlink.ini similarity index 100% rename from tests/mock_userdir/.natlink/natlink.ini rename to tests/mock_settingsdir/.natlink/natlink.ini diff --git a/tests/test_config.py b/tests/test_config.py index 73d5a59..3a32b74 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -1,4 +1,4 @@ -#pylint:disable= C0114, C0116, W0401, W0614, W0621, W0108. W0212 +#pylint:disable= C0114, C0116, W0401, W0614, W0621, W0108, W0212, C3001, import pathlib as p import sys @@ -44,6 +44,7 @@ def test_empty_config(empty_config): dap_settings1 = make_sample_config_fixture("dap_settings_1.ini") dap_settings2 = make_sample_config_fixture("dap_settings_2.ini") dap_settings3 = make_sample_config_fixture("dap_settings_3.ini") + @pytest.fixture() def mock_syspath(monkeypatch): """Add a tempory path to mock modules in sys.pythonpath""" @@ -52,9 +53,10 @@ def mock_syspath(monkeypatch): monkeypatch.syspath_prepend(str(mock_folder)) @pytest.fixture() -def mock_userdir(monkeypatch): - mock_folder=p.WindowsPath(os.path.dirname(__file__)) / "mock_userdir" / ".natlink" - print(f"Mock Userdir Folder {mock_folder}") +def mock_settingsdir(monkeypatch): + """Mock Config folder with natlink_settingsdir """ + mock_folder=p.WindowsPath(os.path.dirname(__file__)) / "mock_settingsdir" / ".natlink" + print(f"Mock Config folder with natlink_settingsdir mocked env variable: {mock_folder}") monkeypatch.setenv("natlink_settingsdir",str(mock_folder)) @@ -70,18 +72,18 @@ def test_settings_1(mock_syspath,settings1): def filt(s,sub): return s.upper().find(sub.upper()) >=0 - filt1=lambda s : filt(s, "fake_package1") - filt2=lambda s : filt(s, "C:\\") + filt1 = lambda s : filt(s, "fake_package1") + filt2 = lambda s : filt(s, "C:\\") filt3 = lambda s: filt(s,"nonexistant") #gets loaded anyway even though doesnt exist. def lenlistfilter(f,l): return len(list(filter(f,l))) - assert lenlistfilter(filt1,test_cfg.directories_for_user('')) >0 + assert lenlistfilter(filt1,test_cfg.directories_for_user('')) > 0 - assert lenlistfilter(filt2,test_cfg.directories_for_user('')) >0 -# assert lenlistfilter(filt3,test_cfg.directories_for_user('')) >0 + assert lenlistfilter(filt2,test_cfg.directories_for_user('')) > 0 + assert lenlistfilter(filt3,test_cfg.directories_for_user('')) == 0 # relevant? QH assert test_cfg.log_level is LogLevel.DEBUG @@ -105,22 +107,22 @@ def test_settings_2(mock_syspath,settings2): def test_dap_settings(dap_settings1,dap_settings2,dap_settings3): test_cfg=dap_settings1 - assert test_cfg.dap_enabled == False + assert test_cfg.dap_enabled is False assert test_cfg.dap_port == 7474 - assert test_cfg.dap_wait_for_debugger_attach_on_startup == False + assert test_cfg.dap_wait_for_debugger_attach_on_startup is False test_cfg=dap_settings2 - assert test_cfg.dap_enabled ==True + assert test_cfg.dap_enabled is True assert test_cfg.dap_port == 0 - assert test_cfg.dap_wait_for_debugger_attach_on_startup == True + assert test_cfg.dap_wait_for_debugger_attach_on_startup is True test_cfg=dap_settings3 - assert test_cfg.dap_enabled ==False + assert test_cfg.dap_enabled is False assert test_cfg.dap_port == 0 - assert test_cfg.dap_wait_for_debugger_attach_on_startup == False + assert test_cfg.dap_wait_for_debugger_attach_on_startup is False -def test_expand_path(mock_syspath,mock_userdir): +def test_expand_path(mock_syspath,mock_settingsdir): """test the different expand_path possibilities, including finding a directory along sys.path since we know users might pip a package to a few different spots depending on whether they are in an elevated shell. We specifically aren't testing unimacro and vocola2 since they might be in the sys.path or maybe not""" @@ -208,4 +210,4 @@ def test_mocks_actually_work(mock_syspath): print("-----------------------------------------") pprint(sys.path) - pytest.main([f'test_config.py']) + pytest.main(['test_config.py']) From e347a4202c01133c8bf6088183f36a996409f5b4 Mon Sep 17 00:00:00 2001 From: Quintijn Hoogenboom Date: Sat, 10 Aug 2024 15:47:15 +0200 Subject: [PATCH 20/25] working on sample macros, added _sample_move_natlinktimer.py for continuous cursor moving. --- .../OriginalSampleMacros/_mouse.py | 12 +- .../SampleMacros/_sample_move_natlinktimer.py | 234 ++++++++++++++++++ 2 files changed, 240 insertions(+), 6 deletions(-) create mode 100644 src/natlinkcore/SampleMacros/_sample_move_natlinktimer.py diff --git a/src/natlinkcore/SampleMacros/OriginalSampleMacros/_mouse.py b/src/natlinkcore/SampleMacros/OriginalSampleMacros/_mouse.py index ba47d7e..834daa4 100644 --- a/src/natlinkcore/SampleMacros/OriginalSampleMacros/_mouse.py +++ b/src/natlinkcore/SampleMacros/OriginalSampleMacros/_mouse.py @@ -160,7 +160,7 @@ def cancelMode(self): natlink.setTimerCallback(None,0) self.haveCallback = 0 self.activateSet(['start'],exclusive=0) - natlink.setTrayIcon() + # natlink.setTrayIcon() # This function is called on a timer event. If we are in a movement # mode then we move the mouse or caret by the indicated amount. @@ -176,7 +176,7 @@ def onTimer(self): if self.curMode == 1: moduleInfo = natlink.getCurrentModule() if natlink.getMicState() == 'on' and moduleInfo == self.moduleInfo: - self.setTrayIcon(1) + # self.setTrayIcon(1) # Note: it is often during a playString operation that the # "stop moving" command occurs natlink.playString('{'+self.curDirection+'}') @@ -224,10 +224,10 @@ def gotResults_startMoving(self,words,fullResults): direction = findKeyWord(words,self.listDefn['direction']) self.curMode = 1 self.curDirection = direction - self.setTrayIcon(0) + # self.setTrayIcon(0) self.moduleInfo = natlink.getCurrentModule() self.curSpeed = defaultMoveSpeed - self.lastClock = time.clock() + self.lastClock = time.time() natlink.setTimerCallback(self.onTimer,defaultMoveSpeed) self.haveCallback = 1 self.activateSet(['nowMoving'],exclusive=1) @@ -239,7 +239,7 @@ def gotResults_nowMoving(self,words,fullResults): direction = findKeyWord(words,self.listDefn['direction']) if direction: self.curDirection = direction - self.setTrayIcon(0) + # self.setTrayIcon(0) elif 'stop' in words: self.cancelMode() elif 'faster' in words: @@ -319,7 +319,7 @@ def setTrayIcon(self,toggleIcon): else: self.iconState = 1 iconName = iconName + '2' - natlink.setTrayIcon(iconName,toolTip,self.onTrayIcon) + # natlink.setTrayIcon(iconName,toolTip,self.onTrayIcon) # This is called if the user clicks on the tray icon. We simply cancel # movement in all cases. diff --git a/src/natlinkcore/SampleMacros/_sample_move_natlinktimer.py b/src/natlinkcore/SampleMacros/_sample_move_natlinktimer.py new file mode 100644 index 0000000..d8deb7a --- /dev/null +++ b/src/natlinkcore/SampleMacros/_sample_move_natlinktimer.py @@ -0,0 +1,234 @@ +# +# Python Macro Language for Dragon NaturallySpeaking +# (c) Copyright 1999 by Joel Gould +# Portions (c) Copyright 1999 by Dragon Systems, Inc. +# +# _sample_move_natlinktimer.py +# Sample macro file which implements keyboard movement modes +# similar to DragonDictate for Windows +# +# This uses a module natlinktimer (in natlinkcore). +# +# Start with: "start moving (up | down | left | right) +# Change direction and/or speed with "up faster", "down much slowere" etc. +# Stop with "stop" or by turning the microphone off. +# +# April 2022, adapting a little for python3 +# August 2024, try the new natlinktimer module, only for moving (QH, August 24) +#pylint:disable= C0206, E1101, R1730, R1731 +import time +import natlink +from natlinkcore.natlinkutils import * +from natlinkcore import natlinktimer + +# For caret movement, this represents the default speed in milliseconds +# between arrow keys + +defaultMoveSpeed = 250 + +# For caret movement, this is the rate change applied when you make it +# faster. For example, 1.5 is a 50% speed increase. + +moveRateChange = 2.0 + + +############################################################################ +# +# Here are some of our instance variables +# +# self.haveCallback set when the timer callback in installed +# self.curMode 1 for caret movement, or None +# self.curSpeed current movement speed (milliseconds for timer) +# self.lastClock time of last timer callback or 0 +# self.curDirection direction of movement as string +# + + +class ThisGrammar(GrammarBase): + + # when we unload the grammar, we must make sure we clear the timer + # callback so we keep a variable which is set when we currently own + # the timer callback + + def __init__(self): + self.haveCallback = 0 + self.curMode = None + self.iconState = 0 + GrammarBase.__init__(self) + + def unload(self): + # if self.haveCallback: + # # natlinktimer.setTimerCallback(testGram.doTimerClassic, interval=testGram.interval, callAtMicOff=testGram.cancelMode, debug=debug) + # natlink.setTimerCallback(None,0) + # self.haveCallback = 0 + GrammarBase.unload(self) + + # This is our grammar. The rule 'start' is what is normally active. The + # rules 'nowMoving' and 'nowMousing' are used when we are in caret or + # mouse movement mode. + + gramDefn = """ + # this is the rule which is normally active + exported = ; + + # this rule is active when we are moving the caret + exported = + [ move ] ( {direction} | steady | fast | slow | [much] faster | [much] slower ) | + stop [ moving ]; + + # here are the subrules which deal with caret movement + = start moving {direction}; + + """ + + # These are the lists which we use in our grammar. The directions and + # counts are implemented as lists to make parsing easier (words from + # lists are referenced as part of the rule which includes the list). + + listDefn = { + 'direction' : ['up','down','left','right'], + } + + # Load the grammar, build the direction and count lists and activate the + # main rule ('start') + + def initialize(self): + self.load(self.gramDefn) + for listName in self.listDefn: + self.setList(listName,self.listDefn[listName]) + self.activateSet(['start'],exclusive=0) + + # This subroutine cancels any active movement mode + + def cancelMode(self): + self.curMode = None + if self.haveCallback: + natlink.setTimerCallback(None,0) + self.haveCallback = 0 + self.activateSet(['start'],exclusive=0) + # natlink.setTrayIcon() + + # This function is called on a timer event. If we are in a movement + # mode then we move the mouse or caret by the indicated amount. + # + # The apparent speed for mouse movement is the speed divided by the + # number of pixels per move. We calculate the number of pixels per + # move to ensure that the speed is never faster than 50 milliseconds. + + def onTimer(self): + if self.lastClock: + diff = int( (time.time() - self.lastClock) * 1000 ) + self.lastClock = time.time() + if self.curMode == 1: + moduleInfo = natlink.getCurrentModule() + if natlink.getMicState() == 'on' and moduleInfo == self.moduleInfo: + # self.setTrayIcon(1) + # Note: it is often during a playString operation that the + # "stop moving" command occurs + natlink.playString('{'+self.curDirection+'}') + else: + self.cancelMode() + + # This handles the startMoving rule. We only need to extract the + # direction. To turn on cursor movement mode we need to install a + # timer callback (warning: this is global) and set the recognition + # state to be exclusively from the rule . The cursor only + # moves in the timer callback itself. + + def gotResults_startMoving(self,words,fullResults): + self.cancelMode() + direction = findKeyWord(words,self.listDefn['direction']) + self.curMode = 1 + self.curDirection = direction + # self.setTrayIcon(0) + self.moduleInfo = natlink.getCurrentModule() + self.curSpeed = defaultMoveSpeed + self.lastClock = time.time() + self.timer = natlinktimer.createGrammarTimer(self.onTimer, self.curSpeed, callAtMicOff=self.cancelMode) + self.timer.start() + # print(f'started timer: {self.timer} with interval ') + self.haveCallback = 1 + self.activateSet(['nowMoving'],exclusive=1) + + # This handles the nowMoving rule. We want to extract the keyword which + # tells us what to do. + + def gotResults_nowMoving(self,words,fullResults): + direction = findKeyWord(words,self.listDefn['direction']) + if direction: + print(f'change direction to {direction}') + self.curDirection = direction + self.timer.start() + # self.setTrayIcon(0) + if 'stop' in words: + self.cancelMode() + return + + speed = self.curSpeed + if 'normal' in words or 'steady' in words: + speed = defaultMoveSpeed + elif 'fast' in words: + speed = int(defaultMoveSpeed / moveRateChange) + elif 'slow' in words: + speed = int(defaultMoveSpeed * moveRateChange) + elif 'faster' in words: + speed = int(self.curSpeed / moveRateChange) + if 'much' in words: + speed = int(speed / moveRateChange) + if speed < 50: + speed = 50 + elif 'slower' in words: + speed = int(self.curSpeed * moveRateChange) + if 'much' in words: + speed = int(speed * moveRateChange) + if speed > 4000: + speed = 4000 + + + if self.curSpeed == speed: + return + self.curSpeed = speed + self.timer.start(self.curSpeed) + + # # This turns on the tray icon depending on the movement direction. + # # self.iconState is used to toggle the image to animate the icon. + # def setTrayIcon(self,toggleIcon): + # iconName = self.curDirection + # toolTip = 'moving '+self.curDirection + # if not toggleIcon or self.iconState: + # self.iconState = 0 + # else: + # self.iconState = 1 + # iconName = iconName + '2' + # # natlink.setTrayIcon(iconName,toolTip,self.onTrayIcon) + + # This is called if the user clicks on the tray icon. We simply cancel + # movement in all cases. + # def onTrayIcon(self,message): + # self.cancelMode() + +# This is a simple utility subroutine. It takes two lists of words and +# returns the first word it finds which is in both lists. We use this to +# extract special words (like the direction) from recognition results. + +def findKeyWord(list1,list2): + for word in list1: + if word in list2: + return word + return None + +# +# Here is the initialization and termination code. See wordpad.py for more +# comments. +# + +thisGrammar = ThisGrammar() +thisGrammar.initialize() + +def unload(): + #pylint:disable=W0603 + global thisGrammar + if thisGrammar: + thisGrammar.unload() + thisGrammar = None + From 6b7776bcea6d3bc186449cfa169fea47341d4389 Mon Sep 17 00:00:00 2001 From: Quintijn Hoogenboom Date: Sat, 10 Aug 2024 15:48:01 +0200 Subject: [PATCH 21/25] changes to loader.py, message when NATLINK_SETTINGSDIR is defined. --- src/natlinkcore/loader.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/natlinkcore/loader.py b/src/natlinkcore/loader.py index ad60f6b..85b5f31 100644 --- a/src/natlinkcore/loader.py +++ b/src/natlinkcore/loader.py @@ -1,4 +1,5 @@ -#pylint:disable=C0114, C0115, C0116, R1705, R0902, R0904, R0911, R0912, R0915, W0703, E1101, W1203 +#pylint:disable=C0114, C0115, C0116, R1705, R0902, R0904, R0911, R0912, R0915, W0703, E1101, W1203, W0719 +#pylint:disable=R1710, W0603 import importlib import importlib.machinery import importlib.util @@ -514,6 +515,11 @@ def set_user_language(self, args: Any = None): def start(self) -> None: self.logger.info(f'Starting natlink loader from config file:\n\t"{self.config.config_path}"') + nsd = os.getenv('natlink_settingsdir') + if nsd: + self.logger.info('\t(You set environment variable "NATLINK_SETTINGSDIR")') + + natlink.active_loader = self # checking for default config location (probably when no natlinkconfig_gui has been run) @@ -688,7 +694,6 @@ def startDap(config : NatlinkConfig) -> bool: Exception {ee} while starting DAP in {__file__}. Possible cause is incorrect python executable specified {python_exec} """ ) - def run() -> None: default_logger=logging.getLogger("natlink") dh = OutputDebugStringHandler() From 3702eeee15fcf9d230986bf70edcbbda1288f661 Mon Sep 17 00:00:00 2001 From: Quintijn Hoogenboom Date: Sat, 10 Aug 2024 15:48:36 +0200 Subject: [PATCH 22/25] changing dependencies for dtactions 1.6.2 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 1eaf8ea..548e11e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,7 +11,7 @@ readme = "readme.md" dependencies= [ "FreeSimpleGUI>=5.1.0", "pydebugstring >= 1.0.0.1", - "dtactions>=1.6.1", + "dtactions>=1.6.2", "platformdirs >= 4.2.0" ] classifiers=[ From 061932a3ae824e4ae95fb4918231e856f3868290 Mon Sep 17 00:00:00 2001 From: Quintijn Hoogenboom Date: Sat, 10 Aug 2024 15:49:40 +0200 Subject: [PATCH 23/25] going to pip release 5.4.0 --- src/natlinkcore/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/natlinkcore/__init__.py b/src/natlinkcore/__init__.py index 47e6b1f..9172caf 100644 --- a/src/natlinkcore/__init__.py +++ b/src/natlinkcore/__init__.py @@ -1,6 +1,6 @@ '''Python portion of Natlink, a compatibility module for Dragon Naturally Speaking The python stuff including test modules''' -__version__="5.3.13" +__version__="5.4.0" #pylint:disable= from pathlib import Path From 1ce5a686553a6373eb353e4f4b01eda5ed07d621 Mon Sep 17 00:00:00 2001 From: Quintijn Hoogenboom Date: Thu, 22 Aug 2024 17:26:32 +0200 Subject: [PATCH 24/25] several last changes, and bump to 5.4.1 --- documentation/modules.rst | 2 ++ src/natlinkcore/__init__.py | 2 +- src/natlinkcore/config.py | 2 +- src/natlinkcore/natlinkstatus.py | 42 +++++++++++++++++++++++++------- tests/buttonclicktest.py | 2 +- 5 files changed, 38 insertions(+), 12 deletions(-) diff --git a/documentation/modules.rst b/documentation/modules.rst index f880302..7266694 100644 --- a/documentation/modules.rst +++ b/documentation/modules.rst @@ -8,5 +8,7 @@ This section includes the available modules in the natlink project config loader natlinkstatus + natlinktimer + readwritefile \ No newline at end of file diff --git a/src/natlinkcore/__init__.py b/src/natlinkcore/__init__.py index 9172caf..ddb6976 100644 --- a/src/natlinkcore/__init__.py +++ b/src/natlinkcore/__init__.py @@ -1,6 +1,6 @@ '''Python portion of Natlink, a compatibility module for Dragon Naturally Speaking The python stuff including test modules''' -__version__="5.4.0" +__version__="5.4.1" #pylint:disable= from pathlib import Path diff --git a/src/natlinkcore/config.py b/src/natlinkcore/config.py index d4c2cd1..062a91d 100644 --- a/src/natlinkcore/config.py +++ b/src/natlinkcore/config.py @@ -1,4 +1,4 @@ -#pylint:disable=C0114, C0115, C0116, R0913, E1101, R0911, R0914, W0702 +#pylint:disable=C0114, C0115, C0116, R0913, E1101, R0911, R0914, W0702, R0912, C0209 import sys import configparser import logging diff --git a/src/natlinkcore/natlinkstatus.py b/src/natlinkcore/natlinkstatus.py index 8cd2512..9b59b21 100644 --- a/src/natlinkcore/natlinkstatus.py +++ b/src/natlinkcore/natlinkstatus.py @@ -326,9 +326,10 @@ def unimacroIsEnabled(self): uuDir = self.getUnimacroUserDirectory() if not uuDir: return False - # ugDir = uuDir # only _control self.getUnimacroGrammarsDirectory() + + # ugDir = self.getUnimacroGrammarsDirectory() # if not (ugDir and isdir(ugDir)): - # print(f'UnimacroGrammarsDirectory ({ugDir}) not present, please create') + # print(f'UnimacroGrammarsDirectory ({ugDir}) is not present, should be a subdirectory "unimacrogrammars" of {uDir}, please (re)run your pip install unimacro command, of rerun the "Configure Natlink with GUI" or "Configure Natlink with CLI"') # return False return True @@ -362,6 +363,8 @@ def getNatlinkIni(self): raise OSError(f'getNatlinkIni: not a valid file: "{path}"') return path + getnatlinkini = getNatlinkIni + def getNatlink_Settingsdir(self): """get the directory where "natlink.ini" should be stored @@ -378,6 +381,8 @@ def getNatlink_Settingsdir(self): return str(natlink_settings_dir) + getnatlink_settingsdir = getNatlink_Settingsdir + def getUnimacroUserDirectory(self): isdir, abspath = os.path.isdir, os.path.abspath if self.UnimacroUserDirectory is not None: @@ -400,7 +405,7 @@ def getUnimacroUserDirectory(self): self.UnimacroUserDirectory = '' return '' - + getunimacrouserdirectory = getUnimacroUserDirectory def getUnimacroDirectory(self): """return the path to the UnimacroDirectory @@ -419,6 +424,9 @@ def getUnimacroDirectory(self): self.UnimacroDirectory = unimacro.__path__[-1] return self.UnimacroDirectory + getunimacrodirectory = getUnimacroDirectory + + def getUnimacroGrammarsDirectory(self): """return the path to the UnimacroGrammarDirectory @@ -442,6 +450,8 @@ def getUnimacroGrammarsDirectory(self): self.UnimacroGrammarsDirectory = um_grammars_dir return um_grammars_dir + getunimacrogrammarsdirectory = getUnimacroGrammarsDirectory + def getUnimacroDataDirectory(self): """return the path to the directory where grammars can store data. @@ -451,6 +461,8 @@ def getUnimacroDataDirectory(self): """ if self.UnimacroDataDirectory is not None: return self.UnimacroDataDirectory + if not self.unimacroIsEnabled(): + return '' natlink_settings_dir = self.getNatlink_Settingsdir() @@ -461,16 +473,22 @@ def getUnimacroDataDirectory(self): self.UnimacroDataDirectory = um_data_dir return um_data_dir + + getunimacrodatadirectory = getUnimacroDataDirectory def getNatlinkDirectory(self): """return the path of the NatlinkDirectory, where the _natlink_core.pyd package (C++ code) is """ return self.NatlinkDirectory + getnatlinkdirectory = getNatlinkDirectory + def getNatlinkcoreDirectory(self): """return the path of the natlinkcore package directory, same as thisDir! """ return self.NatlinkcoreDirectory + getnatlinkcoredirectory = getNatlinkcoreDirectory + def getUserDirectory(self): """return the path to the Natlink User directory @@ -500,7 +518,8 @@ def getUserDirectory(self): print('invalid path for UserDirectory: "{value}"') self.UserDirectory = '' return '' - + getuserdirectory = getUserDirectory + def getDragonflyDirectory(self): """return the path to the DragonflyDirectory @@ -519,7 +538,7 @@ def getDragonflyDirectory(self): self.DragonflyDirectory = str(Path(dragonfly2.__file__).parent) return self.DragonflyDirectory - + getdragonflydirectory = getDragonflyDirectory def getDragonflyUserDirectory(self): @@ -550,7 +569,7 @@ def getDragonflyUserDirectory(self): print('invalid path for DragonflyUserDirectory: "{value}"') self.DragonflyUserDirectory = '' return '' - + getdragonflyuserdirectory = getDragonflyUserDirectory def getVocolaUserDirectory(self): @@ -576,6 +595,8 @@ def getVocolaUserDirectory(self): print(f'invalid path for VocolaUserDirectory: "{value}" (expanded: "{expanded}")') self.VocolaUserDirectory = '' return '' + getvocolauserdirectory = getVocolaUserDirectory + def getVocolaDirectory(self): if self.VocolaDirectory is not None: @@ -588,7 +609,7 @@ def getVocolaDirectory(self): return '' self.VocolaDirectory = vocola2.__path__[-1] return self.VocolaDirectory - + getvocoladirectory = getVocolaDirectory def getVocolaGrammarsDirectory(self): """return the VocolaGrammarsDirectory, but only if Vocola is enabled @@ -611,6 +632,7 @@ def getVocolaGrammarsDirectory(self): voc_grammars_dir = natlinkcore.config.expand_path(value) self.VocolaGrammarsDirectory = voc_grammars_dir return voc_grammars_dir + getvocolagrammarsdirectory = getVocolaGrammarsDirectory def getDtactionsDirectory(self): """dtactions directory should be found with an import (like getUnimacroDirectory) @@ -625,10 +647,12 @@ def getDtactionsDirectory(self): return "" self.DtactionsDirectory = dtactions.__path__[-1] return self.DtactionsDirectory + getdtactionsdirectory = getDtactionsDirectory + def getAhkUserDir(self): return self.getAhkUserDirFromIni() - + getahkuserdir = getAhkUserDir def getAhkUserDirFromIni(self): isdir, abspath = os.path.isdir, os.path.abspath @@ -655,7 +679,7 @@ def getAhkExeDir(self): if not self.AhkExeDir is None: return self.AhkExeDir return self.getAhkExeDirFromIni() - + getahkexedir = getAhkExeDir def getAhkExeDirFromIni(self): isdir, abspath = os.path.isdir, os.path.abspath diff --git a/tests/buttonclicktest.py b/tests/buttonclicktest.py index ded28b0..bfb53ff 100644 --- a/tests/buttonclicktest.py +++ b/tests/buttonclicktest.py @@ -5,7 +5,7 @@ # the "ESP" error is hit. # When Dragon is running, it freezes, and must be closed with the windows task manager - +# with release 5.5.7 this should be OK, because PlayEvents has been disabled. import natlink from natlinkcore import natlinkutils From 0e68c77b0dced8006fee2f3b1941c9b4ed23d4e8 Mon Sep 17 00:00:00 2001 From: Quintijn Hoogenboom Date: Thu, 22 Aug 2024 17:30:53 +0200 Subject: [PATCH 25/25] updated dependency: dtactions 1.6.3 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 548e11e..1d986fb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,7 +11,7 @@ readme = "readme.md" dependencies= [ "FreeSimpleGUI>=5.1.0", "pydebugstring >= 1.0.0.1", - "dtactions>=1.6.2", + "dtactions>=1.6.3", "platformdirs >= 4.2.0" ] classifiers=[