[Distutils] A possible refactor/streamlining of PEP 517

Nick Coghlan ncoghlan at gmail.com
Mon Jul 17 23:02:27 EDT 2017


On 17 July 2017 at 23:06, Nathaniel Smith <njs at pobox.com> wrote:
> On Mon, Jul 17, 2017 at 5:56 AM, Nick Coghlan <ncoghlan at gmail.com> wrote:
>> As an added bonus: the frontend could display the exception message as
>> part of executing the fallback.
>
> I can live with this, but I wrote up a rationale for why it's somewhat
> worse than the alternative:
> https://mail.python.org/pipermail/distutils-sig/2017-July/030901.html
>
> So my request is that if you're going to insist on this can you
> provide some similar rationale for why?

Sure: because of the way magic return values fail if the *frontend*
doesn't check for them.

That is, if we make the protocol "return NotImplemented", then the
likely symptom of a missing check in a frontend is going to be
something like this (on 3.6+):

   >>> open(NotImplemented)
   Traceback (most recent call last):
     File "<stdin>", line 1, in <module>
   TypeError: expected str, bytes or os.PathLike object, not NotImplementedType

Or, on Python 2.7, the even more cryptic:

   >>> open(NotImplemented)
   Traceback (most recent call last):
     File "<stdin>", line 1, in <module>
   TypeError: coercing to Unicode: need string or buffer,
NotImplementedType found

And on earlier versions of Python 3.x:

   >>> open(NotImplemented)
   Traceback (most recent call last):
     File "<stdin>", line 1, in <module>
   TypeError: invalid file: NotImplemented

And any associated exception traceback won't point to the offending
unchecked call to backend.build_sdist, it will point to the first
attempted *use* of that return value as a filename.

By contrast, if we make the error signal "raise NotImplementedError",
then a missing check in the frontend will not only reliably give a
traceback that points to the failed build_sdist call (since
NotImplementedError will be treated the same as any other exception by
default), but it will also include any specific message that the
backend developers chose to provide.

If backend implementors want to ensure that it's categorically
impossible for NotImplementedError to escape unexpectedly, they can
write their build_sdist like this:

    def build_sdist(sdist_directory, config_settings=None):
        try:
           problem = check_sdist_preconditions(sdist_directory, config_settings)
        except NotImplementedError as exc:
            raise RuntimeErrror("Unexpected NotImplementedError when
checking sdist preconditions") from exc
        if problem:
            raise NotImplementedError(problem)
        try:
            return _make_sdist(sdist_directory, config_settings)
        except NotImplementedError as exc:
            raise RuntimeErrror("Unexpected NotImplementedError when
making sdist") from exc

However, Python APIs letting NotImplementedError escape is rare enough
that even I'd consider writing a build_sdist implementation that way
as being overly paranoid :)

Cheers,
Nick.

-- 
Nick Coghlan   |   ncoghlan at gmail.com   |   Brisbane, Australia


More information about the Distutils-SIG mailing list