Issue19266
This issue tracker has been migrated to GitHub,
and is currently read-only.
For more information,
see the GitHub FAQs in the Python's Developer Guide.
Created on 2013-10-15 11:50 by ncoghlan, last changed 2022-04-11 14:57 by admin. This issue is now closed.
Files | ||||
---|---|---|---|---|
File name | Uploaded | Description | Edit | |
cligsu.patch | zero.piraeus, 2013-10-15 13:33 | review |
Messages (22) | |||
---|---|---|---|
msg199995 - (view) | Author: Alyssa Coghlan (ncoghlan) * | Date: 2013-10-15 11:50 | |
Issue 15806 added contextlib.ignored to the standard library (later renamed to contextlib.ignore), as a simple helper that allows code like: try: os.remove(fname) except FileNotFoundError: pass to instead be written as: with ignore(FileNotFoundError): os.remove('somefile.tmp') The point has been made that "ignore" may easily be taken to mean preventing the exception being raised *at all* (since truly ignoring the exception would mean not skipping the rest of the with statement), rather than suppressing the exception in the context manager's __exit__ method. If you look at the rest of the contextlib docs, as well as the docs for the with statement and context manager objects, they don't refer to returning True from __exit__ as ignoring the exception, but rather as *suppressing* it. Even the docs for contextlib.ignore now make use of the term "suppress". So I think it makes sense to rename the context manager to "suppress", while keeping the same semantics: with suppress(FileNotFoundError): os.remove('somefile.tmp') |
|||
msg199996 - (view) | Author: Alyssa Coghlan (ncoghlan) * | Date: 2013-10-15 13:01 | |
The specific docs quotes that persuaded me "suppress" was a better name than "ignore" for this feature (by contrast, "ignore" in this sense only appears in its own docs): From http://docs.python.org/dev/library/stdtypes.html#contextmanager.__exit__: "Exit the runtime context and return a Boolean flag indicating if any exception that occurred should be suppressed." "Returning a true value from this method will cause the with statement to suppress the exception and continue execution with the statement immediately following the with statement. " From http://docs.python.org/dev/reference/datamodel.html#object.__exit__ "If an exception is supplied, and the method wishes to suppress the exception (i.e., prevent it from being propagated), it should return a true value." From http://docs.python.org/dev/library/contextlib#contextlib.contextmanager "If an exception is trapped merely in order to log it or to perform some action (rather than to suppress it entirely), the generator must reraise that exception." From http://docs.python.org/dev/library/contextlib#contextlib.ignore (!) "As with any other mechanism that completely suppresses exceptions, it should only be used to cover very specific errors where silently ignoring the exception is known to be the right thing to do." From http://docs.python.org/dev/library/contextlib#contextlib.ExitStack "...if an inner callback suppresses or replaces an exception, then outer callbacks will be passed arguments based on that updated state." From http://docs.python.org/dev/library/contextlib#contextlib.ExitStack.enter_context "These context managers may suppress exceptions just as they normally would if used directly as part of a with statement." From http://docs.python.org/dev/library/contextlib#contextlib.ExitStack.push "By returning true values, these callbacks can suppress exceptions the same way context manager __exit__() methods can." From http://docs.python.org/dev/library/contextlib#contextlib.ExitStack.callback "Unlike the other methods, callbacks added this way cannot suppress exceptions (as they are never passed the exception details)." |
|||
msg199997 - (view) | Author: Zero Piraeus (zero.piraeus) * | Date: 2013-10-15 13:33 | |
This is my first submitted patch; if there's anything wrong with it, please let me know (but the testsuite passes, and make patchcheck only warns about Misc/NEWS and Misc/ACKS, which I assume is handled by committer). |
|||
msg199998 - (view) | Author: Alyssa Coghlan (ncoghlan) * | Date: 2013-10-15 13:55 | |
Zero's patch looks good to me, but it may be a couple of days before I can get to applying it. If anyone else can handle it before then, please feel free :) Also, Zero, if you could review and sign the contributor agreement, that would be great: http://www.python.org/psf/contrib/contrib-form/ (while this patch is mechanical enough to be OK without one, it's still good to take care of the formalities of granting the PSF clear redistribution rights for CPython contributions) |
|||
msg199999 - (view) | Author: Zero Piraeus (zero.piraeus) * | Date: 2013-10-15 14:20 | |
> Zero, if you could review and sign the contributor agreement, that > would be great: http://www.python.org/psf/contrib/contrib-form/ Done :-) |
|||
msg200007 - (view) | Author: Raymond Hettinger (rhettinger) * | Date: 2013-10-15 16:28 | |
This patch looks fine. I'll apply it shortly. |
|||
msg200037 - (view) | Author: Raymond Hettinger (rhettinger) * | Date: 2013-10-16 07:25 | |
After more thought, I think that suppress() isn't as clear as ignore() and it doesn't read as well in typical use cases. I'm assigning this one back to Nick to decide. If you want to scan existing code for examples to see how well this would read, run this: $ egrep -C2 "except( [A-Za-z]+)?:" *py | grep -C2 "pass" |
|||
msg200039 - (view) | Author: STINNER Victor (vstinner) * | Date: 2013-10-16 07:47 | |
On python-dev, abort_on() and trap() were proposed. |
|||
msg200044 - (view) | Author: Raymond Hettinger (rhettinger) * | Date: 2013-10-16 09:11 | |
I oppose abort_on() because it implies that it aborts the program. The word trap() is accurate but will be weird-sounding and non-communicative to users without a CS background: with trap(sqlite3.OperationalError): cursor.execute('CREATE TABLE dict (key text, value text)') The word "trap" in a CS context is also archaic and falling out of use. (Remember, glob.glob() was a good name in 1990 but most people now don't get know the reference to "globbing" and so the word is meaningless gobbledygook to them). Please give some weight to the fact the ignore() was checked in for seven months, it was presented at a conference, I've put it front of working Python programmers to use in real code, and I've checked to see how it reads in the try/except/pass code examples in the standard library. Don't throw away this work on a whim. |
|||
msg200052 - (view) | Author: Stefan Krah (skrah) * | Date: 2013-10-16 10:18 | |
trap() is a bit ambiguous, since in floating point operations it means that something is actually raised and not suppressed. So one could write: from decimal import * c = getcontext() c.traps[Inexact] = True >>> Decimal(9) / 11 # raises now! with trap(Inexact): Decimal(9) / 11 # quiet! As for "ignore" vs. "suppress", I'm with the people who think that they are largely synonyms here. I find "ignore" slightly catchier and nicer to read. Being pedantic, one could call it "ignore_once". I would also like "catch", or pedantically, "catch_once". |
|||
msg200054 - (view) | Author: Zero Piraeus (zero.piraeus) * | Date: 2013-10-16 12:16 | |
'Ignore' and 'suppress' are not synonyms: https://www.google.com/search?q=define%3Asuppress > forcibly put an end to. > "the rising was savagely suppressed" > synonyms: subdue, repress, crush, quell, quash, squash, stamp out https://www.google.com/search?q=define%3Asuppress > refuse to take notice of or acknowledge; disregard intentionally. > "he ignored her outraged question" > synonyms: disregard, take no notice of, pay no attention to [...] I know that ncoghlan and rhettinger (and maybe others) are annoyed by what they see as bikeshedding, but there is a genuine issue here. To summarize the objection raised on python-dev, the problem is that this: with ignore(SomeException): do_something() do_something_else() ... is easily misunderstood as ignoring every occurrence of SomeException throughout the with-statement. If you understand how context managers work, it's not difficult to see why that's not the case, but the name strongly suggests the incorrect reading over the correct one. I don't think 'suppress' is perfect. At the risk of further enraging those who are already tired of this discusion, I'll re-propose 'silence', which IMO comes closest to describing what is actually going on: https://www.google.com/search?q=define%3Asilence > cause to become silent; prohibit or prevent from speaking. > "the team's performance silenced their critics" > synonyms: quiet, hush, shush I also quite like 'quash' from the list of 'suppress' synonyms above, but that's probably just because it's a nice word to say :-) |
|||
msg200056 - (view) | Author: Stefan Krah (skrah) * | Date: 2013-10-16 12:28 | |
Zero Piraeus <report@bugs.python.org> wrote: > 'Ignore' and 'suppress' are not synonyms: I wrote "synonyms here", meaning that in *this context* they are practically synonyms. "suppress" describes the mechanics more precisely, "ignore" descibes the human intent: suppress_and_thereby_ignore. |
|||
msg200091 - (view) | Author: Alexander Belopolsky (belopolsky) * | Date: 2013-10-16 22:40 | |
> Please give some weight to the fact the ignore() was > checked in for seven months, ... +1 |
|||
msg200092 - (view) | Author: R. David Murray (r.david.murray) * | Date: 2013-10-16 22:55 | |
Yes, in this context ingnore, suppress, and silence all have essentially the same problem, or lack of it, depending on your point of view. Catch would be fine with me :) Please note that someone *reading the thread* on python-dev misunderstood what ignore did after *reading the documentation*. So, whether or not the name is changed, the documentation should be updated to stress the fact that the with block is exited as soon as the exception is raised for the first time. |
|||
msg200093 - (view) | Author: R. David Murray (r.david.murray) * | Date: 2013-10-16 23:02 | |
To be clear: I do think 'suppress' is better than 'ignore', for the reasons Nick articulated. |
|||
msg200094 - (view) | Author: Raymond Hettinger (rhettinger) * | Date: 2013-10-16 23:04 | |
On Oct 16, 2013, at 3:55 PM, R. David Murray <report@bugs.python.org> wrote: > Catch would be fine with me :) I like "catch". Raymond |
|||
msg200095 - (view) | Author: Alyssa Coghlan (ncoghlan) * | Date: 2013-10-16 23:18 | |
I didn't choose suppress on a whim. I actually agree with Raymond that ignore reads better when the context manager is used correctly, but suppress is more consistent with the terminology used in the documentation (including even PEP 343), *and* I think it is slightly less vulnerable to people expecting it to mean "don't even raise the exception and continue with the next statement inside the with block" (aka the "on error resume next" misinterpretation). I think suppress reads *well enough* for it to be worth making the switch in order to gain those other benefits. |
|||
msg200096 - (view) | Author: Alyssa Coghlan (ncoghlan) * | Date: 2013-10-16 23:21 | |
The reason I specifically *don't* like trap or catch for this is that they both have "... and do something with it" connotations for me, whereas ignore and suppress both appropriately imply "... and silently discard it". |
|||
msg200097 - (view) | Author: Alexander Belopolsky (belopolsky) * | Date: 2013-10-16 23:24 | |
> Catch would be fine with me :) Both "catch" and "trap" have the same problem in my view: you don't get to eat what you have caught (or trapped). :-) > Please note that someone *reading the thread* on python-dev > misunderstood what ignore did after *reading the documentation*. I question whether the confusion was genuine. Anyone who has discovered contextlib modules should know enough about with statement, context managers and exceptions to understand how ignore() can work. Sky is the limit when it comes to documentation improvements, but in this case code is better than a thousand words: @contextmanager def ignore(*exceptions): """Context manager to ignore particular exceptions""" try: yield except exceptions: pass Here is how I understand the word "ignore" in the context of context managers. (Pun unavoidable.) The context manager implements logic of how to exit the with block. The logic of ignore() CM is to (drum roll, please) ignore the specified exception(s) if any is raised within the with block. I gave my +0 to "suppress" on the list, but with more thought and considering more examples, I like "ignore" best. It is still a close call, but "suppress" suggests more effort on the part of CM than there is. |
|||
msg200098 - (view) | Author: Alyssa Coghlan (ncoghlan) * | Date: 2013-10-16 23:29 | |
Agreed it's a close call - it's really the docs consistency issue that tipped the balance for me, since I think either ignore *or* suppress would be a suitable name for the pattern when used correctly. |
|||
msg200100 - (view) | Author: Alexander Belopolsky (belopolsky) * | Date: 2013-10-16 23:38 | |
Feel free to ignore() me if it helps to close this debate. English is not my native language and my understanding may not match that of the majority of users. Note, however, that this debate might not even have started if not for a change s/ignored/ignore/. The s/ignore/suppress/ commit may sparkle yet another round. (It is quite possible that my dislike of "suppress" stems from not being able to remember how many p's and s's this word has in its spelling. As I said - feel free to ignore me.) |
|||
msg200126 - (view) | Author: Roundup Robot (python-dev) | Date: 2013-10-17 13:42 | |
New changeset 22247b7d17fa by Nick Coghlan in branch 'default': Close #19266: contextlib.ignore -> contextlib.suppress http://hg.python.org/cpython/rev/22247b7d17fa |
History | |||
---|---|---|---|
Date | User | Action | Args |
2022-04-11 14:57:52 | admin | set | github: 63465 |
2013-10-17 13:42:52 | python-dev | set | status: open -> closed nosy: + python-dev messages: + msg200126 resolution: fixed stage: needs patch -> resolved |
2013-10-16 23:47:02 | vstinner | set | nosy:
- vstinner |
2013-10-16 23:38:18 | belopolsky | set | messages: + msg200100 |
2013-10-16 23:29:47 | ncoghlan | set | messages: + msg200098 |
2013-10-16 23:24:02 | belopolsky | set | messages: + msg200097 |
2013-10-16 23:21:37 | ncoghlan | set | messages: + msg200096 |
2013-10-16 23:18:19 | ncoghlan | set | messages: + msg200095 |
2013-10-16 23:04:47 | rhettinger | set | messages: + msg200094 |
2013-10-16 23:02:59 | r.david.murray | set | messages: + msg200093 |
2013-10-16 22:55:11 | r.david.murray | set | nosy:
+ r.david.murray messages: + msg200092 |
2013-10-16 22:40:48 | belopolsky | set | nosy:
+ belopolsky messages: + msg200091 |
2013-10-16 22:31:55 | belopolsky | link | issue15806 superseder |
2013-10-16 22:31:31 | belopolsky | set | dependencies: + Add context manager for the "try: ... except: pass" pattern |
2013-10-16 12:28:30 | skrah | set | messages: + msg200056 |
2013-10-16 12:16:59 | zero.piraeus | set | messages: + msg200054 |
2013-10-16 10:18:46 | skrah | set | nosy:
+ skrah messages: + msg200052 |
2013-10-16 09:11:29 | rhettinger | set | messages: + msg200044 |
2013-10-16 07:47:50 | vstinner | set | nosy:
+ vstinner messages: + msg200039 |
2013-10-16 07:25:20 | rhettinger | set | assignee: rhettinger -> ncoghlan messages: + msg200037 |
2013-10-15 16:28:43 | rhettinger | set | assignee: rhettinger messages: + msg200007 |
2013-10-15 14:20:31 | zero.piraeus | set | messages: + msg199999 |
2013-10-15 13:55:00 | ncoghlan | set | messages: + msg199998 |
2013-10-15 13:33:30 | zero.piraeus | set | files:
+ cligsu.patch nosy: + zero.piraeus messages: + msg199997 keywords: + patch |
2013-10-15 13:15:30 | barry | set | nosy:
+ barry |
2013-10-15 13:01:29 | ncoghlan | set | messages: + msg199996 |
2013-10-15 11:50:54 | ncoghlan | create |