Referencing a session prop from a script library?

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)
2 Likes

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 :slight_smile:

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? :sweat_smile:

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)

2 Likes

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.

1 Like

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.

2 Likes

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 :frowning: 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?

1 Like

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 use self.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 a null 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