Skip to content

gh-150459: Fix SyntaxError message for from x lazy import y#150877

Open
sobolevn wants to merge 4 commits into
python:mainfrom
sobolevn:issue-150459
Open

gh-150459: Fix SyntaxError message for from x lazy import y#150877
sobolevn wants to merge 4 commits into
python:mainfrom
sobolevn:issue-150459

Conversation

@sobolevn

@sobolevn sobolevn commented Jun 3, 2026

Copy link
Copy Markdown
Member

There's a problem with another branch of from ... import.
Because from .lazy import and from . lazy import is the same thing from the parser's point of view.

Things I've tried:

    | 'from' ('.' | '...')+ a="lazy" 'import' import_from_targets {
        RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a,
            "use 'lazy from ... ' instead of 'from ... lazy import'") }

What do I suggest? Maybe we can add an exception note for from .lazy import y when ImportError is raised with a similar message?


Update: Thanks a lot to @gpshead for the SyntaxWarning idea and draft implementation. See #150877 (comment)

@johnslavik johnslavik left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

❤️❤️❤️

Excellent

@gpshead

gpshead commented Jun 4, 2026

Copy link
Copy Markdown
Member

I think we can go further and detect this insignificant whitespace between the . and NAME tokens specifically when the name in question is lazy.

@sobolevn

sobolevn commented Jun 4, 2026

Copy link
Copy Markdown
Member Author

@gpshead I am not sure that this is really possible without introducing breaking changes.
For example, people might have this code in Python 3.14:

# lazy.py
x = 1

and

# example.py
from . lazy import x  # not-pep8 compatible, but working code
print(x)

If we change anything - we will break this code :(
What we can do is:

>>> from . lazy import x
<python-input-0>:2: ImportWarning: can't resolve package from __spec__ or __package__, falling back on __name__ and __path__
Traceback (most recent call last):
  File "<python-input-0>", line 2, in <module>
    from . lazy import x
ImportError: attempted relative import with no known parent package
Did you mean to use "lazy from . import"?

@gpshead

gpshead commented Jun 4, 2026

Copy link
Copy Markdown
Member
$ build/python -W always pkg/mod.py        # pkg/lazy.py exists, x = 42
pkg/mod.py:1: SyntaxWarning: 'from . lazy import' is the same as 'from .lazy import'; did you mean 'lazy from . import'?

is doable matching basically how the decimal literal special case works (thanks claude!). The bulk of the code winds up as in Parser/action_helpers.c and the unittest. everything else parser/grammar wise is pretty much one line changes if anyone wants to pick that up and run with it main...gpshead:cpython:claude/gifted-noether-pFmpK (i won't have time)

@pablogsal

Copy link
Copy Markdown
Member

This is may be a bit hacky though. In the world of the parser there are no more strings: just tokens. Although it's possible to reconstruct the "spacing" via the position information of the tokens this is a bit inelegant (at least with our parser theorist googles on) and I think is too much code for the small edge case that's this.

@sobolevn

sobolevn commented Jun 5, 2026

Copy link
Copy Markdown
Member Author

@gpshead @pablogsal I've implemented a much simplier warning code for this feature. Thanks a lot to @gpshead for the draft.

This is now ready to be reviewed. I would really like to get this into 3.15 as well, so it would be in sync with PEP-810 release. @hugovk can we do that, please? :)

@sobolevn

sobolevn commented Jun 5, 2026

Copy link
Copy Markdown
Member Author

Question: this seem unexpected that this warning happens twice in this case

» ./python.exe -c 'from . lazy import x'
<string>:1: SyntaxWarning: 'from . lazy import' is the same as 'from .lazy import'; did you mean 'lazy from . import'?
<string>:1: ImportWarning: can't resolve package from __spec__ or __package__, falling back on __name__ and __path__
Traceback (most recent call last):
<unknown>:1: SyntaxWarning: 'from . lazy import' is the same as 'from .lazy import'; did you mean 'lazy from . import'?
  File "<string>", line 1, in <module>
    from . lazy import x
ImportError: attempted relative import with no known parent package

What can be the cause of <unknown>:1: SyntaxWarning: 'from . lazy import' is the same as 'from .lazy import'; did you mean 'lazy from . import'?

@vstinner

vstinner commented Jun 5, 2026

Copy link
Copy Markdown
Member

test_peg_generator fails on the CI "Tests / Ubuntu / build and test (ubuntu-24.04-arm)":

ImportError: (...)/parse.cpython-316d-aarch64-linux-gnu.so: undefined symbol: _PyErr_EmitSyntaxWarning

You should export the symbol for test_peg_generator: use PyAPI_FUNC() in Include/internal/pycore_pyerrors.h and add a comment explaining that the symbol is needed by test_peg_generator.

@gpshead

gpshead commented Jun 7, 2026

Copy link
Copy Markdown
Member

I wouldn't worry about the double SyntaxWarning here. that's a pre-existing issue.

python3.14 -c '"\d" and undefined_name'

will do the same thing. The traceback module re-parses the source via ast.parse and warnings are deduped by filename and "<string>" and "<unknown>" don't match so... not a huge deal but could be fixed as a separate issue.

@hugovk

hugovk commented Jun 12, 2026

Copy link
Copy Markdown
Member

I would really like to get this into 3.15 as well, so it would be in sync with PEP-810 release. @hugovk can we do that, please? :)

Yes, that makes sense.

@hugovk hugovk added the needs backport to 3.15 pre-release feature fixes, bugs and security fixes label Jun 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

awaiting merge needs backport to 3.15 pre-release feature fixes, bugs and security fixes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants