Ideas to store add-on state.


Pawel Urbanski
 

Dear Everyone,
Since I still occasionally use Visual Studio Code and nobody followed
up with my request to take over the development, I am working on
updating the add-on.
I am looking for hints and inspiration on how to best keep add-on
state. It does not need to be saved but needs to work when the
application is running. I use it to store some add-on flags and state.
Is there anything in NVDA api like this or maybe you cane up with a
working way to share global state. There is the configuration class
but I don't know if it can be made local to the add-on running
instance in the scope of the AppModule class - please treat this
example as explanatory not in terms of working code.

Thank you for any hints...
Pawel


James Scholes
 

If you have state that only needs to be utilised during the add-on's runtime, and not persisted, I would just store it on the AppModule or GlobalPlugin instance:

class AppModule(appModuleHandler.AppModule):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._someStateFlag = False
self._someOtherStateFlag = 14
# or
self._state = {'flag1': False, 'flag2': 14}

Is there a reason why this wouldn't be sufficient?

Regards,

James Scholes

On 21/06/2022 at 11:20, Pawel Urbanski wrote:
Dear Everyone,
Since I still occasionally use Visual Studio Code and nobody followed
up with my request to take over the development, I am working on
updating the add-on.
I am looking for hints and inspiration on how to best keep add-on
state. It does not need to be saved but needs to work when the
application is running. I use it to store some add-on flags and state.
Is there anything in NVDA api like this or maybe you cane up with a
working way to share global state. There is the configuration class
but I don't know if it can be made local to the add-on running
instance in the scope of the AppModule class - please treat this
example as explanatory not in terms of working code.

Thank you for any hints...
Pawel





Pawel Urbanski
 

Thank you for the suggestion. I decided to go the 'appModule' instance
route. This time, I did it properly with the super method and
inheritance and so on.
Unfortunately Pylance of VS Code kept throwing errors about missing
type when parsing the expression of:
self.appModule.InstanceVariableName
I guess it is due to different capitalization and the fact that
'appModule' with a small 'a' is a runtime property of classes in the
add-on runtime.

All in all, things are working well and I even managed to remove that
code part but still use instance variables for other cases.

I posted about the updated VS Code add-on. Thank you once again.

Best,
Pawel

On 6/21/22, James Scholes <james@...> wrote:
If you have state that only needs to be utilised during the add-on's
runtime, and not persisted, I would just store it on the AppModule or
GlobalPlugin instance:

class AppModule(appModuleHandler.AppModule):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._someStateFlag = False
self._someOtherStateFlag = 14
# or
self._state = {'flag1': False, 'flag2': 14}

Is there a reason why this wouldn't be sufficient?

Regards,

James Scholes

On 21/06/2022 at 11:20, Pawel Urbanski wrote:
Dear Everyone,
Since I still occasionally use Visual Studio Code and nobody followed
up with my request to take over the development, I am working on
updating the add-on.
I am looking for hints and inspiration on how to best keep add-on
state. It does not need to be saved but needs to work when the
application is running. I use it to store some add-on flags and state.
Is there anything in NVDA api like this or maybe you cane up with a
working way to share global state. There is the configuration class
but I don't know if it can be made local to the add-on running
instance in the scope of the AppModule class - please treat this
example as explanatory not in terms of working code.

Thank you for any hints...
Pawel









Luke Davis
 

Pawel Urbanski wrote:

Unfortunately Pylance of VS Code kept throwing errors about missing
type when parsing the expression of:
self.appModule.InstanceVariableName
That does not seem to be what James suggested. Why do you think it's proper?
Specifically, wherefore the ".appModule" part of that construct?

I haven't looked at your code to see exactly how you're using that, but when assigning instance variables from within class methods for that instance you would not use ".appModule" as part of the construct.

James Scholes wrote:
self._someStateFlag = False
self._someOtherStateFlag = 14
# or
self._state = {'flag1': False, 'flag2': 14}

Luke


Luke Davis
 

Pawel Urbanski wrote:

Unfortunately Pylance of VS Code kept throwing errors about missing
type when parsing the expression of:
self.appModule.InstanceVariableName
After glancing at your code briefly [1], it seems that what you are trying to do
isn't to save runtime state data for an App Module, so much as you are trying to
access the state of an App Module from an associated overlay class. Do I
understand that correctly?

I am no expert on overlay classes, nor how they are supposed to communicate
state, but I think a better way to do this might be by way of some global
namespace.
Fortunately, NVDA provides one of those, called globalVars.

You import globalVars in each of your modules, and then can set state upon it,
and read state from it.

import globalVars
class AppModule(appModuleHandler.AppModule):
def __init__(self, *args, **kwargs):
# ...
globalVars.vscode = {}
globalVars.vscode["name"] = "myName"
# Or, if you don't need to bother with a dict
globalVars.vscodeName = "myName"

Then, in your other class, you can simply do:

if globalVars.vscodeName == "whatever":

There may be a more elegant way to reach outside the class scope to get at the
AppModule's state variables from an overlay that also doesn't generate a
compiler error, but this is one that should definitely work and is easy to read.

[1]:
https://github.com/accessifix/nvda-for-vs-code/releases/download/2022.1.0/nvda-for-vs-code-2022.1.0.nvda-addon

Luke


Pawel Urbanski
 

Thanks alot for that tip. I was thinking about GlobalVars but for some
reason made a lazy assumption that it is a dictionary of useful
values. It looks like it can be used in a more clever way.
I have some ideas to implement in a very near future so it will be a
good occasion to test the waters.

On 6/25/22, Luke Davis <luke@...> wrote:
Pawel Urbanski wrote:

Unfortunately Pylance of VS Code kept throwing errors about missing
type when parsing the expression of:
self.appModule.InstanceVariableName
After glancing at your code briefly [1], it seems that what you are trying
to do
isn't to save runtime state data for an App Module, so much as you are
trying to
access the state of an App Module from an associated overlay class. Do I
understand that correctly?

I am no expert on overlay classes, nor how they are supposed to communicate

state, but I think a better way to do this might be by way of some global
namespace.
Fortunately, NVDA provides one of those, called globalVars.

You import globalVars in each of your modules, and then can set state upon
it,
and read state from it.

import globalVars
class AppModule(appModuleHandler.AppModule):
def __init__(self, *args, **kwargs):
# ...
globalVars.vscode = {}
globalVars.vscode["name"] = "myName"
# Or, if you don't need to bother with a dict
globalVars.vscodeName = "myName"

Then, in your other class, you can simply do:

if globalVars.vscodeName == "whatever":

There may be a more elegant way to reach outside the class scope to get at
the
AppModule's state variables from an overlay that also doesn't generate a
compiler error, but this is one that should definitely work and is easy to
read.

[1]:
https://github.com/accessifix/nvda-for-vs-code/releases/download/2022.1.0/nvda-for-vs-code-2022.1.0.nvda-addon

Luke







Luke Davis
 

Pawel Urbanski wrote:

Thanks alot for that tip. I was thinking about GlobalVars but for some
reason made a lazy assumption that it is a dictionary of useful
values. It looks like it can be used in a more clever way.
globalVars (lower case g) is literally just a module. It has some variables of its own that NVDA itself uses for various things, but it is little more than a namespace that you can import and set things on.

Technically you could do that with anything, from one of NVDA's modules, to a Python core library, to an empty module of your own. But in NVDA contexts it is pretty much always imported, so makes an easily recognized storage platform to avoid using globals in your own module (which is another way you could handle this, although I wouldn't recommend that).

Luke


Doug Lee
 

I'm curious why using the globals module is better than having module-level variables in an add-on?
Intuitively, it feels odd to share a module's variables in a namespace used by other add-ons and NVDA itself.

On Fri, Jun 24, 2022 at 09:16:48PM -0400, Luke Davis wrote:
Pawel Urbanski wrote:

Thanks alot for that tip. I was thinking about GlobalVars but for some
reason made a lazy assumption that it is a dictionary of useful
values. It looks like it can be used in a more clever way.
globalVars (lower case g) is literally just a module. It has some variables of
its own that NVDA itself uses for various things, but it is little more than a
namespace that you can import and set things on.

Technically you could do that with anything, from one of NVDA's modules, to a
Python core library, to an empty module of your own. But in NVDA contexts it
is pretty much always imported, so makes an easily recognized storage platform
to avoid using globals in your own module (which is another way you could
handle this, although I wouldn't recommend that).

Luke

--
Doug Lee dgl@... http://www.dlee.org
"When there is no enemy within, the enemies outside cannot hurt you."
--African Proverb