Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix/more helpful invalid refs (#1080) #1085

Merged
merged 3 commits into from
Oct 23, 2018

Conversation

beckjake
Copy link
Contributor

Fixes #1080 - in particular the issue described by @raybuhr

There are some neat things going on here:

  • the issue is that ParserMacroCapture.__getattr__ accesses self.name without ensuring that it is not doing a lookup for self.name -> recursion error
  • which can happen if a ParserMacroCapture is deepcopied. deepcopy sort of calls new(), and populates the created object, bypassing init through a convoluted set of hasattr checks that we pass due to the __getattr__ implementation.
  • which can happen if an undefined value was ref'd

The ways you might think would help (raising AttributeError in getattr, etc) all end up being pretty unhelpful since jinja does propagation of Undefined values, so you get odd TypeErrors down the line. But implementing a __deepcopy__ that raises a compiler error works: jinja won't catch it and the error can be pretty precise/helpful. Any time you find yourself calling copy.deepcopy() with an undefined value, things have gone horribly wrong, so I think it's a valid solution.

Copy link
Contributor

@drewbanin drewbanin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🏓 @beckjake

)

def __getattr__(self, name):
if name == 'name' or name.startswith('__') and name.endswith('__'):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you put some parens in here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

did one better and just made it a function


def __getattr__(self, name):
if name == 'name' or name.startswith('__') and name.endswith('__'):
raise AttributeError(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why would we raise this error for __*__?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

because copy.deepcopy does a series of successive hasattr(x, '__*__') checks to decide how to deepcopy things, and hasattr(obj, name) is basically implemented as:

try:
  getattr(obj, name)
except AttributeError:
  return False
else:
  return True

Since __getattr__ is only accessed when an attribute is not already defined, we want to signal that we don't implement those methods.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

roger!

Copy link
Contributor

@drewbanin drewbanin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just tested this out locally -- works great! Better error messages, better ingredients, papa johns

🚢 when the tests pass!

@beckjake beckjake merged commit a317456 into dev/guion-bluford Oct 23, 2018
@beckjake beckjake deleted the fix/more-helpful-invalid-refs branch October 29, 2018 16:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants