08.12.20 21:47, Gregory Szorc пише:
> PyOxidizer's pure Rust implementation of a meta path importer
> (https://pyoxidizer.readthedocs.io/en/stable/oxidized_importer_oxidized_finder.html)
> has been surprisingly effective at finding corner cases and behavior
> quirks in Python's importing mechanisms.
> 
> It was recently brought to my attention via
> https://github.com/indygreg/PyOxidizer/issues/317 that "__init__" in
> module names is something that exists in Python code in the wild. (See
> https://github.com/search?l=Python&q=%22from+.__init__+import%22&type=Code
> for some examples.)
> 
> In that GitHub issue and https://bugs.python.org/issue42564, I
> discovered that what's happening is the stdlib PathFinder meta path
> importer is "dumb" and doesn't treat "__init__" in module names
> specially. If someone uses syntax like "import foo.__init__" or "from
> .__init__ import foo", PathFinder operates on "__init__" like any other
> string value and proceeds to probe the filesystem for the relevant {.py,
> .pyc, .so, etc} files. The "__init__" files do exist in probed locations
> and PathFinder summarily constructs a new module object, albeit with
> "__init__" in its name. The end result is you have 2 module objects and
> sys.modules entries referring to the same file, keyed to different names
> (e.g. "foo" and "foo.__init__").
> 
> There is a strong argument to be made that "__init__" in module names
> should be treated specially. It seems wrong to me that you are allowed
> to address the same module/file through different names (let's pretend
> filesystem path normalization doesn't exist) and that the filesystem
> encoding of Python module files/names is addressable through the
> importer names. This feels like a bug that inadvertently shipped.
> 
> However, code in the wild is clearly relying on "__init__" in module
> names being allowed. And changing the behavior is backwards incompatible
> and could break this code.
> 
> Anyway, I was encouraged by Brett Cannon to email this list to assess
> the appetite for introducing a backwards incompatible change to this
> behavior. So here's my strawman/hardline proposal:
> 
> 1. 3.10 introduces a DeprecationWarning for "__init__" appearing as any
> module part component (`"__init__" in fullname.split(".")`).
> 2. Some future release (I'm unsure which) turns it into a hard error.
> 
> (A less aggressive proposal would be to normalize "__init__" in module
> names to something more reasonable - maybe stripping trailing
> ".__init__" from module names. But I'll start by proposing the stricter
> solution.)
> 
> What do others think we should do?

Thank you for good explanation of the problem.

Initially I though that this problem is not worth our attention. It just
does not happen in normal code. If a newbie writes like that and get a
bug because of it, he will learn from his mistake and will not write it
next time. This should be a task for linters to warn about such code.

But beginners and non-professionals do not use linters. And from what
confusion your message caused to commenters in this thread, I changed my
mind and inclined to agree with you. Yes, it may be worth to add a
runtime test to the import machinery.

There are similar precedences of warnings about obviously wrong code:

* `a is 0` currently works on CPython, and always worked, but this code
is clearly semantically incorrect. Now you will get a SyntaxWarning.

* `if a.__lt__(b):` may work most of times, but it can work incorrectly
when types are non-comparable and the result is NotImplemented. Now you
will get DeprecationWarning.
_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/DLEFXMD7LH6AMQD6DG3YAKVND27VIBKD/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to