# Curiosity: why are documented methods throwing AttributeError (is my ignorance showing?)

**URL:** <https://forum.inductiveautomation.com/t/curiosity-why-are-documented-methods-throwing-attributeerror-is-my-ignorance-showing/85081>\
**Category:** Ignition\
**Tags:** scripting\
**Created:** [February 1, 2024, 10:07am UTC](https://forum.inductiveautomation.com/t/curiosity-why-are-documented-methods-throwing-attributeerror-is-my-ignorance-showing/85081 "2024-02-01T10:07:47Z")\
**Posts on this page:** 13\
**Page:** 1

<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:** [February 1, 2024, 10:07am UTC](https://forum.inductiveautomation.com/t/curiosity-why-are-documented-methods-throwing-attributeerror-is-my-ignorance-showing/85081/1 "2024-02-01T10:07:47Z")

</div>

['PyJsonObjectAdapter' object has no attribute 'update'](https://files.inductiveautomation.com/sdk/javadoc/ignition81/8.1.32/com/inductiveautomation/ignition/common/script/adapters/PyJsonObjectAdapter.html#update(org.python.core.PyObject%5B%5D,java.lang.String%5B%5D)) ≈ `dict(PyJsonObjectAdapter).update()`

more fun: ['list' object has no attribute 'get'](https://javadoc.io/static/org.python/jython-standalone/2.7.1/org/python/core/PyList.html#get-int-) ≈ `list(). __getitem__ ()`

I'm guessing the `get()` method is purposefully stripped/overridden to ensure parity with cpython, but I'd love to know how/why.

edit - looks like it's [not necessarily overidden](https://github.com/jython/jython/blob/148bf3749d9c12d55017bbd9556bb0529af6de35/src/org/python/core/PyList.java#L1089) in jython?

---

<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:** [February 1, 2024, 1:00pm UTC](https://forum.inductiveautomation.com/t/curiosity-why-are-documented-methods-throwing-attributeerror-is-my-ignorance-showing/85081/2 "2024-02-01T13:00:07Z")

</div>

Bracket notation is how you use the dunder method of ` __getitem__ ` typically personally I have never run into an issue with doing a getitem from a list. Can you post the code that is causing the issue?

---

<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:** [February 1, 2024, 2:02pm UTC](https://forum.inductiveautomation.com/t/curiosity-why-are-documented-methods-throwing-attributeerror-is-my-ignorance-showing/85081/3 "2024-02-01T14:02:23Z")

</div>

> [@hunterdg](#):
>
> ['PyJsonObjectAdapter' object has no attribute 'update'](https://files.inductiveautomation.com/sdk/javadoc/ignition81/8.1.32/com/inductiveautomation/ignition/common/script/adapters/PyJsonObjectAdapter.html#update(org.python.core.PyObject%5B%5D,java.lang.String%5B%5D)) ≈ `dict(PyJsonObjectAdapter).update()`

The `update()` method of `PyJsonObjectAdapter` is marked with the `org.python.core.PyIgnoreMethodTag` which tells Jython to ignore the method.

[https://www.javadoc.io/static/org.python/jython/2.7.0/index.html?org/python/core/PyIgnoreMethodTag.html](https://www.javadoc.io/static/org.python/jython/2.7.0/index.html?org/python/core/PyIgnoreMethodTag.html)

So it not being available from Jython was an intentional choice.

Like @bkarabinchak.psi I would be interested to see the code that was throwing the attribute error with list. Not sure I understand why you would need to call the dunder method directly.

---

<div class="post-metadata">

**Author:** ![pascal.fragnoud](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pascal.fragnoud/32/24728_2.png) [@pascal.fragnoud](https://forum.inductiveautomation.com/u/pascal.fragnoud)\
**Post date:** [February 1, 2024, 2:10pm UTC](https://forum.inductiveautomation.com/t/curiosity-why-are-documented-methods-throwing-attributeerror-is-my-ignorance-showing/85081/4 "2024-02-01T14:10:17Z")

</div>

> [@lrose](#):
>
> Not sure I understand why you would need to call the dunder method directly.

He's not talking about ` __getitem__ ` but a simple `get`, which could do the same thing as `dict.get`: return a default instead of throwing an error if trying to access something that doesn't exist.

---

<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:** [February 1, 2024, 2:27pm UTC](https://forum.inductiveautomation.com/t/curiosity-why-are-documented-methods-throwing-attributeerror-is-my-ignorance-showing/85081/5 "2024-02-01T14:27:14Z")

</div>

I suppose, part of my confusion is that `list()` is not the same as `PyObject()` or `PyList()`.

python list's don't have a 'get' method. There are of course ways to get a default value if needed.

The example links go to the documentation for `PyList` which does have a `get()` but that method doesn't return a default, it throws an IndexOutOfRangeException.

Then he references `PyObject.get()`, but that method also doesn't exist.

My conclusion was he was trying to call ` __getitem__ ()` directly.

---

<div class="post-metadata">

**Author:** ![pascal.fragnoud](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pascal.fragnoud/32/24728_2.png) [@pascal.fragnoud](https://forum.inductiveautomation.com/u/pascal.fragnoud)\
**Post date:** [February 1, 2024, 2:30pm UTC](https://forum.inductiveautomation.com/t/curiosity-why-are-documented-methods-throwing-attributeerror-is-my-ignorance-showing/85081/6 "2024-02-01T14:30:54Z")

</div>

To be honest I'm not quite sure what the thread is about :X

---

<div class="post-metadata">

**Author:** ![justinedwards.jle](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/justinedwards.jle/32/37854_2.png) [@justinedwards.jle](https://forum.inductiveautomation.com/u/justinedwards.jle)\
**Post date:** [February 1, 2024, 2:41pm UTC](https://forum.inductiveautomation.com/t/curiosity-why-are-documented-methods-throwing-attributeerror-is-my-ignorance-showing/85081/7 "2024-02-01T14:41:40Z")

</div>

The thread is about "Documented Methods" throwing an error in Ignition, but the OP is referencing the Java Docs, and I suspect the methods are being attempted in Ignition's Jython scripting environment.

To be honest, I probably reference the Java docs more than anything when developing scripts for Ignition, but I do it with the understanding that they're written for Java developers, not Jython developers.

---

<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:** [February 1, 2024, 3:06pm UTC](https://forum.inductiveautomation.com/t/curiosity-why-are-documented-methods-throwing-attributeerror-is-my-ignorance-showing/85081/8 "2024-02-01T15:06:03Z")

</div>

> [@justinedwards.jle](#):
>
> I suspect the methods are being attempted in Ignition's Jython scripting environment.

Yes, specifically I suspect in some Perspective Context, since that is where you would most often see a `PyJsonObjectAdapter`.

I strongly suspect that this is brought about by trying to use `dict()` methods on what can be easily confused with one but isn't

---

<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:** [February 1, 2024, 5:18pm UTC](https://forum.inductiveautomation.com/t/curiosity-why-are-documented-methods-throwing-attributeerror-is-my-ignorance-showing/85081/9 "2024-02-01T17:18:21Z")

</div>

When I originally made PyJsonObjectAdapter act more like a Python dictionary, I deliberately omitted some methods (via the `PyIgnoreMethodTag` @lrose noticed) because the underlying object, an instance of Google's Gson `JsonObject`, doesn't have an exact analogue of the Python method so it was easier to omit it than to try to add the extra functionality.

---

<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:** [February 2, 2024, 9:49pm UTC](https://forum.inductiveautomation.com/t/curiosity-why-are-documented-methods-throwing-attributeerror-is-my-ignorance-showing/85081/10 "2024-02-02T21:49:32Z")

</div>

> [@lrose](#):
>
> The `update()` method of `PyJsonObjectAdapter` is marked with the `org.python.core.PyIgnoreMethodTag` which tells Jython to ignore the method.

Thanks for this!! How can I see/discover this myself?

> [@lrose](#):
>
> `list()` is not the same as `PyObject()` or `PyList()`.

is Jython list() not Java PyList()?

I mistakenly mentioned PyObject.get() (removed from original post)

> [@paul-griffith](#):
>
> was easier to omit it than to try to add the extra functionality

@paul-griffith does this (difficulty) suggest my workaround is contrived/naive?

```python
update-able_dict = dict(PyJsonObjectAdapter)
update-able_dict.update()

```

---

<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:** [February 2, 2024, 10:08pm UTC](https://forum.inductiveautomation.com/t/curiosity-why-are-documented-methods-throwing-attributeerror-is-my-ignorance-showing/85081/12 "2024-02-02T22:08:32Z")

</div>

> [@hunterdg](#):
>
> Thanks for this!! How can I see/discover this myself?

Well, the `Ignore` in a `Throws` statement, made me scratch my head, because Ignore and Exceptions aren't really something you see together. Which made me go find out what it did.

---

<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:** [February 2, 2024, 10:09pm UTC](https://forum.inductiveautomation.com/t/curiosity-why-are-documented-methods-throwing-attributeerror-is-my-ignorance-showing/85081/13 "2024-02-02T22:09:25Z")

</div>

Your workaround will accomplish a _shallow copy_ - only the first layer of keys/values will be moved to a true dictionary. There's some snippets floating around on the forum for a true _deep_ copy.

---

<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:** [February 2, 2024, 10:32pm UTC](https://forum.inductiveautomation.com/t/curiosity-why-are-documented-methods-throwing-attributeerror-is-my-ignorance-showing/85081/14 "2024-02-02T22:32:57Z")

</div>

short explanation for everyone asking:

- `list.get()`
  - I wanted an expression structure binding parameter to support named query (including 'json' Return Format option and input parameters)
    - accomplished via runscript() and script transform on expression structure binding
    - enabled parameters to be passed as json string or java.util.hashMap (no dict in expressions)
    - scripting extensions module dataset to json arranges data differently
    - wanted to return a default like named query does

> **binding**
>
> ```auto
> {
> "type": "expr-struct",
> "enabled": false,
> "config": {
> "struct": {
> "consoles": "runScript(\n\t\u0027_system.db.runNamedQuery\u0027,\n\t0,\n\t\u0027Consoles/getConsoles\u0027\n)",
> "userPrefs": "runScript(\n\t\u0027_system.db.runNamedQuery\u0027,\n\t0,\n\t\u0027Metadata/Get User Prefs\u0027, \n\tconcat(\"{\u0027Username\u0027:\", {session.props.auth.user.userName}, \"}\")\n)"
> },
> "waitOnAll": true
> },
> "transforms": [
> {
> "code": "\treturn {\n\t\t\u0027userPrefs\u0027:_system.dataset.pdsToJson(value.userPrefs).get(0,{}),\n\t\t\u0027consoles\u0027:_system.dataset.pdsToJson(value.consoles)\n\t}",
> "type": "script"
> }
> ]
> }
> 
> ```

> **\_system**
>
> ```auto
> '''
> need to sublcass system.* instead of this hack
> '''
> 
> class dataset:
> 
> @staticmethod
> class pdsToJson(list):
> def __init__ (self, pds):
> self.pds = [{colName: value for colName, value in zip(pds.columnNames, row)} for row in pds] if pds else []
> super(dataset.pdsToJson, self). __init__ (self.pds)
> 	
> def get(self, index, default=None):
> if index < len(self.pds): return super(dataset.pdsToJson, self). __getitem__ (index)
> return default
> 
> class db:
> 
> @staticmethod
> def runNamedQuery(path, parameters = None, tx = None, getKey = None):
> import java.util.HashMap
> assert type(path) == str or unicode
> if type(parameters) == java.util.HashMap:
> return system.db.runNamedQuery(path, dict(parameters), tx, getKey)
> elif type(parameters) == str or unicode:
> return system.db.runNamedQuery(path, system.util.jsonDecode(parameters), tx, getKey)
> else: return system.db.runNamedQuery(path, parameters, tx, getKey)
> 
> ```

- `PyJsonObjectAdapter.update()`
  - was chaining script transforms (abandoned that per PTurmel's post on the matter)

basically I wanted one binding instead of multiple

critiques/alternatives welcome!  
go easy on me
