Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve import natlink #41

Merged
merged 24 commits into from
Dec 22, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
4da0ee2
Merge pull request #1 from dictation-toolbox/main
dougransom Aug 25, 2022
bab94ea
Merge branch 'main' of github.com:dougransom/natlinkcore
quintijn Oct 24, 2022
642b04b
bump to 1.5.6
quintijn Oct 27, 2022
0c2d65c
sorry previous bump number was wrong (the branch name so to say, whic…
quintijn Oct 27, 2022
78f87a7
correct import natlink lines
quintijn Nov 14, 2022
28af081
improved expand_path function. Also sub directories of a packages are…
quintijn Nov 27, 2022
772b3c7
why was this one lost??
quintijn Nov 27, 2022
16bb5d2
fixing details (directory is last item of module.__path__ (when packa…
quintijn Nov 27, 2022
4a8662d
added module natlinktimer (multiplexing natlink.setTimerCallback), an…
quintijn Dec 1, 2022
de953da
rename test script to test_natlinktimer.py
quintijn Dec 1, 2022
856e7e0
typo natlinkstatus.py, improved and tested (a bit) natlinktimer
quintijn Dec 3, 2022
8d80a38
work on natlinktimer, with (nearly) old calling method it seems to work.
quintijn Dec 7, 2022
48c7ecd
working on natlinktimer, add callback at mic off in loader
quintijn Dec 9, 2022
c2b8079
natlinktimer.py passes test
quintijn Dec 18, 2022
3a0681d
tidying up some print lines natlinktimer.py, seems to work well now.
quintijn Dec 20, 2022
5b7c700
checkpoint
dougransom Dec 21, 2022
8be8ce9
removed incorrect return statement
dougransom Dec 21, 2022
5cf9d32
removed useless blank line
dougransom Dec 21, 2022
54b64e0
added extension enumeration to config cli
dougransom Dec 21, 2022
703d091
tweaked imports
dougransom Dec 21, 2022
26796a6
improve natlinktimer, when mic switches off!
quintijn Dec 21, 2022
275c089
Merge branch 'improve_import_natlink' of github.com:dougransom/natlin…
quintijn Dec 21, 2022
fdc97ae
check lines in the cancelMode routine of test grammar of natlinktimer.
quintijn Dec 22, 2022
ccff278
Merge branch 'main' into improve_import_natlink
quintijn Dec 22, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions build_natlinkcore.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#powershell to run the tests, then build the python package.
$ErrorActionPreference = "Stop"
pytest --capture=tee-sys
flit build --format sdist
4 changes: 4 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,12 @@ testpaths= [

[project.scripts]
natlinkconfig_cli = "natlinkcore.configure.natlinkconfig_cli:main_cli"
natlink_extensions = "natlinkcore.configure.natlink_extensions:main"
[project.gui-scripts]
natlinkconfig_gui = "natlinkcore.configure.natlinkconfig_gui:main_gui"

[project.entry-points.natlink_extensions]
natlink_sample_macros = "natlinkcore.SampleMacros:locateme"

[project.urls]
Home = "https://github.com/dictation-toolbox/natlinkcore/"
2 changes: 2 additions & 0 deletions src/natlinkcore/SampleMacros/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
def locateme():
return __path__[0]
2 changes: 1 addition & 1 deletion src/natlinkcore/SampleMacros/_debug_natlink.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"""
#pylint:disable=W0611, W0613, C0115, C0116

from natlink import _natlink_core as natlink
import natlink
from natlinkcore import natlinkpydebug as pd
from natlinkcore import natlinkutils
from natlinkcore import gramparser as gp
Expand Down
4 changes: 4 additions & 0 deletions src/natlinkcore/SampleMacros/_sample_callback.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,16 @@ def post_load_callback(self):
print('------- post_load_callback')
def on_mic_on_callback(self):
print('------- on_mic_on_callback')
def on_mic_off_callback(self):
print('------- on_mic_off_callback')
def on_begin_utterance_callback(self):
print('------- on_begin_utterance_callback')

thisGrammar = ThisGrammar()
thisGrammar.initialize()
natlinkmain.set_on_begin_utterance_callback(thisGrammar.on_begin_utterance_callback)
natlinkmain.set_on_mic_on_callback(thisGrammar.on_mic_on_callback)
natlinkmain.set_on_mic_off_callback(thisGrammar.on_mic_off_callback)
natlinkmain.set_pre_load_callback(thisGrammar.pre_load_callback)
natlinkmain.set_post_load_callback(thisGrammar.post_load_callback)

Expand All @@ -36,6 +39,7 @@ def unload():
if thisGrammar:
natlinkmain.delete_on_begin_utterance_callback(thisGrammar.on_begin_utterance_callback)
natlinkmain.delete_on_mic_on_callback(thisGrammar.on_mic_on_callback)
natlinkmain.delete_on_mic_off_callback(thisGrammar.on_mic_off_callback)
natlinkmain.delete_pre_load_callback(thisGrammar.pre_load_callback)
natlinkmain.delete_post_load_callback(thisGrammar.post_load_callback)
# extraneous deletes do not harm:
Expand Down
31 changes: 21 additions & 10 deletions src/natlinkcore/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from enum import IntEnum
from typing import List, Iterable, Dict
from pathlib import Path
from natlink import _natlink_core as natlink
import natlink

class NoGoodConfigFoundException(natlink.NatError):
pass
Expand Down Expand Up @@ -143,7 +143,7 @@ def expand_path(input_path: str) -> str:

Paths can be:

- the name of a python package, to be found along sys.path (typically in site-packages)
- 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
- ~/...: the home directory
- some environment variable: this environment variable is expanded.
Expand Down Expand Up @@ -180,15 +180,26 @@ def expand_path(input_path: str) -> str:
print(f'natlink_userdir does not expand to a valid directory: "{nud}"')
return normpath(nud)

if not (input_path.find('/') >= 0 or input_path.find('\\') >= 0):

# try if package:
if input_path.find('/') > 0:
package_trunk, rest = input_path.split('/', 1)
elif input_path.find('\\') > 0:
package_trunk, rest = input_path.split('\\', 1)
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__(input_path)
except ModuleNotFoundError:
print(f'expand_path, package name "{input_path}" is not found')
return input_path
return pack.__path__[0]

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

env_expanded = expandvars(input_path)
# print(f'env_expanded: "{env_expanded}", from envvar: "{input_path}"')
return normpath(env_expanded)
Expand Down
1 change: 1 addition & 0 deletions src/natlinkcore/configure/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from natlinkcore.configure.natlink_extensions import extensions_and_folders
29 changes: 29 additions & 0 deletions src/natlinkcore/configure/natlink_extensions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
"""Command Line Program to List Advertised Natlink Exensions."""
import sys
from importlib.metadata import entry_points
import argparse

def extensions_and_folders():
discovered_extensions=entry_points(group='natlink_extensions')

for extension in discovered_extensions:
n=extension.name
ep=extension.value
try:
pathfn=extension.load()
path=pathfn()

except Exception as e:
path = e
yield n,path


def main():
parser=argparse.ArgumentParser(description="Enumerate natlink extension momdules.")
args=parser.parse_args()
for n,path in extensions_and_folders():
print(f"{n} {path}")
return 0

if '__main__' == __name__:
main()
12 changes: 11 additions & 1 deletion src/natlinkcore/configure/natlinkconfig_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import cmd
import os
import os.path
from natlinkcore.configure import extensions_and_folders

from natlinkcore.configure import natlinkconfigfunctions

Expand All @@ -18,7 +19,7 @@ def _main(Options=None):
"""
cli = CLI()
cli.Config = natlinkconfigfunctions.NatlinkConfig()
shortOptions = "DVNOHKaAiIxXbBuq"
shortOptions = "DVNOHKaAiIxXbBuqe"
shortArgOptions = "d:v:n:o:h:k:"
if Options:
if isinstance(Options, str):
Expand Down Expand Up @@ -129,6 +130,8 @@ def usage(self):
[AutoHotkey]
h/H - set/clear the AutoHotkey exe directory.
k/K - set/clear the User Directory for AutoHotkey scripts.
[Extensions]
e - give a list of python modules registered as extensions.
[Other]

u/usage - give this list
Expand All @@ -153,6 +156,13 @@ def do_j(self, arg):

self.Config.printPythonPath()

def do_e(self,arg):
print("extensions and folders for registered natlink extensions:")
ef=""
for n,f in extensions_and_folders():
ef+= f"\n{n} {f}"
print(ef)

def help_i(self):
print('-'*60)
print("""The command info (i) gives an overview of the settings that are
Expand Down
12 changes: 11 additions & 1 deletion src/natlinkcore/loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
from types import ModuleType
from typing import List, Dict, Set, Iterable, Any, Tuple, Callable

from natlink import _natlink_core as natlink
import natlink
from natlinkcore.config import LogLevel, NatlinkConfig, expand_path
from natlinkcore.readwritefile import ReadWriteFile
from natlinkcore.callbackhandler import CallbackHandler
Expand Down Expand Up @@ -65,6 +65,7 @@ def __init__(self, logger: Any=None, config: Any = None):
self._pre_load_callback = CallbackHandler('pre_load')
self._post_load_callback = CallbackHandler('post_load')
self._on_mic_on_callback = CallbackHandler('on_mic_on')
self._on_mic_off_callback = CallbackHandler('on_mic_off')
self._on_begin_utterance_callback = CallbackHandler('on_begin_utterance')
self.seen: Set[Path] = set() # start empty in trigger_load
self.bom = self.encoding = self.config_text = '' # getconfigsetting and writeconfigsetting
Expand All @@ -76,6 +77,9 @@ def set_on_begin_utterance_callback(self, func: Callable[[], None]) -> None:
def set_on_mic_on_callback(self, func: Callable[[], None]) -> None:
self._on_mic_on_callback.set(func)

def set_on_mic_off_callback(self, func: Callable[[], None]) -> None:
self._on_mic_off_callback.set(func)

def set_pre_load_callback(self, func: Callable[[], None]) -> None:
self._pre_load_callback.set(func)

Expand All @@ -88,6 +92,9 @@ def delete_on_begin_utterance_callback(self, func: Callable[[], None]) -> None:
def delete_on_mic_on_callback(self, func: Callable[[], None]) -> None:
self._on_mic_on_callback.delete(func)

def delete_on_mic_off_callback(self, func: Callable[[], None]) -> None:
self._on_mic_off_callback.delete(func)

def delete_pre_load_callback(self, func: Callable[[], None]) -> None:
self._pre_load_callback.delete(func)

Expand Down Expand Up @@ -401,6 +408,9 @@ def on_change_callback(self, change_type: str, args: Any) -> None:

if self.config.load_on_mic_on:
self.trigger_load()
elif change_type == 'mic' and args == 'off':
self.logger.debug('on_change_callback called with: "mic", "off"')
self._on_mic_off_callback.run()
else:
self.logger.debug(f'on_change_callback unhandled: change_type: "{change_type}", args: "{args}"')

Expand Down
48 changes: 34 additions & 14 deletions src/natlinkcore/natlinkstatus.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,15 +57,18 @@
Also users that have their own custom grammar files can use this user directory

getUnimacroDirectory: get the directory where the Unimacro system is.
When git cloned, relative to the Core directory, otherwise somewhere or in the site-packages (if pipped). This grammar will (and should) hold the _control.py grammar
and needs to be included in the load directories list of James' natlinkmain
This directory is normally in the site-packages area of Python (name "unimacro"), but can be
"linked" to your cloned source code when you installed the packages with "pip install -e ."

getUnimacroGrammarsDirectory: get the directory, where the user can put his Unimacro grammars. This directory will be
located in the `ActiveGrammars` subdirectory of the `~/.unimacro' or `%NATLINK_USERDIR%/.unimacro`).

getUnimacroUserDirectory: get the directory of Unimacro INI files, if not return '' or
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

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
grammar _vocola_main.py.
Expand Down Expand Up @@ -120,7 +123,6 @@
"esp": "may\xfas"}

thisDir, thisFile = os.path.split(__file__)
thisDirSymlink = natlinkcore.getThisDir(__file__)

class NatlinkStatus(metaclass=singleton.Singleton):
"""this class holds the Natlink status functions.
Expand All @@ -138,7 +140,7 @@ class NatlinkStatus(metaclass=singleton.Singleton):
'vocoladirectory', 'vocolagrammarsdirectory']

def __init__(self):
"""initialise all instance variables, in this singleton class, hoeinstance
"""initialise all instance variables, in this singleton class, (only one instance)
"""
self.natlinkmain = natlinkmain # global
self.DNSVersion = None
Expand All @@ -152,6 +154,7 @@ def __init__(self):
self.UnimacroDirectory = None
self.UnimacroUserDirectory = None
self.UnimacroGrammarsDirectory = None
self.UnimacroDataDirectory = None
## Vocola:
self.VocolaUserDirectory = None
self.VocolaDirectory = None
Expand All @@ -165,10 +168,9 @@ def __init__(self):
self.symlink_line = ''

if self.NatlinkDirectory is None:
self.NatlinkDirectory = natlink.__path__[0]
self.NatlinkcoreDirectory = thisDirSymlink # equal to thisDir if no symlinking is there.
if thisDirSymlink != thisDir:
self.symlink_line = f'NatlinkcoreDirectory is symlinked, for developing purposes.\n\tFiles seem to be in "{thisDirSymlink}",\n\tbut they can be edited in "{thisDir}".\n\tWhen debugging files from this directory, open and set breakpoints in files in the first (site-packages) directory!'
self.NatlinkDirectory = natlink.__path__[-1]
if len(natlinkcore.__path__) > 0:
self.symlink_line = 'NatlinkcoreDirectory is editable'

def refresh(self):
"""rerun the __init__, refreshing all variables
Expand Down Expand Up @@ -399,10 +401,30 @@ def getUnimacroDirectory(self):
except ImportError:
self.UnimacroDirectory = ""
return ""
self.UnimacroDirectory = str(Path(unimacro.__file__).parent)
self.UnimacroDirectory = unimacro.__path__[-1]
return self.UnimacroDirectory


def getUnimacroDataDirectory(self):
"""return the path to the directory where grammars can store data.

Expected in "UnimacroData" of the natlink user directory
(November 2022)

"""
if self.UnimacroDataDirectory is not None:
return self.UnimacroDataDirectory

natlink_user_dir = self.getNatlink_Userdir()

um_data_dir = Path(natlink_user_dir)/'UnimacroData'
if not um_data_dir.is_dir():
um_data_dir.mkdir()
um_data_dir = str(um_data_dir)
self.UnimacroDataDirectory = um_data_dir

return um_data_dir

def getUnimacroGrammarsDirectory(self):
"""return the path to the directory where the ActiveGrammars of Unimacro are located.

Expand Down Expand Up @@ -539,7 +561,6 @@ def getVocolaUserDirectory(self):
return ''

def getVocolaDirectory(self):
isdir, isfile, join, abspath = os.path.isdir, os.path.isfile, os.path.join, os.path.abspath
if self.VocolaDirectory is not None:
return self.VocolaDirectory

Expand All @@ -548,7 +569,7 @@ def getVocolaDirectory(self):
except ImportError:
self.VocolaDirectory = ''
return ''
self.VocolaDirectory = str(Path(vocola2.__file__).parent)
self.VocolaDirectory = vocola2.__path__[-1]
return self.VocolaDirectory


Expand Down Expand Up @@ -693,7 +714,7 @@ def getNatlinkStatusDict(self):
for key in ['DNSIniDir', 'WindowsVersion', 'DNSVersion',
'PythonVersion',
'DNSName', 'NatlinkIni', 'Natlink_Userdir',
'UnimacroDirectory', 'UnimacroUserDirectory', 'UnimacroGrammarsDirectory',
'UnimacroDirectory', 'UnimacroUserDirectory', 'UnimacroGrammarsDirectory', 'UnimacroDataDirectory',
'VocolaDirectory', 'VocolaUserDirectory', 'VocolaGrammarsDirectory',
'VocolaTakesLanguages', 'VocolaTakesUnimacroActions',
'UserDirectory',
Expand Down Expand Up @@ -726,7 +747,6 @@ def getNatlinkStatusString(self):
L = []
D = self.getNatlinkStatusDict()
if self.symlink_line:
L.append('--- warning:')
L.append(self.symlink_line)
L.append('--- properties:')
self.appendAndRemove(L, D, 'user')
Expand Down Expand Up @@ -766,7 +786,7 @@ def getNatlinkStatusString(self):
## Unimacro:
if D['unimacroIsEnabled']:
self.appendAndRemove(L, D, 'unimacroIsEnabled', "---Unimacro is enabled")
for key in ('UnimacroUserDirectory', 'UnimacroDirectory', 'UnimacroGrammarsDirectory'):
for key in ('UnimacroUserDirectory', 'UnimacroDirectory', 'UnimacroGrammarsDirectory', 'UnimacroDataDirectory'):
self.appendAndRemove(L, D, key)
else:
self.appendAndRemove(L, D, 'unimacroIsEnabled', "---Unimacro is disabled")
Expand Down
Loading