Date
1 - 3 of 3
Recommendation to deal with NVDA's configurations in add-ons.
DaVid
Hi there.
Today I developed a small utility to deal with NVDA's settings in our add-ons. I really hate to write config.conf.['a1']['a2]['option'] each time I need to access, or set a value in the configuration. But was not a problem for me until now. I was merging a pr in one of my add-ons, I was a little asleep, and was very hard to find the error. Just a capital letter! And the editor usually don't help with autocompletion if we are writting inside ''. So, I thought... The config names and path should be declared in one part only, and access the configurations using that code. Then I decided to experiment with one of my mantained add-ons. This consist on a class and a very simple descriptor, to get and access the config. See this example: class appConfig: def __init__(self): # the path to the config. currently you can't use customized paths (for example to set it for each synthesizer) but is not hard to implement it. self.path = ['speechHistoryExplorer'] # if the following is true, will return the value. False, will return the configuration name. # is set to false to help creating the conspec. self.returnValue = False # now declaring some configurations, outside the constructor. # optConfig is the descriptor that does all the ting, but it doesn't matter to explain it. # you can use properties too, but is too repetitive. maxHistoryLength = OptConfig('maxHistoryLength') trimWhitespaceFromStart = OptConfig('trimWhitespaceFromStart') trimWhitespaceFromEnd = OptConfig('trimWhitespaceFromEnd') beepWhenPerformingActions = OptConfig('beepWhenPerformingActions') beepPanning = OptConfig('beepPanning') # now instantiate the class. appConfig = appConfig() # now, it will create the conspec. confspec = { appConfig.maxHistoryLength: 'integer(default=500)', appConfig.trimWhitespaceFromStart: 'boolean(default=false)', appConfig.trimWhitespaceFromEnd: 'boolean(default=false)', appConfig.beepWhenPerformingActions: 'boolean(default=true)', appConfig.beepPanning: 'boolean(default=true)', } # set the conspec to the config of NVDA. config.conf.spec[appConfig.path[0]] = confspec # now change returnValue to True, because usually we want the value of the config, not the name. appConfig.returnValue = True # Now, get or set a setting is so easy! just do the following: # get a copnfig: appConfig.maxHistoryLength # set a config: appConfig.maxHistoryLength = 250 and you can use the smart Autocomplete feature of vs code, for example. So, you will never make a mistake when refering to a config. And you can avoid to use those tedious ', [, etc each time you need to access a configuration. You can see the entire file here: https://github.com/davidacm/SpeechHistoryExplorer/blob/SPE/addon/globalPlugins/_config.py I'm open to suggestions. Regards, David. |
|
DaVid
Hi again. I decided to do all the stuff in a configHelper, so, now is
easier to define a conspec. and the options can be recognized by the ides without issues. I need to do more tests, but I like this way of declaring configurations specs for add-ons. Now, to declare a spec you can do the following, if you use this util. from ._configHelper import * class AppConfig(BaseConfig): def __init__(self): super().__init__('speechHistoryExplorer') # declaration of the options for the config. maxHistoryLength = OptConfig('integer(default=500)') trimWhitespaceFromStart = OptConfig('boolean(default=false)') trimWhitespaceFromEnd = OptConfig('boolean(default=true)') beepWhenPerformingActions = OptConfig('boolean(default=true)') beepPanning = OptConfig('boolean(default=true)') AF = registerConfig(AppConfig) And to acces or set a configuration: AF.beepPanning AF.beepPanning = True It can be improved a lot, but is enough for me. the config helper can be found here: https://raw.githubusercontent.com/davidacm/SpeechHistoryExplorer/SPE/addon/globalPlugins/speechHistoryExplorer/_configHelper.py |
|
DaVid
Hi there!.
Again, I added a small but big change to this utility to help dealing with the add-ons settings. Now, all the things can be done with a class decorator. But you can use the older whay if you want. see the complete information here: https://github.com/davidacm/NVDADevelopmentUtilities Let's see how easy is to write a spec now, and help to the ides to understand the configuration. All things declared in just one place. # first, import the utility. The decorator and the register config function. from ._configHelper import configSpec, registerConfig # now the class definition, with the decorator first. # this decorator will replace the attributes with a descriptor to manage accessing and updating values. @configSpec class AppConfig: # the config path. Important to call it __path__ = ... __path__ = 'beepKeyboard' # now the definition of the settings. in form of name = 'desc' beepUpperWithCapsLock = 'boolean(default=True)' beepCharacterWithShift = 'boolean(default=False)' beepToggleKeyChanges = 'boolean(default=False)' announceToggleStatus = 'boolean(default=True)' disableBeepingOnPasswordFields = 'boolean(default=True)' ignoredCharactersForShift = "string(default='\\x1b\\t\\b\\r ')" beepForCharacters = "string(default='')" shiftedCharactersTone = 'int_list(default=list(6000,10,25))' customCharactersTone = 'int_list(default=list(6000,10,25))' capsLockUpperTone = 'int_list(default=list(3000,40,50))' toggleOffTone = 'int_list(default=list(500,40,50))' toggleOnTone = 'int_list(default=list(2000, 40, 50))' AF = registerConfig(AppConfig) # accessing an option: print("this should print False", AF.disableBeepingOnPasswordFields) # changing the value: AF.disableBeepingOnPasswordFields = True # let's see the new value. print("this should print True", AF.disableBeepingOnPasswordFields) It can't be easier! I wish to use python typings to make the config description, and that would help to reduce typing errors. But for now, is enough for me. Although I think that this idea is perfectly possible. Saludos, David CM. 2022-07-30 5:26 GMT-06:00, DaVid via groups.io <dhf360@...>: |
|