Help: can't set attribute in 3.9.14

Hi. I’m writing code in a Python 3.9.9 environment and running it in a 3.9.14 environment. But I’m running into a problem.

I’m using pyparsing (3.0.9) and adding attributes to ParseResults objects, e.g.:
node.extra_info = something

It works fine under 3.9.9 but triggers an AttributeError: 'ParseResults' object has no attribute 'extra_info' under 3.9.14.

I assume something changed between 3.9.9 and 3.9.14. What would it be, and is there a way around it?

Thank you.

What version of pyparsing are you using in the 3.9.14 environment?

Can you demonstrate a minimal example of this code? E.g.

import pyparsing
print(pyparsing.__version__)
something = ...
something.extra = "something"
print("done")

Ouch! The 3.9.14 environment has pyparsing 3.0.9, but the Python 3.9.9 environment has pyparsing 2.4.7!

So would that suggest that pyparsing might’ve had its objects re-implemented in C, so that they no longer have a _dict_?

Is there any way to attach extra information to such an object, or do I simply need a different approach?

Or they got __slots__ added, which would have the same effect.

One option, assuming that a ParseResults is hashable, would be to maintain your own dictionary that maps the results object to your own attributes. Or subclass the ParseResults and do nothing:

class ParseResults(ParseResults): pass

This will re-add a dict to it. But then you might have to monkey-patch that back into the place that creates them, which may not be a good idea.

The source code suggests that it was converted to slots for performance reasons. You could possibly ask the devs to add a userdata slot, which would be the same as just adding attributes, but safe against future changes, and wouldn’t have as big a performance cost as keeping a __dict__ on everything (since it would only be added when YOU choose to add it). In your code, the only change would be:

# Was:
node.extra_info = something
# Now:
node.userdata = {"extra_info": something}

although it’s a little more complicated if you have multiple possible extra info fields and all of them are optional.