Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rename contextlib.ignore to contextlib.suppress #63465

Closed
ncoghlan opened this issue Oct 15, 2013 · 22 comments
Closed

Rename contextlib.ignore to contextlib.suppress #63465

ncoghlan opened this issue Oct 15, 2013 · 22 comments
Assignees
Labels
stdlib Python modules in the Lib dir type-feature A feature request or enhancement

Comments

@ncoghlan
Copy link
Contributor

BPO 19266
Nosy @warsaw, @rhettinger, @ncoghlan, @abalkin, @bitdancer, @skrah
Dependencies
  • bpo-15806: Add context manager for the "try: ... except: pass" pattern
  • Files
  • cligsu.patch
  • Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

    Show more details

    GitHub fields:

    assignee = 'https://github.com/ncoghlan'
    closed_at = <Date 2013-10-17.13:42:52.934>
    created_at = <Date 2013-10-15.11:50:54.804>
    labels = ['type-feature', 'library']
    title = 'Rename contextlib.ignore to contextlib.suppress'
    updated_at = <Date 2013-10-17.13:42:52.883>
    user = 'https://github.com/ncoghlan'

    bugs.python.org fields:

    activity = <Date 2013-10-17.13:42:52.883>
    actor = 'python-dev'
    assignee = 'ncoghlan'
    closed = True
    closed_date = <Date 2013-10-17.13:42:52.934>
    closer = 'python-dev'
    components = ['Library (Lib)']
    creation = <Date 2013-10-15.11:50:54.804>
    creator = 'ncoghlan'
    dependencies = ['15806']
    files = ['32133']
    hgrepos = []
    issue_num = 19266
    keywords = ['patch']
    message_count = 22.0
    messages = ['199995', '199996', '199997', '199998', '199999', '200007', '200037', '200039', '200044', '200052', '200054', '200056', '200091', '200092', '200093', '200094', '200095', '200096', '200097', '200098', '200100', '200126']
    nosy_count = 8.0
    nosy_names = ['barry', 'rhettinger', 'ncoghlan', 'belopolsky', 'r.david.murray', 'skrah', 'python-dev', 'zero.piraeus']
    pr_nums = []
    priority = 'normal'
    resolution = 'fixed'
    stage = 'resolved'
    status = 'closed'
    superseder = None
    type = 'enhancement'
    url = 'https://bugs.python.org/issue19266'
    versions = ['Python 3.4']

    @ncoghlan
    Copy link
    Contributor Author

    bpo-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')

    @ncoghlan ncoghlan added stdlib Python modules in the Lib dir type-feature A feature request or enhancement labels Oct 15, 2013
    @ncoghlan
    Copy link
    Contributor Author

    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)."

    @zeropiraeus
    Copy link
    Mannequin

    zeropiraeus mannequin commented Oct 15, 2013

    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).

    @ncoghlan
    Copy link
    Contributor Author

    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)

    @zeropiraeus
    Copy link
    Mannequin

    zeropiraeus mannequin commented Oct 15, 2013

    Zero, if you could review and sign the contributor agreement, that
    would be great: http://www.python.org/psf/contrib/contrib-form/

    Done :-)

    @rhettinger
    Copy link
    Contributor

    This patch looks fine. I'll apply it shortly.

    @rhettinger rhettinger self-assigned this Oct 15, 2013
    @rhettinger
    Copy link
    Contributor

    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"

    @rhettinger rhettinger assigned ncoghlan and unassigned rhettinger Oct 16, 2013
    @vstinner
    Copy link
    Member

    On python-dev, abort_on() and trap() were proposed.

    @rhettinger
    Copy link
    Contributor

    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.

    @skrah
    Copy link
    Mannequin

    skrah mannequin commented Oct 16, 2013

    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".

    @zeropiraeus
    Copy link
    Mannequin

    zeropiraeus mannequin commented Oct 16, 2013

    '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 :-)

    @skrah
    Copy link
    Mannequin

    skrah mannequin commented Oct 16, 2013

    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.

    @abalkin
    Copy link
    Member

    abalkin commented Oct 16, 2013

    Please give some weight to the fact the ignore() was
    checked in for seven months, ...

    +1

    @bitdancer
    Copy link
    Member

    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.

    @bitdancer
    Copy link
    Member

    To be clear: I do think 'suppress' is better than 'ignore', for the reasons Nick articulated.

    @rhettinger
    Copy link
    Contributor

    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

    @ncoghlan
    Copy link
    Contributor Author

    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.

    @ncoghlan
    Copy link
    Contributor Author

    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".

    @abalkin
    Copy link
    Member

    abalkin commented Oct 16, 2013

    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.

    @ncoghlan
    Copy link
    Contributor Author

    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.

    @abalkin
    Copy link
    Member

    abalkin commented Oct 16, 2013

    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.)

    @python-dev
    Copy link
    Mannequin

    python-dev mannequin commented Oct 17, 2013

    New changeset 22247b7d17fa by Nick Coghlan in branch 'default':
    Close bpo-19266: contextlib.ignore -> contextlib.suppress
    http://hg.python.org/cpython/rev/22247b7d17fa

    @python-dev python-dev mannequin closed this as completed Oct 17, 2013
    @ezio-melotti ezio-melotti transferred this issue from another repository Apr 10, 2022
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
    Labels
    stdlib Python modules in the Lib dir type-feature A feature request or enhancement
    Projects
    None yet
    Development

    No branches or pull requests

    5 participants