Writing a new script in the script library and I want to change a session property inside of it. There’s no drop down selector to pick a property. How can I reference the session property from a script library? Do I need to pass a reference to self?
You must pass what you need as function arguments. This is true in Perspective, in Vision, and in any gateway events.
Ok I thought session props were analogous to tags, and in Vision I didn’t have to pass anything as long as I knew the tag path I could just do a system.tag.read() on the path.
So there is nothing to replace Client tags in 8.0? I have almost 100 functions defined in a script library and want to change the database they point to based on the plant selected. I have a session property that does this for everything else but I can’t use it at the beginning of the script library? I would have to pass it into each function separately.
In theory, the InternalSession.SESSION
ThreadLocal
would be populated if you’re running a project script from a Perspective thread; so something like this might work:
from com.inductiveautomation.perspective.gateway.session import InternalSession
session = InternalSession.SESSION.get()
if session is not None:
system.perspective.print(session.custom.something)
Hah! And I thought I was bad about exposing unsupported and undocumented implementation details… (:
Definitely true. Phil's suggestion to pass explicit parameters is the only non-magic way to do this. And I don't want any PMs about this thread in three years when we end up breaking someone's code
Ok so the way to do it would be something like
def myFunc(self):
self.session.custom.myCustomProp = 1
or to use your undocumented method and then DM you in a few years when it breaks right?
I get how this would work with hardcoded custom session properties I know exists, but say I want to read/write to a dynamic one like
def myFunc2(self, propertyName):
#How would I read the session prop
#How would I write to it?
Use Python’s getattr
builtin; the following examples will both achieve the same result:
x = self.session.custom.myCustomProp
x = getattr(self.session.custom, "myCustomProp")
The corresponding reverse function would be setattr
:
setattr(self.session.custom, "myCustomProp", 1)
You really should reconsider passing self or session.self to your script libraries, except maybe to helpers to extract specific blocks of Perspective data or to re-encode (json) results for Perspective’s use.
For any script module function, ask yourself if the core logic would be applicable outside Perspective, other than the mechanics of obtaining the arguments and returning a useful result. If so, make it generic, just in case you need to use in in Vision or maybe in WebDev for some future project. Separate the Perspective-specific code from the rest.
I was planning on making getter/setter functions with using undocumented way to try to do that. But, if I want to do it in a fully documented way, and I need to pass the necessary info, and I shouldn’t pass self, how would you recommend doing it? Won’t we at some point necessarily need a self so that we can get self.session etc?
Yes, pass self.session to your Perspective-specific helpers. Pass that result to your generic business/process logic. In simple cases, just do everything needed with self in the event.
Right - invert your assumptions. If you need to do something with session properties, then only assume you have a session object in your project script:
def doSomething(session):
session.custom.something = 123
And then call it with the shortcut to the session object you get from all perspective components:
if self.custom.doSomething:
project.library.doSomething(self.session)
Sticking to the self
nomenclature in project scripts is just making things more confusing than they need to be.
A post was split to a new topic: Global name 'self' is not defined in script
A long time later...
This line in a project script run from a Perspective component binding:
from com.inductiveautomation.perspective.gateway.session import InternalSession
bombs out saying ImportError: No module named perspective
All I want to do in the project script is to check if a user has a role, but without passing in self
, it seems exceedingly difficult And I don't really want to have to pass self
into 7 functions, since I'm only using it to do extra stuff if a user has the Developer
role.
What about using the system.util.getContext()
from the Extensions module?
The problem is the class loaders, I think. On the gateway, each module's classes are independent, so the execution of your script doesn't have access to Perspective internals.
You could, I guess, go from context to the module manager and ask it to resolve the class, which will go through all modules and attempt.
Hi @PGriffith I have got a really simple message handler and all I am wanting to do is to retrieve a custom parameter in session props and print it to the logger for the time being. Any chance you know what is happening here. I am assuming it is being returned as null and is stopping the rest of the code from executing. As without the line......
logger.info(Current)
the Navigation function is called. i simply just want to check that the correct value is being returned.
def onMessageReceived(self, payload):
Current = getattr(self.session.custom , "CurrentIndex")
logger = system.util.getLogger('logger')
logger.info(Current)
self.navigateTo(payload['type'], payload['path'], payload['params'])
return
Thanks
- you don't need to use
getattr
if you know the attribute name.
Just useself.session.custom.CurrentIndex
.
getattr
is useful if the property you want to get is dynamic, ie:
getattr(self.session.custom, payload.get('prop_name'))
- Even if it was
null
, it wouldn't stop the script. You're not using it anywhere that would cause an exception, and if it did, you'd have that exception in your logs. Logging anull
will just result in an empty message in your logs. - The
return
is useless and its indentation is wrong. Just remove it
What exactly is going wrong with your script ? You told us what you'd want to happen, but not what is actually happening.
Well, drop the misindented return statement for one.
The error is probably because logger arguments must be strings. Try logger.info(str(self.session.custom.CurrentIndex))
Note there's no need for getattr
if you know exactly what property you want at the time you're writing your code.
Thankyou @PGriffith, Very frustrating, turns out y value was correct in the first place so I didn't need the logger. Cheers