Hi Marc-André,
Thanks for providing a clear example case! I agree that delayed errors can be a problem. I am a bit confused as to exactly where your disagreement with PEP 690 is, though, since I think the PEP already provides the tools needed to handle this case: in fact what the PEP already proposes is very similar to your sys.lazy_import_unsafe
.
You say:
But this is not true! Quoting directly from the PEP:
So the PEP spells it importlib.set_eager_imports(['fast_csv'])
instead of sys.lazy_import_unsafe.add('fast_csv.config')
; otherwise it seems quite similar to what you propose.
In fact the callback option also allows your “opt in just a few modules” case, too: define a callback that implements an allow-list instead of a block-list.
One difference is that the PEP proposes to name modules within which imports are eager, instead of modules whose import will always be eager. I don’t think this is a critical difference either way; as I described above I don’t really think describing fast_csv.config
as “lazy import unsafe” is accurate: rather I would say the usage of fast_csv.config
in the specific context of fast_csv
(whatever module defines parse_float
) is not safe to be lazy. (Although if we make the LazyImportError
change, then I think even that alone makes it OK.)
The other case the PEP does not currently support is the library author marking fast_csv.config
as lazy import unsafe. But if the library author is willing to bother accounting for lazy imports in the first place, they can just as easily “opt out” for a potentially problematic import by doing this:
with importlib.eager_imports():
import config
def parse_float(value):
...
So in sum: I agree with your concern, and your example case, and I think the PEP already provides all the tools required to handle it in a way that is not very different from what you propose; it seems more like API bikeshedding than a real difference in capability.
I still think the concern about delayed errors from imports biting someone is very real, and I love your idea for that:
I am inclined to think the PEP should include this. That way lazy errors will not silently pass as some other error in the way shown in your example.
I do think inheriting BaseException
is a step too far: except Exception:
should still catch LazyImportError
. If someone is catching all exceptions, they don’t want errors bubbling through and they are already accepting the risk that they might catch any random thing they don’t expect. I don’t think LazyImportError
is parallel to MemoryError
or KeyboardInterrupt
and deserves to be treated so differently; being a distinct exception type is sufficient to handle your example case.