diff --git a/pyproject.toml b/pyproject.toml index f6cdeba..df49a5d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -40,6 +40,9 @@ dev = [ [project.entry-points."natlink.grammars"] unimacro_builtins = "unimacro.UnimacroGrammars:locateme" +[project.entry-points."natlink.loggers"] + unimacro ="unimacro:logname" + [tool.pytest.ini_options] minversion = "7.1.2" addopts = "--capture=tee-sys " diff --git a/src/unimacro/__init__.py b/src/unimacro/__init__.py index ef1de61..3cc4b30 100644 --- a/src/unimacro/__init__.py +++ b/src/unimacro/__init__.py @@ -1,11 +1,15 @@ """Unimacro __init__ -Provides a logger for logging throughout unimacro. Use this instead of a global logger of the 'natlink' root logger. -This lets us set the levels for unimacro differently for debugging, if desired. + +Note there will be a global variable created in the unimacro module 'ulogger' which is Logging.Logger object named 'natlink.unimacro' +You can always access it by name. It is created in _control.py. + """ import os import sys -from .logger import unimacro_logger +def logname() -> str: + """ Returns the name of the unimacro logger.""" + return "natlink.unimacro" __version__ = '4.1.4.2' diff --git a/src/unimacro/_control.py b/src/unimacro/_control.py index 3b870f8..5f87157 100644 --- a/src/unimacro/_control.py +++ b/src/unimacro/_control.py @@ -25,11 +25,23 @@ from dtactions.unimacro import unimacroactions as actions from unimacro import natlinkutilsbj as natbj -from unimacro import spokenforms, unimacro_logger +from unimacro import spokenforms +import importlib.metadata as meta +#from unimacro.logger import ulogger status = natlinkstatus.NatlinkStatus() natlinkmain = loader.NatlinkMain() +#a global logger for unimacro. perfectly reasonable to access by name instead. +import logging as l + +#for some reason, importing amodule which does this doesn't work. Likely because natlinkmain must be started first for +#this sublogger natlink.unimacro to work correctly. +import unimacro as unimacro_l #bring in so we can add a variable ulogger to the namespace. +ulogger : l.Logger = l.getLogger("natlink.unimacro") +unimacro_l.__dict__['ulogger']=ulogger +ulogger.debug("natlink.unimacro logger available") + tracecount = list(map(str, list(range(1, 10)))) # #Constants for the UtilGrammar @@ -43,9 +55,38 @@ # showAll = 1 # reset if no echo of exclusive commands is wished +def natlink_loggers() ->dict: + """ + returns dictionary, keys are the names of the module to show to users (or for them to use in dication), + values are the string names of the loggers. + For example, {'unimacro':'natlink.unimacro'}. + Any python module/package/etc. can enable their own logger by defining an entry point in group 'natlink.loggers'. + The entry point must be a function that returns a logger name. Is the Python 'logging' module. + + """ + + + discovered_eps=meta.entry_points(group='natlink.loggers') + ulogger.debug(f"Entry Points for natlink.loggers: {discovered_eps}") + loggers=dict() + for ep in discovered_eps: + try: + (name,_)=ep + ulogger.debug(f"Entry Point {ep}") + f=ep.load() + logname=f() + loggers[name]=logname + except Exception as e: + ulogger.error(f"Attempting to load EntryPoint {ep},error\n {e}") + return loggers + ancestor = natbj.IniGrammar class UtilGrammar(ancestor): language = status.get_language() + + loggers=natlink_loggers() + ulogger.debug(f"Control: Available Loggers {loggers}") + loggers_names=sorted(loggers.keys()) iniIgnoreGrammarLists = ['gramnames', 'tracecount', 'message'] # are set in this module name = 'control' @@ -57,6 +98,7 @@ class UtilGrammar(ancestor): # if spokenforms: ## assume spokenforms is imported!!! specialList.append("'spoken forms'") + specialList.append("loggers") if specialList: specials = "|" + '|'.join(specialList) else: @@ -74,7 +116,7 @@ class UtilGrammar(ancestor): gramDict['resetexclusive'] = """ exported = reset (exclusive | exclusive grammars);""" gramDict['checkalphabet'] = """ exported = check alphabet;""" gramDict['message'] = """ exported = {message};""" - gramDict['setlogging'] = """ exported = (global|unimacro) loglevel ;""" + gramDict['setlogging'] = """ exported = {logmodulename} loglevel ;""" gramDict['loglevel'] = " = (debug|info|warning|error|critical);" @@ -98,7 +140,7 @@ class UtilGrammar(ancestor): ((on|off| {tracecount})("""+ specials2 +""")) | (("""+ specials2 +""") (on|off|{tracecount}))) ;""" # gramSpec.append(traceSpecial) # add trace for actions of spoken forms (latter not implemented) - print('check, correct _control?????') + ulogger.info('check, correct _control?????') Mode = Normal LastMode = Normal @@ -109,6 +151,7 @@ def initialize(self): # temp set allResults to 0, disabling the messages trick: if not self.load(self.gramSpec, allResults=showAll): return + self.setList('logmodulename',self.loggers_names) self.RegisterControlObject(self) self.emptyList('message') # at post load @@ -120,12 +163,10 @@ def initialize(self): self.activateAll() self.setMode(Normal) self.startExclusive = self.exclusive # exclusive state at start of recognition! - self.loglevel_for = None - self.current_loglevel = None ## if unimacroutils.getUser() == 'martijn': ## print 'martijn, set exclusive %s'% self.name ## self.setExclusive(1) - print('---now starting other Unimacro grammars:') + ulogger.info('---now starting other Unimacro grammars:') def unload(self): @@ -184,7 +225,7 @@ def gotResults_checkalphabet(self,words,fullResults): for letter in string.ascii_lowercase: spoken = ini.get(alph, letter, '') if not spoken: - print('fill in in "%s_spokenform.ini", [alphabet] spoken for: "%s"'% (self.language, letter)) + ulogger.info('fill in in "%s_spokenform.ini", [alphabet] spoken for: "%s"'% (self.language, letter)) continue if version < 11: normalform = '%s\\%s'% (letter.upper(), spoken) @@ -193,7 +234,7 @@ def gotResults_checkalphabet(self,words,fullResults): try: natlink.recognitionMimic([normalform]) except natlink.MimicFailed: - print('invalid spoken form "%s" for "%s"'% (spoken, letter)) + ulogger.info('invalid spoken form "%s" for "%s"'% (spoken, letter)) if spoken == spoken.lower(): spoken = spoken.capitalize() trying = 'try capitalized variant' @@ -209,15 +250,15 @@ def gotResults_checkalphabet(self,words,fullResults): try: natlink.recognitionMimic([normalform]) except natlink.MimicFailed: - print('%s fails also: "%s" for "%s"'% (trying, spoken, letter)) + ulogger.info('%s fails also: "%s" for "%s"'% (trying, spoken, letter)) else: - print('alphabet section is corrected with: "%s = %s"'% (letter, spoken)) + ulogger.info('alphabet section is corrected with: "%s = %s"'% (letter, spoken)) ini.set(alph, letter, spoken) ini.writeIfChanged() def gotResults_trace(self,words,fullResults): - print('control, trace: %s'% words) + ulogger.info('control, trace: %s'% words) traceNumList = self.getNumbersFromSpoken(words) # returns a string or None if traceNumList: traceNum = int(traceNumList[0]) @@ -236,7 +277,7 @@ def gotResults_trace(self,words,fullResults): else: actions.debugActions(1) elif self.hasCommon(words, 'spoken forms'): - print("no tracing possible for spoken forms") + ulogger.info("no tracing possible for spoken forms") #def gotResults_voicecode(self,words,fullResults): # """switch on if requirements are fulfilled @@ -280,7 +321,7 @@ def gotResults_switch(self,words,fullResults): self.switch(gram, gname, switchOn) # self never needs switching on else: - print('_control switch, no valid grammar found, command: %s'% words) + ulogger.info('_control switch, no valid grammar found, command: %s'% words) def switch(self, gram, gname, switchOn): """switch on or off grammar, and set in inifile, @@ -289,7 +330,7 @@ def switch(self, gram, gname, switchOn): switchOn is True or False """ if gram == self: - print(f'should not be here, do not switch on of off _control {gram}') + ulogger.error(f'should not be here, do not switch on of off _control {gram}') return None if switchOn: if gram.ini: @@ -298,16 +339,16 @@ def switch(self, gram, gname, switchOn): gram.ini.write() unimacroutils.Wait(0.1) else: - print(f'--- ini file of grammar {gname} is invalid, please try "edit {gname}"...') + ulogger.error(f'--- ini file of grammar {gname} is invalid, please try "edit {gname}"...') gramName = gram.getName() unimacro_grammars_paths = self.getUnimacroGrammarNamesPaths() try: filepath = Path(unimacro_grammars_paths[gramName]) except KeyError: - print(f'_control, grammar not in unimacro_grammars_paths dict: {gramName}, cannot switchOn') + ulogger.error(f'_control, grammar not in unimacro_grammars_paths dict: {gramName}, cannot switchOn') return None # now reload with force option. - print(f'_control, now reload grammar "{gramName}":') + ulogger.info(f'_control, now reload grammar "{gramName}":') natlinkmain.seen.clear() natlinkmain.load_or_reload_module(filepath, force_load=True) @@ -319,25 +360,33 @@ def switch(self, gram, gname, switchOn): gram.cancelMode() gram.deactivateAll() # gram.unload() - print('grammar "%s" switched off'% gram.getName()) + ulogger.info('grammar "%s" switched off'% gram.getName()) return 1 def gotResults_setlogging(self,words, fullresults): """ """ - unimacro_logger.info("gotResults_logging_level words: {words} fullResults: {fullresults}") - self.loglevel_for = words[0] # global or unimacro + ulogger.debug(f"unimacro logger gotResults_logging_level words: {words} fullResults: {fullresults}") - def gotResults_loglevel(self,words,fullresults): + loglevel_for = words[0] # something like natlink, unimacro,... + new_level_str_mc,_=fullresults[-1] + new_log_level_str=new_level_str_mc.upper() + #the string should be in the + logger_name=self.loggers[loglevel_for] + new_log_level=l.__dict__[new_log_level_str] + + ulogger.debug(f"New Log Level {new_log_level_str} for logger {logger_name}") + logger=l.getLogger(logger_name) + logger.setLevel(new_log_level) + + + + +#Hide numbers def gotResults_loglevel(self,words,fullresults): """ """ - unimacro_logger.info("gotResults_logging_level words: {words} fullResults: {fullresults}") - new_loglevel = words[-1] - if self.current_loglevel == new_loglevel: - unimacro_logger.info('loglevel for "%s" is already: "%s"'% (self.loglevel_for, new_loglevel)) - return - print(f'setting loglevel "{new_loglevel}" for "{self.loglevel_for}"') - ##TODO Doug + ulogger.debug(f"gotResults_logging_level words: {words} fullResults: {fullresults}") + return def gotResults_showexclusive(self,words,fullResults): @@ -349,7 +398,7 @@ def gotResults_showexclusive(self,words,fullResults): else: Start=() # fix state at this moment (in case of Active grammars popup) - print(f'_control, showexclusive, exclusiveGrammars: {natbj.exclusiveGrammars}') + ulogger.info(f'_control, showexclusive, exclusiveGrammars: {natbj.exclusiveGrammars}') if natbj.exclusiveGrammars: Exclusive = 1 self.BrowsePrepare(Start, All, Exclusive) @@ -373,7 +422,7 @@ def gotResults_showexclusive(self,words,fullResults): def gotResults_resetexclusive(self,words,fullResults): - print('reset exclusive') + ulogger.info('reset exclusive') exclGrammars = natbj.getExclusiveGrammars() if exclGrammars: T = ['exclusive grammars:'] @@ -412,14 +461,17 @@ def gotResults_show(self,words,fullResults): if self.hasCommon(words, 'exclusive'): G = self.getExclusiveGrammars() exclNames = [gname for gname, gram in G.items() if gram.isExclusive()] - print(f'exclusive grammars (+ control) are: {exclNames}') + ulogger.info(f'exclusive grammars (+ control) are: {exclNames}') self.gotResults_showexclusive(words, fullResults) return + if self.hasCommon(words,"loggers"): + ulogger.info(f"Available Loggers: {self.loggers}") + return grammars = self.getUnimacroGrammars() gramNames = list(grammars.keys()) - # print(f'_control, gramNames: {gramNames}') + ulogger.debug(f'_control, gramNames: {gramNames}') gramName = self.hasCommon(words, gramNames) if gramName: grammar = grammars[gramName] @@ -464,9 +516,9 @@ def gotResults_show(self,words,fullResults): activeGrammars = [g for g in G if G[g].isActive()] inactiveGrammars = [g for g in G if G[g].isLoaded() and not G[g].isActive()] switchedOffGrammars = [g for g in G if not G[g].isLoaded()] - print(f'activeGrammars: {activeGrammars}') - print(f'inactiveGrammars: {inactiveGrammars}') - print(f'switchedOffGrammars: {switchedOffGrammars}') + ulogger.info(f'activeGrammars: {activeGrammars}') + ulogger.info(f'inactiveGrammars: {inactiveGrammars}') + ulogger.info(f'switchedOffGrammars: {switchedOffGrammars}') # for grammar_name, gram in G.items(): # print(f'grammar_name: {grammar_name}, gram: {gram}') @@ -537,7 +589,7 @@ def gotResults_edit(self,words,fullResults): try: grammar = grammars[gramName] except KeyError: - print(f'grammar {words[-1:]} not found in list of gramNames:\n{gramNames}') + ulogger.error(f'grammar {words[-1:]} not found in list of gramNames:\n{gramNames}') return # print(f'grammar: {gramName}: {grammar}') if self.hasCommon(words, 'grammar'): @@ -546,9 +598,9 @@ def gotResults_edit(self,words,fullResults): try: filepath = unimacro_grammars_paths[gramName] except KeyError: - print(f'grammar not in unimacro_grammars_paths dict: {gramName}') + ulogger.error(f'grammar not in unimacro_grammars_paths dict: {gramName}') return - print(f'open for edit file: "{filepath}"') + ulogger.info(f'open for edit file: "{filepath}"') self.openFileDefault(filepath, mode="edit", name=f'edit grammar {gramName}') else: # edit the inifile @@ -562,7 +614,7 @@ def switchOff(self, **kw): """overload, this grammar never switches off """ - print('remains switched on: %s' % self) + ulogger.info('remains switched on: %s' % self) def switchOn(self, **kw): """overload, just switch on @@ -622,7 +674,7 @@ def getUnimacroGrammarNamesPaths(self): unimacro_modules[name] = try_file break else: - print(f'not found in natlink_modules_files: {name}') + ulogger.info(f'not found in natlink_modules_files: {name}') unimacro_modules[name] = name # not found return unimacro_modules diff --git a/src/unimacro/logger.py b/src/unimacro/logger.py deleted file mode 100644 index 97c2ccd..0000000 --- a/src/unimacro/logger.py +++ /dev/null @@ -1,5 +0,0 @@ -import logging - -# use this logger for logging -unimacro_logger=logging.Logger("natlink.unimacro") -