Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

String annotations [PEP 563]#4390

Merged
ambv merged 7 commits intopython:masterfrom
ambv:string_annotations
Jan 26, 2018
Merged

String annotations [PEP 563]#4390
ambv merged 7 commits intopython:masterfrom
ambv:string_annotations

Conversation

@gvanrossum
Copy link
Member

@gvanrossumgvanrossum commentedNov 14, 2017
edited by ambv
Loading

This is unfinished work by@ambv. UPDATE: this is ready for review now.

I'm adding it here because patching and reviewing are easier (for me anyway) when it's in PR form. Also,@serhiy-storchaka your eye would be appreciated, esp. for the hairy AST unparsing code in C. (Also, if you had to do this from scratch, would it be easier to unparse the CST instead?)

lsloan reacted with thumbs up emoji
@gvanrossum
Copy link
MemberAuthor

I'm guessing there are still crasher bugs in here... E.g.

>>> from __future__ import string_annotations>>> def f(a: list[str]): pass... Segmentation fault: 11

Copy link
Member

@serhiy-storchakaserhiy-storchaka left a comment

Choose a reason for hiding this comment

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

There are crashes because the work is unfinished. Some parts still are not implemented (in particularly subscribing). Error checking is minimal if exists.

All concatenation has quadratic time. I think it is worth to implement simple accumulator that uses overallocated array and makes concatenations for linear time. Or you can reuse existing_PyBytesWriter or_PyUnicodeWriter.

Yes, maybe unparsing the CST could be much simpler. But we don't have feature flags at this stage.

Choose a reason for hiding this comment

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

ann_as_str is leaked. UseADDOP_N.

Choose a reason for hiding this comment

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

Check if not NULL.

Python/ast.c Outdated
Copy link
Member

@serhiy-storchakaserhiy-storchakaNov 14, 2017
edited
Loading

Choose a reason for hiding this comment

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

Results of all allocations should be checked for NULL.

Python/ast.c Outdated

Choose a reason for hiding this comment

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

Add the default case. At least for debugging.

@serhiy-storchaka
Copy link
Member

If unparse the AST I would move the code into a separate file. There will be a lot of code, comparable with the size ofcompile.c.

@ambv
Copy link
Contributor

Alright, I'm going to:

  • change the future name back to annotations (yay!)
  • stick to AST unparsing
  • move this work to a separate file
  • change concatenation to use the accumulator pattern (reusing_PyBytesWriter would be great)
  • finish the functionality

@gvanrossum
Copy link
MemberAuthor

Sounds great! I am pretty happy to see where this is going, I'd like to see it in a solid state by the time beta 1 comes around.

@ambvambv changed the title[WIP] String annotationsString annotations [PEP 563]Nov 18, 2017
@ambvambv self-assigned thisNov 18, 2017
@ambv
Copy link
Contributor

ambv commentedNov 18, 2017
edited
Loading

All comments from Serhiy's review acted upon, the import renamed back to "annotations" like commented above. The only missing piece in the implementation is f-string support but my battery will die soon so I wanted to push this out for you to look at.

Shouldn't segfault anymore, trying to use f-strings raises an exception instead.

@ambv
Copy link
Contributor

Hm, the clang Travis CI build is failing due to invalid whitespace.make patchcheck is complaining aboutInclude/code.h, suggesting the following diff:
https://gist.github.com/ambv/9f0874d56c7cf0d5ce98dfef38de0ce6

This diff is suggesting a lot of changes but not on the single line that I modified¯\_(ツ)_/¯

@ambv
Copy link
Contributor

I added a commit that fixes the whitespace according to the generated patch above so that I can see Travis CI passing. We can decide what to do with it later.

AppVeyor is failing because we need to modify PCbuild/* but I don't have access to a Windows box.

NEWS entry is not there yet since Blurb is tied to BPO issues and I'm wondering whether creating dummy issues for PEP work isn't redundant? I asked@larryhastings, we can also deal with this later.

@gvanrossumgvanrossum requested a review froma team as acode ownerNovember 18, 2017 23:28
@ambvambv added skip news and removed skip news labelsNov 20, 2017
@ambv
Copy link
Contributor

ambv commentedNov 20, 2017
edited
Loading

Changes:

  • Rebased on top of latest master
  • Added a NEWS entry (manually since this is a PEP; the bot doesn't recognize this, therefore theskip news label has to stay)
  • Moved the changes to PCbuild to the respective implementation commit ("Implement unparsing...")

This is ready for another review pass,@serhiy-storchaka. The only bit left is f-strings which is going to be a bit tedious so I'm waiting with it after a new round of feedback :-)

@ilevkivskyi
Copy link
Member

How, do we organize the updates totyping.get_type_hints() to work with "doubly quoted" strings? I mean this should still work with the__future__ import:

deff()->List['int']:    ...assertget_type_hints(f)['return']==List[int]

I suppose this can be part of the same PR, since this is not necessary in the backported version on PyPI. Also my updates totyping following PEP 560 should not have merge conflicts.

@ambv
Copy link
Contributor

@ilevkivskyi, I want to fixget_type_hints() separately since there's really no reason why accepting"List['int']" shouldn't be supported even today. Same with fixing the self-class reference as you suggested on python-dev (I think I'd do it with a ChainMap though), fixing the forward ref cache conflicts, etc.

@ilevkivskyi
Copy link
Member

@ambv OK, I am fine with this as well.

@serhiy-storchaka
Copy link
Member

It will take a time for making a review of such large change. But one comment I can say now.

The unparser adds parenthesis for grouping subexpression. They are added even if not strictly needed, e.g. ina + (b * (c ** d)). The problem is not that redundant parenthesis makes an expression less readable. The problem is that they increase the stack consumption when parse the expression again. It is possible that the original expression can be parsed, but parsing the unparsed expression will fail or even crash.

I already encountered with similar problem when worked on the parser of plural form expressions ingettext.py. A C-like syntax is parsed and converted to Python syntax, and the result is evaluated. I minimized the use of parenthesis. If the subexpression operator has higher priority than the operator of the outer expression, parenthesis are not added.

This is not a blocker, and we can solve this problem later, but you can think about this while I'm making a review.

@gvanrossum
Copy link
MemberAuthor

gvanrossum commentedNov 22, 2017 via email

Good observation. Also, mypy doesn't like redundant parentheses in typeexpressions. (Though it won't ever encounter these, since it parses thesource, so maybe it doesn't matter.)
On Wed, Nov 22, 2017 at 11:32 AM, Serhiy Storchaka ***@***.*** > wrote: It will take a time for making a review of such large change. But one comment I can say now. The unparser adds parenthesis for grouping subexpression. They are added even if not strictly needed, e.g. in a + (b * (c ** d)). The problem is not that redundant parenthesis makes an expression less readable. The problem is that they increase the stack consumption when parse the expression again. It is possible that the original expression can be parsed, but parsing the unparsed expression will fail or even crash. I already encountered with similar problem when worked on the parser of plural form expressions in gettext.py. A C-like syntax is parsed and converted to Python syntax, and the result is evaluated. I minimized the use of parenthesis. If the subexpression operator has higher priority than the operator of the outer expression, parenthesis are not added. This is not a blocker, and we can solve this problem later, but you can think about this while I'm making a review. — You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub <#4390 (comment)>, or mute the thread <https://github.com/notifications/unsubscribe-auth/ACwrMqGgQ0gZQAtXZIJpySJuO8Q7_UV0ks5s5HbagaJpZM4Qco6U> .
-- --Guido van Rossum (python.org/~guido)

@ambv
Copy link
Contributor

ambv commentedNov 23, 2017 via email

ast_unparse.c is a close translation of the relevant parts of Tools/unparse.py. I didn't want to create an entire new thing from scratch as I'd miss edge cases that way for sure.Tools/unparse.py uses parens liberally as this is the simplest way to ensure the order of operations is preserved. To know if it's safe to omit a paren, a sub-expression would need to know where it's being emitted (e.g. the super-expression). That's way more complicated than what is already done. So, Tools/unparse.py makes no effort to omit parens when they aren't needed.This, as Guido points out, produces types that mypy is unable to parse (like "Dict[(str, int)]"). That won't fly for us so my C implementation allows for omitting parens under certain circumstances already (like the tuple index in the previous example). There are many tests around this. The goal was to not put any spurious parens in typical expressions used in typing. I didn't focus on minimizing parens in expressions which aren't valid types per PEP 484.Two enhancements that are definitely possible:- math operation ordering; and- omitting comma-catching parens if there is no comma in the inner expression (like in comprehensions, dict literals, etc.)I'll look into this next week. I am worried that such cleanup effort is likely to lead to bugs (expressions that end up semantically different from their original form). A spurious pair of parens is way less harmful than that.Speaking of harm, Serhiy, do you have a legit example where we can get to a stack overflow due to spurious parens? While this is theoretically possible, I think we'd have to maliciously create an expression pathological enough to trigger this condition. Any other parse errors or crashes that spurious parens induce?Serhiy, also, thank you for spending your time on reviewing this. I appreciate it. Your first round of review was already super helpful! Let me know if I can do anything to make review easier for you.
-- Best regards,Łukasz Langa
On Nov 22, 2017, at 11:37 AM, Guido van Rossum ***@***.***> wrote: Good observation. Also, mypy doesn't like redundant parentheses in type expressions. (Though it won't ever encounter these, since it parses the source, so maybe it doesn't matter.) On Wed, Nov 22, 2017 at 11:32 AM, Serhiy Storchaka ***@***.*** > wrote: > It will take a time for making a review of such large change. But one > comment I can say now. > > The unparser adds parenthesis for grouping subexpression. They are added > even if not strictly needed, e.g. in a + (b * (c ** d)). The problem is > not that redundant parenthesis makes an expression less readable. The > problem is that they increase the stack consumption when parse the > expression again. It is possible that the original expression can be > parsed, but parsing the unparsed expression will fail or even crash. > > I already encountered with similar problem when worked on the parser of > plural form expressions in gettext.py. A C-like syntax is parsed and > converted to Python syntax, and the result is evaluated. I minimized the > use of parenthesis. If the subexpression operator has higher priority than > the operator of the outer expression, parenthesis are not added. > > This is not a blocker, and we can solve this problem later, but you can > think about this while I'm making a review. > > — > You are receiving this because you authored the thread. > Reply to this email directly, view it on GitHub > <#4390 (comment)>, or mute > the thread > <https://github.com/notifications/unsubscribe-auth/ACwrMqGgQ0gZQAtXZIJpySJuO8Q7_UV0ks5s5HbagaJpZM4Qco6U> > . > -- --Guido van Rossum (python.org/~guido) — You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub, or mute the thread.

@serhiy-storchaka
Copy link
Member

Yes, in case ofgettext the one of purposes was to guard against a malicious input. In the case of annotations it is less likely. The other purpose -- speeding up the compilation.

This problem can be solved by assigning the numerical priority level to expressions and omitting parenthesis only if the current priority level is higher then the level of a super-expression (the sub-expression rather of a super-expression is responsible for adding parenthesis).

I have yet two questions.

  1. Is the performance important here (I afraid yes)? The Python implementation would be simpler and more reliable. But much slower.

  2. Do we need to support the full Python expression syntax? In particular arithmetic operations. Or it would be enough to support only the small subset used in type annotations? Names, attributes, indexing, tuples, what more?

@gvanrossum
Copy link
MemberAuthor

gvanrossum commentedNov 23, 2017 via email

1. The string will be embedded in code objects. I don't want to have tocall out to Python code when creating code objects.2. Yes it should support anything that's currently legal in an expression,not just what we think are valid type expressions. Otherwise it's notbackwards compatible. (Also, otherwise the whole thing about stringliterals was bogus.)

Copy link
Member

@serhiy-storchakaserhiy-storchaka left a comment

Choose a reason for hiding this comment

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

Added comments are mostly style comments (PEP 7) and suggestions for cleaning up the code, but there are several errors.

Include/ast.h Outdated

Choose a reason for hiding this comment

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

For uniformity with other names it would be better to name this function likePyAST_AsUnicode.

And I think it would be better to make it private and don't include in a limited API for now.

Choose a reason for hiding this comment

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

Actually, since this functions supports only AST corresponding to expressions,PyAST_AsUnicode is not a good name. Maybe just add an underscore toPyAST_UnicodeFromAstExpr? Or_PyAST_ExprAsUnicode?

Copy link
Contributor

Choose a reason for hiding this comment

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

OK, I like _PyAST_ExprAsUnicode.

Choose a reason for hiding this comment

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

Are all these differences just differences between tabs and spaces? It would be better to make this in a separate commit, and left only related changes.

Copy link
Contributor

Choose a reason for hiding this comment

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

I did make this a separate commit. As I commented on it, it's only to make "patchcheck" happy.

Choose a reason for hiding this comment

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

This already was done in#4583. You need just merge with master.

Copy link
Contributor

Choose a reason for hiding this comment

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

With your changes frombpo-32150 this is no longer necessary :-)

Choose a reason for hiding this comment

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

Should we test also an argument's annotation?

Copy link
Contributor

Choose a reason for hiding this comment

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

That's the same code but sure, I can add tests with that, too.

Copy link
Contributor

Choose a reason for hiding this comment

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

Done.

Choose a reason for hiding this comment

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

Update alsoPCbuild/pythoncore.vcxproj.filters

Copy link
Contributor

Choose a reason for hiding this comment

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

Done.

Choose a reason for hiding this comment

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

Whystatic?

Copy link
Contributor

Choose a reason for hiding this comment

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

A left-over from something else I tried before. Removed.

Choose a reason for hiding this comment

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

The opening branch should be at the end of the same line as a condition (unless a condition is a multiline). PEP 7.

Copy link
Contributor

Choose a reason for hiding this comment

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

Fixed.

Choose a reason for hiding this comment

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

Await. Move the opening brace.

Copy link
Contributor

Choose a reason for hiding this comment

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

Fixed.

Choose a reason for hiding this comment

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

According to the meaning of this function it would be better to name the parameterraw.

Copy link
Contributor

Choose a reason for hiding this comment

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

Function removed in "Strings are no longer treated special".

Choose a reason for hiding this comment

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

Constant_kind can be a string too.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, however, this special handling of strings has since been dropped from the PEP, I'll remove it in the next commit.

Copy link
Contributor

Choose a reason for hiding this comment

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

Removed in "Strings are no longer treated special".

Choose a reason for hiding this comment

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

Constant_kind can be the Ellipsis too, in which case it outputsEllipsis instead of....

Copy link
Contributor

Choose a reason for hiding this comment

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

Well, yes, because apparently the user wrote "Ellipsis" and not "...". Do you think we should convert to "..." in this case, too?

Copy link
Contributor

Choose a reason for hiding this comment

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

FWIW:

>>> Ellipsis is ...True

so this looks relatively low-pri.

@gvanrossum
Copy link
MemberAuthor

gvanrossum commentedNov 27, 2017 via email

The readability issue will occasionally come up when people are starting todebug annotations. There's also the hypothetical issue that if someone wereto generate stub files based on these, the redundant parentheses may elicitcomplaints from either mypy or pytype, both of which employ a limitedsyntax for annotations. That said we can always improve this later, soprioritize as you see fit.

@ambv
Copy link
Contributor

As I said in my comment on Nov 23rd, to the best of my knowledge, the current state of the diff already omits all cases of spurious parens that occur in valid type annotations.

@serhiy-storchaka
Copy link
Member

Don't spend your time on fighting with the extra parens if this distracts you from more prioritized tasks. If you don't solve this problem in your PR I'm going to do this after its merging. I suppose this will not add too much complexity. Your code already avoid producing the extra parens in many cases. This is enough for the initial implementation.

Yet one consideration. Could it help if introduce macros like theVISIT macro insymtable.c andcompile.c? They should call specified function with explicit and implicit arguments, check a result and return a failure if it is failed. Most functions could be just a short sequence of invocations of these macros. This technique is used in many places in CPython sources.

@ambv
Copy link
Contributor

Could it help if introduce macros like the VISIT macro in symtable.c and compile.c?

I was thinking about this when I was originally writing this but wasn't sure if macros aren't reserved just for special usage so I avoided them. If you'd like, I can refactor the file to use a macro instead, you're right, that should shorten it quite a bit.

ambvand others added4 commitsDecember 30, 2017 21:29
The string form is recovered by unparsing the AST.
This is required for PEP 563 and as such only implements a part of theunparsing process that covers expressions.
@ambv
Copy link
Contributor

Alright, this is fully rebased without conflicts and all comments from previous code review are addressed. Things left to do:

  • remove special handling of strings
  • add support for f-strings
  • (maybe?) refactor using a VISIT-style macro

@ambv
Copy link
Contributor

Special handling of strings removed. I plan to add the missing f-string support in the first week of January so that the implementation is hopefully mergeable in 3.7.0a4.

@ambv
Copy link
Contributor

Alright,@serhiy-storchaka, this is complete now, including f-string support! I realize it's pretty last minute, sorry for that.

A piece of useless statistics: this pull request was implementedin full during intercontinental flights. There's something very tranquil about sitting in one place for 10+ hours with no distractions.

auvipy, tirkarthi, DrLuke, siorai, osfanbuff63, covertg, and caprx-mutterberg reacted with hooray emoji

class B:
...

Since this change breaks compatibiltiy, the new behavior can be enabled

Choose a reason for hiding this comment

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

Small typo - compatibiltiy -> compatibility

ambv reacted with thumbs up emoji
Copy link
Contributor

Choose a reason for hiding this comment

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

Fixed, thanks!

Copy link
Member

@1st11st1 left a comment
edited
Loading

Choose a reason for hiding this comment

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

Overall looks good. Code inPython/ast_unparse.c looks fine, I didn't see any refleaks or non-checked return values. I think we can go ahead with this one and merge it, we'll have plenty of time to catch any bugs during the beta/rc period.

Strongbone315

This comment was marked as spam.

Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment

Reviewers

@ambvambvambv left review comments

@serhiy-storchakaserhiy-storchakaserhiy-storchaka left review comments

@emilyemorehouseemilyemorehouseemilyemorehouse left review comments

@1st11st11st1 approved these changes

+2 more reviewers

@Strongbone315Strongbone315Strongbone315 left review comments

@auvipyauvipyauvipy approved these changes

Reviewers whose approvals may not affect merge requirements

Assignees

@ambvambv

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

10 participants

@gvanrossum@serhiy-storchaka@ambv@ilevkivskyi@1st1@emilyemorehouse@auvipy@Strongbone315@the-knights-who-say-ni@bedevere-bot

[8]ページ先頭

©2009-2026 Movatter.jp