# Checking for PyDocumentObjectAdapter

**URL:** <https://forum.inductiveautomation.com/t/checking-for-pydocumentobjectadapter/115499>\
**Category:** Ignition\
**Tags:** scripting, ignition81\
**Created:** [May 13, 2026, 2:05am UTC](https://forum.inductiveautomation.com/t/checking-for-pydocumentobjectadapter/115499 "2026-05-13T02:05:49Z")\
**Posts on this page:** 16\
**Page:** 1

<div class="post-metadata">

**Author:** ![drewdin](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/drewdin/32/3363_2.png) [@drewdin](https://forum.inductiveautomation.com/u/drewdin)\
**Post date:** [May 13, 2026, 2:05am UTC](https://forum.inductiveautomation.com/t/checking-for-pydocumentobjectadapter/115499/1 "2026-05-13T02:05:49Z")

</div>

I have a gateway script that is triggered by two different tags, one boolean and one document tag.

When the document tag is empty {}, I want to skip the functions. But the value I'm being returned is the PyDocumentObjectAdapter.

I tried both:

`if type(tagvalue) == 'com.inductiveautomation.ignition.common.script.adapters.PyDocumentObjectAdapter'`

`if type(tagvalue) == 'PyDocumentObjectAdapter'`

Is it possible to check for the PyDocumentAdaptor by type?

---

<div class="post-metadata">

**Author:** ![lrose](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/lrose/32/62724_2.png) [@lrose](https://forum.inductiveautomation.com/u/lrose)\
**Post date:** [May 13, 2026, 11:46am UTC](https://forum.inductiveautomation.com/t/checking-for-pydocumentobjectadapter/115499/2 "2026-05-13T11:46:30Z")

</div>

I would opt for just insuring there are keys:

```python
if tagValue.keys:
    #do work here

```

---

<div class="post-metadata">

**Author:** ![drewdin](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/drewdin/32/3363_2.png) [@drewdin](https://forum.inductiveautomation.com/u/drewdin)\
**Post date:** [May 13, 2026, 12:07pm UTC](https://forum.inductiveautomation.com/t/checking-for-pydocumentobjectadapter/115499/3 "2026-05-13T12:07:53Z")

</div>

I'm using that but the two tags are different, ones a boolean and ones a PyDocument. There could be more different tags too, I wanted to check the type and treat the value differently.

I found another post that converted the type to a string and then checked for PyDocumentObjectAdapter. That worked but wasn't sure why I needed to do that.

---

<div class="post-metadata">

**Author:** ![lrose](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/lrose/32/62724_2.png) [@lrose](https://forum.inductiveautomation.com/u/lrose)\
**Post date:** [May 13, 2026, 1:16pm UTC](https://forum.inductiveautomation.com/t/checking-for-pydocumentobjectadapter/115499/4 "2026-05-13T13:16:02Z")

</div>

I guess I missed the two different tags bit.

The pythonic way to do this is to use the `isinstance()` builtin.

```python
import com.inductiveautomation.ignition.common.script.adapters.PyDocumentObjectAdapter as PyDocumentObjectAdapter

if isinstance(tagValue, PyDocumentObjectAdapter):
    #do work for document type tag

elif isinstance(tagValue, bool):
    #do work for boolean tag

```

I have seen where sometimes in Jython the builtin doesn't work all the time, so another way you could do this is:

```python
if hasattr(tagValue,'keys'): #or items in the event you support a list and/or dict psuedo type
    #do work here for document tag

elif isinstance(tagValue, bool):
    #do work here for boolean tag

```

I tested in the script console and the first option works, so that is the route I would recomend here (since you're getting this back from a tag, scoping shouldn't matter in this instance, but you might want to check)

---

<div class="post-metadata">

**Author:** ![danielps1818](https://avatars.discourse-cdn.com/v4/letter/d/ecae2f/32.png) [@danielps1818](https://forum.inductiveautomation.com/u/danielps1818)\
**Post date:** [May 13, 2026, 1:40pm UTC](https://forum.inductiveautomation.com/t/checking-for-pydocumentobjectadapter/115499/5 "2026-05-13T13:40:08Z")

</div>

> [@lrose](#):
>
> The pythonic way to do this is to use the `isinstance()` builtin.

This is they way you should do it ↑.

However, you could also do something like:

```python
if len(tagValue.items()) > 0:
    # process document tag

```

Or if is a Gateway Tag Change Script you could something like this:

```python
if event.tagPath.getItemName() == "YourDocumentTagName":
    # do work here for document tag
elif event.tagPath.getItemName() == "YourBooleanTagName":
    # do work here for boolean tag

```

If you could explain a bit more how is executed your script it would help us.

---

<div class="post-metadata">

**Author:** ![drewdin](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/drewdin/32/3363_2.png) [@drewdin](https://forum.inductiveautomation.com/u/drewdin)\
**Post date:** [May 13, 2026, 1:44pm UTC](https://forum.inductiveautomation.com/t/checking-for-pydocumentobjectadapter/115499/6 "2026-05-13T13:44:24Z")

</div>

I'm using version 8.1.44 and for some reason I couldn't import

```python
import com.inductiveautomation.ignition.common.script.PyDocumentObjectAdapter as PyDocumentObjectAdapter

```

Its showing as `ImportError: No module named PyDocumentObjectAdapter`

I'm using the hasattr and checking if it haskeys() to make sure I'm not returning empty brackets. seems to be working well, thanks

---

<div class="post-metadata">

**Author:** ![drewdin](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/drewdin/32/3363_2.png) [@drewdin](https://forum.inductiveautomation.com/u/drewdin)\
**Post date:** [May 13, 2026, 1:45pm UTC](https://forum.inductiveautomation.com/t/checking-for-pydocumentobjectadapter/115499/7 "2026-05-13T13:45:35Z")

</div>

Its a gateway tag change script, multiple tags calling it. I need to differentiate between values and NULL. Thanks!

---

<div class="post-metadata">

**Author:** ![JordanCClark](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/jordancclark/32/83362_2.png) [@JordanCClark](https://forum.inductiveautomation.com/u/JordanCClark)\
**Post date:** [May 13, 2026, 1:56pm UTC](https://forum.inductiveautomation.com/t/checking-for-pydocumentobjectadapter/115499/8 "2026-05-13T13:56:19Z")

</div>

> [@drewdin](#):
>
> Its showing as `ImportError: No module named PyDocumentObjectAdapter`

it's missing a bit from the path. Somewhere along the line, `adapters` got dropped out:

```python
from com.inductiveautomation.ignition.common.script.adapters import PyDocumentObjectAdapter
```

---

<div class="post-metadata">

**Author:** ![drewdin](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/drewdin/32/3363_2.png) [@drewdin](https://forum.inductiveautomation.com/u/drewdin)\
**Post date:** [May 13, 2026, 1:58pm UTC](https://forum.inductiveautomation.com/t/checking-for-pydocumentobjectadapter/115499/9 "2026-05-13T13:58:58Z")

</div>

Thanks, which method do you prefer? hasattr or checking for PyDocument? Just polling now, haha

---

<div class="post-metadata">

**Author:** ![lrose](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/lrose/32/62724_2.png) [@lrose](https://forum.inductiveautomation.com/u/lrose)\
**Post date:** [May 13, 2026, 2:09pm UTC](https://forum.inductiveautomation.com/t/checking-for-pydocumentobjectadapter/115499/10 "2026-05-13T14:09:45Z")

</div>

> [@JordanCClark](#):
>
> Somewhere along the line, `adapters` got dropped out

Yeah, thats what I get for not doing copy pasta. 🤦‍♂️

> [@drewdin](#):
>
> Just polling now

I prefer checking the type, but if I need to run code which is agnostic to dicts or lists, then using hasattr to check for items is easier for me to read.

---

<div class="post-metadata">

**Author:** ![JordanCClark](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/jordancclark/32/83362_2.png) [@JordanCClark](https://forum.inductiveautomation.com/u/JordanCClark)\
**Post date:** [May 13, 2026, 2:19pm UTC](https://forum.inductiveautomation.com/t/checking-for-pydocumentobjectadapter/115499/11 "2026-05-13T14:19:44Z")

</div>

`isinstance()` is generally the preferred method. I was trying to think on when I had to use `hasattr()`-- it's been longer than four days, so I'm already in trouble...

IIRC it was having to do with vision charts, and having to dig down until I found what i wanted.

For most applicattions, I agree with what @lrose said.

---

<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:** [May 13, 2026, 2:35pm UTC](https://forum.inductiveautomation.com/t/checking-for-pydocumentobjectadapter/115499/12 "2026-05-13T14:35:06Z")

</div>

I tend to use `hasattr()` when looking for dictionary-like or list-like objects. Because that is what jython itself does (approximately) when trying to boil things down to its own basic types.

That, after all, is what "duck typing" means. Types in jython/python are expected to be compatible based on the common methods exposed, not necessarily on the actual class hierarchy.

---

<div class="post-metadata">

**Author:** ![bkarabinchak.psi](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/bkarabinchak.psi/32/83567_2.png) [@bkarabinchak.psi](https://forum.inductiveautomation.com/u/bkarabinchak.psi)\
**Post date:** [May 13, 2026, 2:40pm UTC](https://forum.inductiveautomation.com/t/checking-for-pydocumentobjectadapter/115499/13 "2026-05-13T14:40:26Z")

</div>

I use `isintance` for type checking primitives in the beginning of a function `if not isinstance(param1, int): raise Type Error("blah")` but `hasattr` for objects beause I tend to only care if a specific method is available, which like Phil said is essence of duck typing.

---

<div class="post-metadata">

**Author:** ![lrose](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/lrose/32/62724_2.png) [@lrose](https://forum.inductiveautomation.com/u/lrose)\
**Post date:** [May 13, 2026, 2:48pm UTC](https://forum.inductiveautomation.com/t/checking-for-pydocumentobjectadapter/115499/14 "2026-05-13T14:48:56Z")

</div>

> [@bkarabinchak.psi](#):
>
> only care if a specific method is available

Generally, if I'm checking a type, it came from Java and I'm using more than 1 or 2 attributes.

Other wise, I assume that things are the types I expect and if it fails, I've either made an invalid assumption or there is some other self inflicted error. I can't think of a time when I have needed to check for a primitive type, but then I also control both the front end code and the back end code, and don't have to write functions that are handed to other people who may try to use them in an unintended way.

---

<div class="post-metadata">

**Author:** ![bkarabinchak.psi](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/bkarabinchak.psi/32/83567_2.png) [@bkarabinchak.psi](https://forum.inductiveautomation.com/u/bkarabinchak.psi)\
**Post date:** [May 13, 2026, 2:56pm UTC](https://forum.inductiveautomation.com/t/checking-for-pydocumentobjectadapter/115499/15 "2026-05-13T14:56:19Z")

</div>

Yea I can see it both ways here. A lot of my old code is only isinstance. And it ceratinly works fine and I don't mind the strictness tbh given the lack of it otherwise in jython.

But for testing things that require a gateway context can be annoying and not suitable at all in a script console, so you're left modifiying your script, saving it, testing it, checking the gateway logs to see what logged/errored.

Where with hasattr you can test the flow of a function with a

```python
class testclass(object):
    def __init__ (self):
        pass
    def methodICareToTest(self, ...):
        pass

```

And now you can at least test the flow much more simply without needing saves, going back and forth to the gateway log.

Again this only really affects java objects that only live on the gateway and perhaps is more a workflow thing than anything else.

Personally as long as I am seeing _any_ checks done on the code, isinstance or hastattr I would be happy that the other person who wrote it knew what they were doing and cared about the work.

---

<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:** [May 13, 2026, 4:48pm UTC](https://forum.inductiveautomation.com/t/checking-for-pydocumentobjectadapter/115499/16 "2026-05-13T16:48:54Z")

</div>

For what it's worth, the base Jython object implementation exposes `isMappingType` and `isSequenceType` methods directly, e.g.

```python
if myThing.isMappingType():
   pass

# or
if myThing.mappingType:

```

All of our various Java objects that pretend to be Java data structures implement this faithfully.

I would also generally say that 'duck typing' is the way to go over `isinstance` - from a backwards compatibility standpoint, we would consider the **shape** of something part of our API contract with you as end users, but would not consider the exact **type** of something part of our contract, so refactoring (even within minor versions!) could theoretically break `isinstance` calls where you're importing Ignition types. Plus the issues with classloaders and visibility on the gateway.
