On Aug 14, 2019, at 06:19, Marat Sharafutdinov <[email protected]> wrote:
> 
> 
> The essence of my idea is simple and does not affects compatibility with 
> existing code: to automatically define a magic attribute of module under the 
> working name "__exception__" while importing any module. It can be used in 
> usual way, for example:
>>>> try:
> ...     any_module.anything
> ... except any_module.__ exception__:
> ...     ...
> 
> Here any exception an author of library raises can be handled. This way you 
> can handle any exception that occurs in the library without even knowing what 
> exceptions it can raise.

I think you need to come up with a complete implementation mechanism (not 
necessarily trying to actually code it in C, just being able to write it in 
pseudocode or reference-style description). Without that, there are just way 
too many questions for the idea to really be judged. And trying to answer those 
questions one by one will probably just lead to something contradictory and 
unimplementable, but describing an implementation will immediately answer most 
of the questions. (And if some of them are answered in a way you don’t like, 
it’ll force you to think about how you could change the design to get the right 
answer.)

For example:

How do you define “library” here? Does it include submodules? What if it’s a 
namespace package, with submodules provides by different libraries? What about 
things that are defined in a private sibling module but publicly re-exported by 
the module (as with, e.g., most C accelerators in the stdlib)? Or monkeypatched 
into the module?

What about things defined by exec within a module? Or things like namedtuple, 
where the semantics are clearly defined by the module that uses namedtuple but 
the code is compiled by exec in the collections module? (Does it matter whose 
globals are passed to exec?) Or exceptions raised by decorators like dataclass 
or total_ordering or partial that are semantically meant to be treated as 
exceptions raised by the decorated class or function but that are defined in 
the decorator code? 

If you reraise an exception with bare raise, can it now be caught with your 
module’s __exceptions__? What if you reraise it explicitly with `except 
Exception as e: raise e`?

What if the exception is constructed in one module but raised in another? What 
about generator.throw, where the actual raiser is the interpreter itself, but 
clearly the reader sees it as being raised by the caller of throw? Or 
user-level code that acts like generator.throw (e.g., to throw an exception 
into a thread or run loop); is the module the thrower or the implementor of 
throw?

Does it only handle Exception and its subclasses raised by the module, or 
everything?

Whatever the rule, how is it applied? Does the importer build an __exceptions__ 
tuple while or after compiling the code? Then what happens with C modules, 
dynamically-constructed modules, etc.? (If it’s a tuple but not obviously a 
tuple, what happens when someone quite naturally writes except (IOError, 
yourmod.__exceptions__):?) If it’s not a tuple but something semi-magical that 
tests something dynamic like the __ module__ of the exception being raised, 
what is the magic? How does this it fit into the existing mechanism that just 
stacks up types for try blocks? And what’s the value of __exceptions__ if you 
inspect it?

Can a module override the behavior? For example, if a stdlib or third party 
module already went to a lot of trouble to define an error base class that 
serves the intended function here (possibly making different judgment calls on 
some of those questions, but they’re the ones the user wants, or at least the 
ones the author thinks the user wants), can that module assign __exceptions__ = 
error?

> Developing this idea, it could be more universal mechanism that works not 
> only with modules, but with any objects of the language.

Does a class’s __exceptions__ only include exceptions from the class body? From 
any methods defined in the class body? From any methods found in the class’s 
__dict__ at runtime? (Maybe the __module__ gets added at descriptor __get__ 
time?) Does it include nested classes? Do any of base classes, metaclasses, or 
class decorators count as part of the class?

Can you use it on any object, to catch exceptions raised explicitly by that 
object’s class but only when self matches the object? (What happens if you call 
a classmethod on the object, possibly without even realizing it’s a 
classmethod?) Or some other rule? Whatever that rule is, is it ignored by the 
special rules for module, type, and function, or do they just add their special 
rules to the generic object rule?

On a function, does it include local functions? Classes defined within the 
function? Exec from within the function (does it depend whose locals are 
passed)?

What about a callable that’s not a function or class? Does it just catch 
exceptions raised inside the __call__ method itself?

And so on.

_______________________________________________
Python-ideas mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/[email protected]/message/HWMZKWJGWCPPB3CR4YOKLURBTPL45LMV/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to