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

gh-96348: Deprecate the 3-arg signature of coroutine.throw, generator.throw and agen.athrow #96428

Merged
merged 30 commits into from
Sep 30, 2022

Conversation

ofey404
Copy link
Contributor

@ofey404 ofey404 commented Aug 30, 2022

Add an deprecation warning, when nargs > 1 in Objects/genobject.c:gen_throw.

  • Also change corresponding docstrings.

@bedevere-bot
Copy link

Most changes to Python require a NEWS entry.

Please add it using the blurb_it web app or the blurb command-line tool.

@ofey404
Copy link
Contributor Author

ofey404 commented Aug 30, 2022

There is a problem: raise DeprecationWarning will break many lib tests, since they use the (type, val, tb) exception representation.

Eg:

cpython/Lib/contextlib.py

Lines 154 to 155 in 22ed523

try:
self.gen.throw(typ, value, traceback)

Copy link
Member

@gvanrossum gvanrossum left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One nit. Too bad about the failing tests, let's brainstorm what to do about them:

  • We could just fix them, replacing .throw(A, B, C) with .throw(B).
  • We could add filterwarnings() calls to the offending tests (I don't recall how to do that but there are probable plenty of examples).
  • We could report a SilentDeprecationWarning, then gradually fix the tests, and then later change it into a DeprecationWarning.
  • We could first fix the tests, in batches, and then land this PR.

Objects/genobject.c Outdated Show resolved Hide resolved
@gvanrossum
Copy link
Member

We could report a SilentDeprecationWarning, then gradually fix the tests, and then later change it into a DeprecationWarning.

Whoops, there's no such thing. Maybe it once existed, but it doesn't now, so ignore this option. :-)

@ofey404
Copy link
Contributor Author

ofey404 commented Aug 31, 2022

One nit. Too bad about the failing tests, let's brainstorm what to do about them:

Let's estimate the problem size, by finding with regex throw\(.*,.*,.*\)

There are 51 results in 12 files.


  • We could just fix them, replacing .throw(A, B, C) with .throw(B).
  • We could first fix the tests, in batches, and then land this PR.

I prefer fixing them in this PR, for the fix need to be verified by raising an error. Otherwise the batch fix might miss something.

  • However, the batch plan would be clearer, in Issue and PR history.

We could add filterwarnings() calls to the offending tests (I don't recall how to do that but there are probable plenty of examples).

filterwarnings() call might be a safety valve, if I am not quite confident about how some tests work.

@gvanrossum
Copy link
Member

Okay, make sure you consider this.

Also, some of the hits may be tests for this very feature, those should not be "fixed" but you may have to add a with self.warns() on those.

Co-authored-by: Guido van Rossum <[email protected]>
@bedevere-bot
Copy link

Most changes to Python require a NEWS entry.

Please add it using the blurb_it web app or the blurb command-line tool.

@ofey404 ofey404 requested a review from 1st1 as a code owner September 1, 2022 05:26
@ofey404
Copy link
Contributor Author

ofey404 commented Sep 1, 2022

I run ./python -m test,and fixed clear cases, changed them to .throw(val) form.

However, there are still some DeprecationWarnings need to be handle. As @iritkatriel said in comment of 96348, some of the tests need to stay.

1. Generator's doc test

I think we should filter the DeprecationWarning here, for it's testing exactly the deprecated API.

>>> g.throw(ValueError, ValueError(1)) # value+matching type
caught ValueError (1)
>>> g.throw(ValueError, TypeError(1)) # mismatched type, rewrapped
caught ValueError (1)
>>> g.throw(ValueError, ValueError(1), None) # explicit None traceback
caught ValueError (1)
>>> g.throw(ValueError(1), "foo") # bad args
Traceback (most recent call last):
...
TypeError: instance exception may not have a separate value
>>> g.throw(ValueError, "foo", 23) # bad args

2. Lib unittest.case

It happens here:

with self:
callable_obj(*args, **kwargs)

The output is like:

/../cpython/Lib/unittest/case.py:237: DeprecationWarning: the (type, val, tb) exception representationis deprecated, and may be removed in a future version of Python.
  callable_obj(*args, **kwargs)

I am not sure what callable_obj does here, and maybe filtering this warning requires a change in standard library of python?

Objects/genobject.c Outdated Show resolved Hide resolved
@iritkatriel
Copy link
Member

/../cpython/Lib/unittest/case.py:237: DeprecationWarning: the (type, val, tb) exception representationis deprecated, and may be removed in a future version of Python.
  callable_obj(*args, **kwargs)

I am not sure what callable_obj does here, and maybe filtering this warning requires a change in standard library of python?

Look at the code in Lib/unittest/case.py. This is part of the assertRaises mechanism. The callable_obj and the args passed to it are defined by the test, so this should be dealt with in the particular test and not here in the test framework.

@iritkatriel
Copy link
Member

I am not sure what callable_obj does here, and maybe filtering this warning requires a change in standard library of python?

Look at the code in Lib/unittest/case.py. This is part of the assertRaises mechanism. The callable_obj and the args passed to it are defined by the test, so this should be dealt with in the particular test and not here in the test framework.

The test is this one. It's testing the types of the triplet, so we need to keep it and suppress the deprecation warning.

    def test_future_iter_throw(self):
        fut = self._new_future(loop=self.loop)
        fi = iter(fut)
        self.assertRaises(TypeError, fi.throw, 
                          Exception, Exception("elephant"), 32)
        self.assertRaises(TypeError, fi.throw,
                          Exception("elephant"), Exception("elephant"))
        self.assertRaises(TypeError, fi.throw, list)

@ofey404
Copy link
Contributor Author

ofey404 commented Sep 3, 2022

Okay, handled the remaining warnings.

Tested with those scripts:

./python -m test -j16 > test.log; cat test.log | grep "DeprecationWarning: the (type, val, tb) exception representation is deprecated"
# Come out with nothing

./python -Werror -m unittest -v test.test_asyncio.test_futures.PyFutureTests.test_future_iter_throw test.test_generators
# OK

Besides, should I squash all commits into one, when all the reviews are done?

@gvanrossum
Copy link
Member

Don’t squash please! It makes review harder. We will squash upon merge.

Copy link
Contributor

@kumaraditya303 kumaraditya303 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a significant change, it should be properly documented in 3.12 What's New.

Lib/test/test_asyncgen.py Outdated Show resolved Hide resolved
@iritkatriel iritkatriel added the 🔨 test-with-buildbots Test PR w/ buildbots; report in status section label Sep 28, 2022
@bedevere-bot
Copy link

🤖 New build scheduled with the buildbot fleet by @iritkatriel for commit 8b701d6 🤖

If you want to schedule another build, you need to add the ":hammer: test-with-buildbots" label again.

@bedevere-bot bedevere-bot removed the 🔨 test-with-buildbots Test PR w/ buildbots; report in status section label Sep 28, 2022
@iritkatriel
Copy link
Member

It seems that my tests exposed some problem - there are 3 versions of futures, and only one of them is emitting the deprecation warning?

@iritkatriel
Copy link
Member

Looking at the code, if futures._CFuture is fixed (made to raise the deprecation warning) then that will fix CSubFuture as well.

@iritkatriel
Copy link
Member

So I think we need one more deprecation warning from FutureIter_throw in
Modules/_asynciomodule.c.

@ofey404
Copy link
Contributor Author

ofey404 commented Sep 29, 2022

It seems that my tests exposed some problem - there are 3 versions of futures, and only one of them is emitting the deprecation warning?

The warning is added.


But I still feel a little dizzy about it - How do you know that we should add a test in test_futures.py? Is python future implemented by coroutine object or async generator?

  • My guess: According to the doc, so test_future.py is testing the high-level interface of coroutine object, from that we know that we should add a test on iter(future).throw.

The concurrent.futures module provides a high-level interface for asynchronously executing callables.
concurrent.futures — Launching parallel tasks

@iritkatriel
Copy link
Member

@kumaraditya303 How does it look now? (I'm a little dizzy by now as well).

Copy link
Contributor

@kumaraditya303 kumaraditya303 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@kumaraditya303
Copy link
Contributor

You only need to add deprecation warning in _CFuture since it is implemented in C. The pure Python versions uses regular generators so they will automatically emit warning since warning is added to generator.throw.

def __await__(self):
if not self.done():
self._asyncio_future_blocking = True
yield self # This tells Task to wait for completion.
if not self.done():
raise RuntimeError("await wasn't used with future")
return self.result() # May raise too.
__iter__ = __await__ # make compatible with 'yield from'.

@iritkatriel iritkatriel added 3.12 bugs and security fixes interpreter-core (Objects, Python, Grammar, and Parser dirs) labels Sep 30, 2022
@iritkatriel iritkatriel changed the title gh-96348: Deprecate the 3-arg signature of coroutine.throw and generator.throw gh-96348: Deprecate the 3-arg signature of coroutine.throw, generator.throw and agen.athrow Sep 30, 2022
@iritkatriel iritkatriel merged commit 83a3de4 into python:main Sep 30, 2022
@@ -2996,6 +2996,11 @@ generators, coroutines do not directly support iteration.
above. If the exception is not caught in the coroutine, it propagates
back to the caller.

.. versionchanged:: 3.12

The second signature \(type\[, value\[, traceback\]\]\) is deprecated and
Copy link
Member

@merwok merwok Sep 30, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For future PRs, not that code should generally be marked up like

      The second signature `(type[, value[, traceback]])` is deprecated and

serhiy-storchaka pushed a commit to serhiy-storchaka/cpython that referenced this pull request Oct 2, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
3.12 bugs and security fixes interpreter-core (Objects, Python, Grammar, and Parser dirs)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants