Sometimes, you have an API:
@abc.abstractmethod
def get_property_value(self, prop):
"""Returns the value associated with the given property.
Args:
prop (DataProperty): The property.
Returns:
The value associated with the given property.
Raises:
PropertyError: If the property is not supported by this config
source.
LookupError: If the property is supported, but isn't available.
ValueError: If the property doesn't have exactly one value.
"""
raise PropertyError
and you don't want your API to mask bugs. How would it mask bugs? For
example, if API consumers do an:
try:
x = foo.get_property_value(prop)
except ValueError:
# handle it
then the following implementation:
def get_property_value(self, prop):
iterator = self.get_property_values(prop)
try:
# note: unpacking
ret, = iterator
except LookupError as exc: raise RuntimeError from exc # don't
accidentally swallow bugs in the iterator
return ret
def get_property_values(self, prop):
try:
factory = self.get_supported_properties()[prop]
except KeyError as exc: raise PropertyError from exc
iterator = factory(self._obj)
try:
first = next(iterator)
except StopIteration: return (x for x in ())
except abdl.exceptions.ValidationError as exc: raise
LookupError from exc
except LookupError as exc: raise RuntimeError from exc # don't
accidentally swallow bugs in the iterator
return itertools.chain([first], iterator)
could cause you to accidentally swallow unrelated ValueErrors.
so instead this needs to be rewritten. you can't just unpack things from
the iterator, you need to wrap the iterator into another iterator, that
then converts ValueError into RuntimeError.
but if that ValueError is part of *your* API requirements... it's
impossible to use!
so my proposal is that we get "exception spaces". they'd be used through
the 'in' keyword, as in "except in" and "raise in".
for example:
X = object()
Y = object()
def foo():
raise LookupError in X
def bar():
try:
foo()
except LookupError in Y:
print("bar: caught LookupError in Y, ignoring")
def baz():
try:
bar()
except LookupError in X:
print("baz: caught LookupError in X, re-raising in Y")
raise in Y
def qux():
try:
baz()
except LookupError in Y:
print("qux: caught LookupError in Y, ignoring")
qux()
# would print:
# ---
# baz: caught LookupError in X, re-raising in Y
# qux: caught LookupError in Y, ignoring
# ---
# note the lack of "bar"
(or perhaps "raise in X LookupError" and "except in Y LookupError" etc)
and then you can adjust the above implementations accordingly:
(btw, anyone knows how to tell apart a ValueError from a specific
unpacking and a ValueError from an iterator being used in that unpacking?)
def get_property_value(self, prop, espace=None):
iterator = self.get_property_values(prop, espace=espace)
try:
# note: unpacking
ret, = iterator
except ValueError: raise in espace
# except LookupError as exc: raise RuntimeError from exc # no
longer needed
return ret
def get_property_values(self, prop, espace=None):
try:
factory = self.get_supported_properties()[prop]
except KeyError as exc: raise PropertyError in espace from exc
iterator = factory(self._obj)
try:
first = next(iterator)
except StopIteration: return (x for x in ())
except abdl.exceptions.ValidationError as exc: raise
LookupError in espace from exc
# except LookupError as exc: raise RuntimeError from exc # no
longer needed
return itertools.chain([first], iterator)
as well as the caller:
espace = object()
try:
x = foo.get_property_value(prop, espace=espace)
except ValueError in espace:
# handle it
I feel like this feature would significantly reduce bugs in python code,
as well as significantly improve the error messages related to bugs.
This would be even better than what we did with StopIteration! This
would be comparable to Rust's Result type, where you can have
Result<Result<YourValue, YourError>, TheirError> and the like (except
slightly/a lot more powerful).
_______________________________________________
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/J76S2NBEVKX2MHZULELM22IHT5H7KLP3/
Code of Conduct: http://python.org/psf/codeofconduct/