> If you’re wondering why this works, it’s because Error and InputError
don’t override __new__. Which should make it obvious why a tutorial aimed
at novices doesn’t get into the details, but that’s why Python has
reference manuals instead of just a tutorial.

Between the links I've found, none of them refer to BaseException.__new__
setting up args, and the references to args make it sound like an optional
thing or something the built-in exceptions handle themselves.

https://docs.python.org/3/library/exceptions.html
https://docs.python.org/3/c-api/exceptions.html
https://docs.python.org/3/tutorial/errors.html

Okay, so this __new__/__init__ divide is sort of a hack because you can't
trust users to call super().__init__(...) on their user-defined exceptions?
No judgement, just trying to wrap my head around this.

It sounds like BaseException.args is mostly used for generating strings?
Couldn't I just get away with overriding __str__, __repr__? I understand
that existing built-in exception classes have some semantic value
associated with arguments in given positions, but that wouldn't apply to
new user-defined exceptions. And going forward, if you wanted to make your
tool extract a value, it doesn't seem like it should make a big difference
to access exc.arg[3] or exc.thing.

I've also looked at giving the formatted message as args[0], but I haven't
figured out how to handle a class with an explicit __init__ that defines
a POSITIONAL_OR_KEYWORD argument, like this:
https://github.com/rcfox/exception-template/blob/master/tests/test.py#L58 The
'key' argument ends up getting thrown in with kwargs. Maybe I just get rid
of the error check for extra arguments given?

> I also just realized that your class won't have any helpful introspection
on the call signature either, so all users of your class will have to
document in the docstring very clearly what is expected in the constructor
call as their code editors won't be able to tell them and help()/inspect
won't be able to help either.

I won't try to convince you that this is a good solution, but
help()/inspect could at least be tricked with a metaclass that replaces the
signature of __init__:

    class _Signaturizer(type):
        def __new__(cls, name, bases, classdict):
            result = super().__new__(cls, name, bases, classdict)
            args = set(name for _, name, _, _ in
result.formatter.parse(result.message) if name)
            params = [inspect.Parameter(a, inspect.Parameter.KEYWORD_ONLY)
for a in sorted(args)]
            result.__init__.__signature__ =
inspect.signature(result.__init__).replace(parameters=params)
            return result

    class ExceptionTemplate(Exception, metaclass=_Signaturizer):
    # ...

Of course, tools that rely on static analysis wouldn't be fooled.


On Fri, Aug 9, 2019 at 1:57 PM Sebastian Kreft <skr...@gmail.com> wrote:

>
>
> On Fri, Aug 9, 2019 at 12:55 PM Brett Cannon <br...@python.org> wrote:
>
>>
>>
>> On Thu, Aug 8, 2019 at 5:24 PM Sebastian Kreft <skr...@gmail.com> wrote:
>>
>>>
>>>
>>> On Thu, Aug 8, 2019 at 7:09 PM Andrew Barnert via Python-ideas <
>>> python-ideas@python.org> wrote:
>>>
>>>> On Aug 8, 2019, at 15:01, Ryan Fox <r...@rcfox.ca> wrote:
>>>>
>>>> I don't see why you would want to access arguments by their position.
>>>>
>>>>
>>>> Because that’s the way it’s worked since Python 1.x, and there’s tons
>>>> of existing code that expects it, including the default __str__ and
>>>> __repr__ for exceptions and the code that formats tracebacks.
>>>>
>>> I don't really understand what you mean here. This property was broken
>>> since ImportError started accepting keyword arguments.
>>>
>>
>> The property isn't broken for ImportError, it just isn't being given the
>> keyword arguments because it didn't makes sense to pass them down with no
>> information attached to it. The 'args' attribute still gets the message
>> which is the key detail.
>>
> The "broken" property was alluding to Andrew's comment that exception
> arguments need to be positional and cannot/shouldn't be keywords and I was
> giving an example from the standard library in which we can pass keyword
> arguments which are not stored in the exception's arguments.
>
> Also note that my comment mentioned that passing the formatted message as
> the only argument to the super constructor would solve the compatibility
> problem.
>
>
>>
>> -Brett
>>
>>
>>>
>>> For example:
>>>
>>> >>> ImportError("message", name="name", path="path").args
>>> ('message',)
>>>
>>> >>> ImportError("message", "foo", name="name", path="path").args
>>> ('message', 'foo')
>>>
>>> For the case of str and repr, one could just call super with the
>>> formatted message as the only positional argument.
>>>
>>>
>>> I suggest taking a look at PEP 473
>>> <https://www.python.org/dev/peps/pep-0473/> for ideas on why having
>>> structured arguments is a good idea.
>>>
>>>>
>>>> The user-defined exceptions in the Python documentation don't pass
>>>> arguments to the base class either:
>>>> https://docs.python.org/3/tutorial/errors.html#user-defined-exceptions
>>>>
>>>>
>>>> Yes they do. Try it:
>>>>
>>>>     >>> e = InputError('[2+3)', 'mismatched brackets')
>>>>     >>> e.args
>>>>     ('[2+3)', 'mismatched brackets')
>>>>     >>> e
>>>>     InputError('[2+3)', 'mismatched brackets')
>>>>
>>>> If you’re wondering why this works, it’s because Error and InputError
>>>> don’t override __new__. Which should make it obvious why a tutorial aimed
>>>> at novices doesn’t get into the details, but that’s why Python has
>>>> reference manuals instead of just a tutorial.
>>>>
>>>> Also, notice that the tutorial examples don’t even try to create a
>>>> formatted message; they expect that the type name and the args will be
>>>> enough for debugging. I’m not sure that’s a great design, but it means that
>>>> your intended fix only solves a problem they didn’t even have in the first
>>>> place.
>>>>
>>>> So let's go ahead and assume my implementation is flawed. The fact that
>>>> people prefer to copy their format strings all over their projects implies
>>>> that the current exception scheme is suboptimal. Can we agree on that? If
>>>> not, there's no need to continue this discussion.
>>>>
>>>>
>>>> I agree that it would be nice for more people to move their message
>>>> formatting into the class, but you need a design that encourages that
>>>> without fighting against the fact that exception args are positional, and
>>>> I’m not sure what that looks like. And I don’t think it’s your
>>>> implementation that’s bad (it seems to do what it says perfectly well), but
>>>> that the design doesn’t work.
>>>>
>>>> Of course if you were designing a new language (or a new library from
>>>> builtins up for the same language), this would be easy. Exceptions would
>>>> look like (maybe be) @dataclasses, storing their arguments by name and
>>>> generating repr/str/traceback that takes that into account, and all of them
>>>> would actually store the relevant values instead of half of them making you
>>>> parse it out of the first arg, and there would be a special message
>>>> property or method instead of args[0] being sort of special but not special
>>>> enough, and so on. And then, providing an easier way to create that message
>>>> property would be an easy problem. But I think with the way Python is
>>>> today, it’s not.
>>>>
>>>> Of course I’d be happy to be proven wrong on that.  :)
>>>> _______________________________________________
>>>> 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/5ULPVNH6RBFXY24P76YZCAKIKOLHWF2B/
>>>> Code of Conduct: http://python.org/psf/codeofconduct/
>>>>
>>>
>>>
>>> --
>>> Sebastian Kreft
>>> _______________________________________________
>>> 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/ZOLTXVQPUFWFJXO66JT7JEP2BMLVC5OF/
>>> Code of Conduct: http://python.org/psf/codeofconduct/
>>>
>>
>
> --
> Sebastian Kreft
> _______________________________________________
> 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/426DOBJMY4AV5Q3BCRBAC2SITHTHTNDG/
> Code of Conduct: http://python.org/psf/codeofconduct/
>
_______________________________________________
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/O5AO4UH7PXTJIPE36HIHNPXR5GK5YJ5F/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to