On Tue, 28 Jun 2016 06:56 am, Pavel S wrote: > Hi, > I today uncovered subtle bug and would like to share it with you. > > By a mistake, I forgot to put comma into '__all__' tuple of some module. > Notice missing comma after 'B'. > > # module foo.py > __all__ = ( > 'A', > 'B' > 'C', > )
Right. That's a language feature: implicit concatenation of string literals. If you have two string literals separated by nothing but whitespace, the compiler will concatenate them: s = 'He said, "Hello, did you see where' " they're" ' going?"' is equivalent to: s = 'He said, "Hello, did you see where they\'re going?"' > If you try to import * from the module, it will raise an error, because > 'B' and 'C' will be concatenated into 'BC'. Correct. Exactly the same as if you had written: __all__ = ['A', 'BC', 'D'] > The bug won't be found until someone imports *. I always write a unit-test to check that everything in __all__ exists. > In order to identify problems as soon as possible, here's the proposal. > > Porposal: allow putting objects into __all__ directly, so possible > problems will be found earlier: > > # module foo.py > class A: pass > class B: pass > class C: pass > > __all__ = (A, B, C) There are two problems with this idea. Suppose you have this: prefs_file = "filename" __all__ = (prefs_file, A, B, C) # suppose A, B and C are all defined Obviously, the intention is that the caller can say: from themodule import * print(prefs_file) and "filename" will be printed. But there's two problems: (1) the __all__ tuple doesn't know anything about the name "prefs_file". It only knows about "filename", the object (value) of prefs_file. So there is no way for the import system to know what name to use for that value: ????? = "filename" (2) For backwards-compatibility, we still need to support the old way of writing __all__, using names given as strings: __all__ = ('prefs_file', 'A', 'B', 'C') But now you have an ambiguity. If __all__ looks like this: __all__ = (prefs_file, A, B, C) does the first entry mean "import the value 'filename'" (new behaviour), or does it mean "import the value with the name 'filename'" (old behaviour)? -- Steven “Cheer up,” they said, “things could be worse.” So I cheered up, and sure enough, things got worse. -- https://mail.python.org/mailman/listinfo/python-list