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

Handle new ast.Constant node in SourceGenerator #121

Merged
merged 16 commits into from
Mar 22, 2019

Conversation

chrisrink10
Copy link
Contributor

This PR adds SourceGenerator.visit_Constant to handle Python 3.8 deprecating older constant AST node types. I reused a lot of the logic from the exist node types by breaking them out into private handlers for the node value. For a few of the node types this ended up being a little gnarly, so let me know if you have some other ideas for how to organize this code. I didn't want to duplicate a lot of the functionality, since there was a lot there (especially for strings and numeric types) that was probably learned with a lot of bug reports.

I'm not sure exactly how easily you can test this specific code until the Python compiler is emitting these constant nodes directly, but I'm happy to look into it more if you'd like. Locally (at least) the existing tests were passing for me.

Fixes #120

@berkerpeksag
Copy link
Owner

Thanks for the PR! It looks pretty good to me. I think your organization of the code seems reasonable. I will post my nitpicks later today :)

Perhaps we could try to generate something like spam = 'eggs' from an AST tree generated by Python 3.8?

@chrisrink10
Copy link
Contributor Author

@berkerpeksag I added a few test cases (which are currently failing) to illustrate how I was thinking about testing this change. I'll try to look into why they are failing a little later.

@chrisrink10
Copy link
Contributor Author

Alright @berkerpeksag I fixed the tests now. The only thing we might want to do is add Python 3.8-dev into the Travis test suite, but I'll leave that up to you.

@berkerpeksag
Copy link
Owner

Thank you very much! I think adding 3.8-dev into Travis is a good idea.

@chrisrink10
Copy link
Contributor Author

Alright! Python 3.8 dev builds working.

# ast.Ellipsis, ast.NameConstant, ast.Num, ast.Str in Python 3.8
def visit_Constant(self, node):
value = node.value
if isinstance(value, (complex, float, int)):

Choose a reason for hiding this comment

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

bool will be handled here.

@serhiy-storchaka
Copy link

For most values the code is just self.write(repr(value)). You need to handle just few special values: float and complex numbers with inf and nan and Ellipsis. For some reasons strings need special handling too.

@chrisrink10
Copy link
Contributor Author

Thanks for the comments @serhiy-storchaka ! I just want to clarify - do you want me to remove the private handlers and just use self.write(repr(value)) except for numbers and strings?

@serhiy-storchaka
Copy link

I would write the Constant visitor as

    def visit_Constant(self, node):
        value = node.value
        if isinstance(value, (float, complex)):
            self._handle_numeric_constant(value)
        elif isinstance(value, str):
            precedence = self.get__pp(node)
            self._handle_string_constant(value, precedence)
        else:
            self.write(repr(value))

and make the NameConstant handler using repr() instead of str() for uniformity.

@berkerpeksag
Copy link
Owner

Serhiy's suggestion sounds good to me.

@chrisrink10
Copy link
Contributor Author

Thanks for the comments @berkerpeksag and @serhiy-storchaka . I've implemented the changes you suggested.

Copy link

@serhiy-storchaka serhiy-storchaka left a comment

Choose a reason for hiding this comment

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

I think changes in _handle_string_constant() can be minimized. Other than that all LGTM as the first step.

I see some bugs in existing code, but that is for other issues.


def _handle_string_constant(self, value, precedence, join_fn=None):

Choose a reason for hiding this comment

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

Why not pass the original node? It could be used for precedence and for recursion. You will don't need to repeat precedence = self.get__pp(node).

ast.Assign(targets=[ast.Name(id='spam')], value=ast.Name(id='None')),
"spam = None")

@unittest.skipUnless((3, 4) <= sys.version_info <= (3, 8),

Choose a reason for hiding this comment

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

I think <= (3, 8) can be removed.

ast.Assign(targets=[ast.Name(id='spam')], value=ast.NameConstant(value=None)),
"spam = None")

@unittest.skipIf(sys.version_info >= (3, 8),

Choose a reason for hiding this comment

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

I think the skip should be removed. These tests work in 3.8 and will continue to work in several future versions.

@chrisrink10
Copy link
Contributor Author

Thank you for reviewing again @serhiy-storchaka ! I pushed some changes which addressed your latest round of comments.

@@ -590,7 +607,13 @@ def recurse(node):
uni_lit = False # No formatted byte strings

else:
mystr = node.s
if isinstance(node, ast.Str):

Choose a reason for hiding this comment

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

You can pass both node and value to this function. This will simplify the code.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@serhiy-storchaka What should I pass in visit_JoinedStr? We don't actually use the value in that branch, but I think it's kind of a smell to pass in a throwaway value in that case.

Choose a reason for hiding this comment

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

Pass None.

@chrisrink10
Copy link
Contributor Author

Thank you @serhiy-storchaka ! I addressed your latest round of comments.

@jmfrank63
Copy link

I just commented over at #120 (comment) and could need this.
I am using astor to generate code for python-trio/trio#805
Is there an ETA this PR is getting merged?

@berkerpeksag
Copy link
Owner

@jmfrank63 thank you for the ping. I will try to get this PR in later this week. Sorry for the delay, @chrisrink10!

@Kodiologist
Copy link
Contributor

@berkerpeksag Here's another poke. This seems to be a blocker for support for Python 3.8 features in Hy.

@chrisrink10
Copy link
Contributor Author

@berkerpeksag I fixed the merge conflicts. It would be great if we could get this merged soon. Thanks!

Copy link
Owner

@berkerpeksag berkerpeksag left a comment

Choose a reason for hiding this comment

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

LGTM, thank you! Just a minor thing: Could you add a short note to docs/changelog.rst so users can find out this will be in the next release?

@chrisrink10
Copy link
Contributor Author

Just pushed the changelog update. Thank you!

@berkerpeksag
Copy link
Owner

Sorry, I forgot to say this earlier, but could you add your name to https://github.com/berkerpeksag/astor/blob/master/AUTHORS?

@chrisrink10
Copy link
Contributor Author

Done!

@berkerpeksag berkerpeksag merged commit 6413903 into berkerpeksag:master Mar 22, 2019
@berkerpeksag
Copy link
Owner

Thank you and welcome!

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.

None yet

5 participants