# Get current scope in scripting

**URL:** <https://forum.inductiveautomation.com/t/get-current-scope-in-scripting/55686>\
**Category:** General Discussion\
**Created:** [February 2, 2022, 9:35pm UTC](https://forum.inductiveautomation.com/t/get-current-scope-in-scripting/55686 "2022-02-02T21:35:03Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![kgamble](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/kgamble/32/8019_2.png) [@kgamble](https://forum.inductiveautomation.com/u/kgamble)\
**Post date:** [February 2, 2022, 9:35pm UTC](https://forum.inductiveautomation.com/t/get-current-scope-in-scripting/55686/1 "2022-02-02T21:35:03Z")

</div>

Is there a way to easily grab the current scope in scripting?

We have a lot of code that will either execute through normal python, tag event scripts, script console, or perspective scripts. And so we need to identify what scope we are in sometimes to verify how we want to handle a task.

I know that I can try to do things like import the gateway context, or do a perspective print, etc, but is there a more rigid test to see Current scope? (Understanding this will fail in normal python, but we can work around that)

---

<div class="post-metadata">

**Author:** ![Kevin.Herron](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/kevin.herron/32/7259_2.png) [@Kevin.Herron](https://forum.inductiveautomation.com/u/Kevin.Herron)\
**Post date:** [February 2, 2022, 9:49pm UTC](https://forum.inductiveautomation.com/t/get-current-scope-in-scripting/55686/2 "2022-02-02T21:49:32Z")

</div>

> [@Getting the context in which a function is running?](https://forum.inductiveautomation.com/t/getting-the-context-in-which-a-function-is-running/33977):
>
> Related to my question the other day - [Using importlib to run any function on the gateway?](http://forum.inductiveautomation.com/t/using-importlib-to-run-any-function-on-the-gateway/33915/10) Now with forms, I like to run a validation on the client side so that the window doesn’t close and the user has a chance to fix their mistakes. And if that validation runs fine, then it sends a message to the gateway to run the actual create script. However, I know it’s not enough to just validate client side, and I should run it on the gateway end as well to be safe in case someone is able to start run…

> [@Best methods for checking script scope](https://forum.inductiveautomation.com/t/best-methods-for-checking-script-scope/30201/2):
>
> Try this: def getScope(): """ Returns: scope (int): 0=Gateway, 1=Client, 2=Designer """ try: if system.util.getSystemFlags() & system.util.CLIENT\_FLAG: location = 1 elif system.util.getSystemFlags() & system.util.DESIGNER\_FLAG: location = 2 except AttributeError: # system.util.getSystemFlags() does not exist in gateway scope location = 0 return location (Source: [Which scope is my code running in?](http://forum.inductiveautomation.com/t/which-scope-is-my-code-running-in/15540/3))

> [@Which scope is my code running in?](https://forum.inductiveautomation.com/t/which-scope-is-my-code-running-in/15540/2):
>
> Hmm. Something like this (untested): from com.inductiveautomation.ignition.common.model import ApplicationScope scope = ApplicationScope.getGlobalScope() if (ApplicationScope.isClient(scope)): ... if (ApplicationScope.isDesigner(scope)): ... if (ApplicationScope.isGateway(scope)): ...

---

<div class="post-metadata">

**Author:** ![Kevin.Herron](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/kevin.herron/32/7259_2.png) [@Kevin.Herron](https://forum.inductiveautomation.com/u/Kevin.Herron)\
**Post date:** [February 2, 2022, 9:51pm UTC](https://forum.inductiveautomation.com/t/get-current-scope-in-scripting/55686/3 "2022-02-02T21:51:42Z")

</div>

Options 🙂

---

<div class="post-metadata">

**Author:** ![kgamble](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/kgamble/32/8019_2.png) [@kgamble](https://forum.inductiveautomation.com/u/kgamble)\
**Post date:** [February 2, 2022, 9:52pm UTC](https://forum.inductiveautomation.com/t/get-current-scope-in-scripting/55686/4 "2022-02-02T21:52:41Z")

</div>

Perfect! I guess I didnt search hard enough before I asked lol

---

<div class="post-metadata">

**Author:** ![kgamble](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/kgamble/32/8019_2.png) [@kgamble](https://forum.inductiveautomation.com/u/kgamble)\
**Post date:** [February 2, 2022, 10:01pm UTC](https://forum.inductiveautomation.com/t/get-current-scope-in-scripting/55686/5 "2022-02-02T22:01:37Z")

</div>

My preferred option is probably this one

```python

try:
    from com.inductiveautomation.ignition.common.model import ApplicationScope
    scope = ApplicationScope.getGlobalScope()

    if (ApplicationScope.isClient(scope)):
	    print("Client Scope")

    if (ApplicationScope.isDesigner(scope)):
	    print("Designer Scope")
	
    if (ApplicationScope.isGateway(scope)):
        try:
            system.perspective.print("Perspective Scope")
        except:
	    print("Gateway Scope")
except:
    print("Python Scope")

```

---

<div class="post-metadata">

**Author:** ![bschroeder](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/bschroeder/32/13260_2.png) [@bschroeder](https://forum.inductiveautomation.com/u/bschroeder)\
**Post date:** [February 2, 2022, 11:50pm UTC](https://forum.inductiveautomation.com/t/get-current-scope-in-scripting/55686/6 "2022-02-02T23:50:38Z")

</div>

We’ve got this in a script called env

```auto
from com.inductiveautomation.ignition.common.model import ApplicationScope

scope = ApplicationScope.getGlobalScope()

def isDesigner():
	return ApplicationScope.isDesigner(scope)

def isGateway():
	return ApplicationScope.isGateway(scope)
	
def isPerspective():
	return ApplicationScope.isGateway(scope) and hasattr(system,'perspective')

def isVision():
	return ApplicationScope.isClient(scope)

```

Then call it with env.isGateway() etc…

---

<div class="post-metadata">

**Author:** ![hunterdg](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/hunterdg/32/67774_2.png) [@hunterdg](https://forum.inductiveautomation.com/u/hunterdg)\
**Post date:** [October 25, 2023, 5:17pm UTC](https://forum.inductiveautomation.com/t/get-current-scope-in-scripting/55686/7 "2023-10-25T17:17:55Z")

</div>

any suggestions on how to make isPerspective() return false when called from a _session_ property? In designer and otherwise?

Do I need to combine this method with SYSTEM\_FLAGS?

e.g. when modifying a session property in designer (with change script):

```auto
def valueChanged(self, previousValue, currentValue, origin, missedEvents):
	import inspect
	from com.inductiveautomation.ignition.common.model import ApplicationScope
	
	logger = system.util.getLogger(inspect.currentframe().f_code.co_name)
	logger.info('test Property Change Script scope')
	logger.info('isDesigner | {!s}'.format(env.isDesigner()))
	logger.info('isGateway | {!s}'.format(env.isGateway()))
	logger.info('isPerspective | {!s}'.format(env.isPerspective()))
	logger.info('toCode | {}'.format(ApplicationScope.toCode(ApplicationScope.getGlobalScope())))
	logger.info("hasattr('system,'perspective') | {!s}".format(hasattr(system,'perspective')))
	system.perspective.print('test') # returns 'No perspective page attached to this thread'

```

> test Property Change Script scope  
> isDesigner | False  
> isGateway | True  
> isPerspective | True  
> toCode | G  
> hasattr('system,'perspective') | True  
> ERROR: 'No perspective page attached to this thread'

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [October 25, 2023, 5:33pm UTC](https://forum.inductiveautomation.com/t/get-current-scope-in-scripting/55686/8 "2023-10-25T17:33:03Z")

</div>

Theoretically, something like this should work:

```python
from com.inductiveautomation.ignition.gateway import IgnitionGateway

pageModel = IgnitionGateway.get().moduleManager.resolveClass("com.inductiveautomation.perspective.gateway.model.PageModel")

if pageModel.PAGE.get() is not None:
	# in a page

```

Subject to change between Ignition versions and Perspective module versions; class names should be considered an implementation detail.

What's the ultimate use case for this kind of introspection?

---

<div class="post-metadata">

**Author:** ![hunterdg](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/hunterdg/32/67774_2.png) [@hunterdg](https://forum.inductiveautomation.com/u/hunterdg)\
**Post date:** [October 25, 2023, 5:38pm UTC](https://forum.inductiveautomation.com/t/get-current-scope-in-scripting/55686/9 "2023-10-25T17:38:39Z")

</div>

thank you, I'll give it a shot.

for the moment I'm just using it for context-aware debugging (printing where possible/desired, logging where not). comments/suggestions welcome.

FWIW, I'm fully aware logging alone is the preferred method 🙂

---

<div class="post-metadata">

**Author:** ![hunterdg](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/hunterdg/32/67774_2.png) [@hunterdg](https://forum.inductiveautomation.com/u/hunterdg)\
**Post date:** [October 25, 2023, 6:41pm UTC](https://forum.inductiveautomation.com/t/get-current-scope-in-scripting/55686/10 "2023-10-25T18:41:11Z")

</div>

it appears `isPresent()` is java-specific?

`hasattr(pageModel, 'PAGE')` returns True for me as well 😕

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [October 25, 2023, 6:50pm UTC](https://forum.inductiveautomation.com/t/get-current-scope-in-scripting/55686/11 "2023-10-25T18:50:21Z")

</div>

PageModel is the class. The `PAGE` attribute will always be present because it's a `ThreadLocal` field:

> **[PageModel](https://files.inductiveautomation.com/sdk/javadoc/ignition81/8.1.33/com/inductiveautomation/perspective/gateway/model/PageModel.html#PAGE)**
>
> declaration: package: com.inductiveautomation.perspective.gateway.model, class: PageModel

I steered you wrong with `isPresent()` because it's available in the JDK source code, which is what I was looking at for the class, but it's a package-private method that won't be accessible. The `get()` method is public: [https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/ThreadLocal.html#get()](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/ThreadLocal.html#get())

So `if pageModel.PAGE.get() is not None:` would be the equivalent operation and should work.

---

<div class="post-metadata">

**Author:** ![hunterdg](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/hunterdg/32/67774_2.png) [@hunterdg](https://forum.inductiveautomation.com/u/hunterdg)\
**Post date:** [January 12, 2024, 5:49pm UTC](https://forum.inductiveautomation.com/t/get-current-scope-in-scripting/55686/12 "2024-01-12T17:49:22Z")

</div>

anyone have success getting custom code/module/component/binding/etc scripting/context tracebacks as well as Ignition does with native logger/console exceptions?

end goal is to never have to specify a logger "name" in `system.util.getLogger()` - i just want it to know exactly where it is - all the way down to the component/script/function name - from wherever I call it

here's my (super-hacky) variation of @bschroeder's [code](https://forum.inductiveautomation.com/t/get-current-scope-in-scripting/55686/6):

> **env**
>
> ```python
> # https://forum.inductiveautomation.com/t/get-current-scope-in-scripting/55686/6
> from com.inductiveautomation.ignition.common.model import ApplicationScope
> 
> scope = ApplicationScope.getGlobalScope()
> 
> def isDesigner():
> return ApplicationScope.isDesigner(scope)
> 
> def isGateway():
> return ApplicationScope.isGateway(scope)
> 
> def isPerspective():
> # https://forum.inductiveautomation.com/t/get-current-scope-in-scripting/55686/8
> # https://forum.inductiveautomation.com/t/get-current-scope-in-scripting/55686/11
> try:
> from com.inductiveautomation.ignition.gateway import IgnitionGateway
> pageModel = IgnitionGateway.get().moduleManager.resolveClass("com.inductiveautomation.perspective.gateway.model.PageModel")
> return ApplicationScope.isGateway(scope) and hasattr(system,'perspective') and pageModel.PAGE.get() is not None
> except: return False
> 
> def isPerspectiveAsync():
> # https://forum.inductiveautomation.com/t/get-current-scope-in-scripting/55686/8
> # https://forum.inductiveautomation.com/t/get-current-scope-in-scripting/55686/11
> try:
> from com.inductiveautomation.ignition.gateway import IgnitionGateway
> pageModel = IgnitionGateway.get().moduleManager.resolveClass("com.inductiveautomation.perspective.gateway.model.PageModel")
> return ApplicationScope.isGateway(scope) and hasattr(system,'perspective') and pageModel.PAGE.get() is None
> except: return False
> 
> def isVision():
> return ApplicationScope.isClient(scope)
> 
> def getScopeCode():
> return ApplicationScope.toCode(scope)
> 
> class util:
> class getLogger:
> '''
> EXAMPLE:
> 
> import inspect
> 
> logger = env.util.getLogger('{!s}.{!s}.{!s}'.format(self.name, __name__ ,inspect.currentframe().f_code.co_name))
> try:
> #code here
> logger.info('message')
> except Exception as e: logger.info(e)
> 
> '''
> def __init__ (self, name):
> self.name = name
> 
> def __getattr__ (self, name):
> def overload(message=''):
> string = "{} {} - {}".format(name.upper(), self.name, message)
> if isPerspective(): system.perspective.print(string)
> elif isGateway():
> logger = system.util.getLogger(self.name)
> eval('logger.{}'.format(name))(message)
> elif isDesigner() or isVision(): print(string)
> return overload
> 
> ```

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [January 12, 2024, 5:56pm UTC](https://forum.inductiveautomation.com/t/get-current-scope-in-scripting/55686/13 "2024-01-12T17:56:39Z")

</div>

Basically, no, there's no great way to do so at the moment.  
I filed a ticket a few months ago to make sure that we're adding context where we have it, probably via the ` __file__ ` or ` __name__ ` or something standard variables.

---

<div class="post-metadata">

**Author:** ![hunterdg](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/hunterdg/32/67774_2.png) [@hunterdg](https://forum.inductiveautomation.com/u/hunterdg)\
**Post date:** [January 12, 2024, 6:26pm UTC](https://forum.inductiveautomation.com/t/get-current-scope-in-scripting/55686/14 "2024-01-12T18:26:19Z")

</div>

thanks! at least now I know I can stop trying for a while and just watch the release notes

---

<div class="post-metadata">

**Author:** ![richardNZ15](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/richardnz15/32/33373_2.png) [@richardNZ15](https://forum.inductiveautomation.com/u/richardNZ15)\
**Post date:** [July 22, 2024, 9:15pm UTC](https://forum.inductiveautomation.com/t/get-current-scope-in-scripting/55686/15 "2024-07-22T21:15:53Z")

</div>

> [@hunterdg](#):
>
> `pageModel = IgnitionGateway.get().moduleManager.resolveClass("com.inductiveautomation.perspective.gateway.model.PageModel")`

Will this help distinguish between a proper Perspective session (ie: button on a Perspective View calling a function) and a function being called from a Perspective session but via an **asynchronous thread**. ?

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [July 22, 2024, 9:25pm UTC](https://forum.inductiveautomation.com/t/get-current-scope-in-scripting/55686/16 "2024-07-22T21:25:08Z")

</div>

> [@richardNZ15](#):
>
> asynchronous thread

The asynchronous thread will not have the thread local for the page.

---

<div class="post-metadata">

**Author:** ![richardNZ15](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/richardnz15/32/33373_2.png) [@richardNZ15](https://forum.inductiveautomation.com/u/richardNZ15)\
**Post date:** [July 22, 2024, 9:30pm UTC](https://forum.inductiveautomation.com/t/get-current-scope-in-scripting/55686/17 "2024-07-22T21:30:51Z")

</div>

Yep perfect, I've run a few tests and it is working much better with that in now.

---

<div class="post-metadata">

**Author:** ![nminchin](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/nminchin/32/6911_2.png) [@nminchin](https://forum.inductiveautomation.com/u/nminchin)\
**Post date:** [May 8, 2025, 1:49am UTC](https://forum.inductiveautomation.com/t/get-current-scope-in-scripting/55686/18 "2025-05-08T01:49:06Z")

</div>

There are a number of topics about this, with this being the only topic that works to distinguish between gateway and perspective 🙂 thanks @paul-griffith and @hunterdg

I've incorporated this into @Kyle_Chase 's script from [this topic](https://forum.inductiveautomation.com/t/best-methods-for-checking-script-scope/30201/2):

```python
from com.inductiveautomation.ignition.common.model import ApplicationScope
try:
	from com.inductiveautomation.ignition.gateway import IgnitionGateway
	isGateway = True
except ImportError:
	isGateway = False

def getScope():
	scope = ApplicationScope.getGlobalScope()
	
	if ApplicationScope.isClient(scope):
		return "vision"

	elif ApplicationScope.isDesigner(scope):
		return "designer"

	elif ApplicationScope.isGateway(scope):
		pageModel = IgnitionGateway.get().moduleManager.resolveClass("com.inductiveautomation.perspective.gateway.model.PageModel")
		if pageModel.PAGE.get() is not None:
			return "perspective"
		return "gateway"
	
	else:
		raise ValueError("Could not resolve execution scope!")

```

Edit:  
This is simpler from [Can I tell what scope a script is running from? - #9 by Michael\_Lindon](https://forum.inductiveautomation.com/t/can-i-tell-what-scope-a-script-is-running-from/70880/9)

```python
def getScope():
	scope = ApplicationScope.getGlobalScope()
	if ApplicationScope.isClient(scope):
		return "c" # vision client

	if ApplicationScope.isDesigner(scope):
		return "d" # designer

	if ApplicationScope.isGateway(scope):
		try:
			system.perspective.getProjectInfo()
			return "p"
		except:
			return "g"
	return "u" # unknown

```

---

<div class="post-metadata">

**Author:** ![hunterdg](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/hunterdg/32/67774_2.png) [@hunterdg](https://forum.inductiveautomation.com/u/hunterdg)\
**Post date:** [May 8, 2025, 2:59am UTC](https://forum.inductiveautomation.com/t/get-current-scope-in-scripting/55686/19 "2025-05-08T02:59:01Z")

</div>

credit to @paul-griffith above for sure.

FWIW this breaks in perspective session startup scripts as `page` isn’t initialized yet (and it’s asynchronous as discussed up a few posts). I added an`isPerspectiveStartup()` function as well. Probably should’ve called it isPerspectiveAsync().

This might be another candidate for a wiki-style post as we refine/consolidate.

---

<div class="post-metadata">

**Author:** ![mdemaris](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/mdemaris/32/54639_2.png) [@mdemaris](https://forum.inductiveautomation.com/u/mdemaris)\
**Post date:** [June 24, 2026, 4:59pm UTC](https://forum.inductiveautomation.com/t/get-current-scope-in-scripting/55686/20 "2026-06-24T16:59:11Z")

</div>

Can you share this function?

[Next page](https://forum.inductiveautomation.com/t/get-current-scope-in-scripting/55686.md?page=2)
