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/
