Async-only for Requests v3?

A discussion at PyCon in the Requests BoF has suggested two approaches to our glorious async future:

1. Write a codebase that is async and Python 3-only, and then apply an automated code transformation to turn that into a synchronous codebase that ships on Python 2. This will mean that Requests v3 supports *only* synchronous code on Python 2, and both sync and async code on Python 3.
2. Mark Requests v2 as a LTS release that we will support until 2020, and then ship Requests v3 as a Python-3-only release (like Django!)

I don't want to go into too much detail on (1), but I'd like to ask our users what they think about option (2). If it's acceptable to you, leave a :+1:, if it's unacceptable leave a :-1:, and if you have notes about why it's either please leave them below.

Let the comment period begin!

Thumb up for v2 as LTS and v3 Py3 only :). 👍
Adding the Django example, it gives good push in the right of direction of Py3 only. Hopefully this starts a trend and all libraries will follow that model. It helps me to promote that model as well internally, for our own libraries (if everybody does that, let's do the same :))
Side note, like @kennethreitz was saying at the BoF, v3 being Py3 only opens great opportunities to have  native type hints support (not based on comments), or to avoid adding that burden to a code transformer.

👍 

I'm in favor of option 2, and here are my reasons:

### Political

Requests is in the privileged position of being an incredibly widely used—and thus influential—package. Python 3 is not just the future but also present for many of its users, and the Python community at large. Requests _can and should_ help move the community forward.

### Practical

Major version numbers are meant to represent significant, breaking changes (at least in SemVer). Deprecating a slated-for-deprecation version of the language seems to me a rather fitting scenario.

Nothing stands in the way of the LTS version being updated even past 2020, depending on the needs of the community.

And another shocker: should it prove desirable, it's entirely possible to restore Python 2 compatibility in a future major version.

As it has been for the past several years, my opinion is that Python 2 should have died long ago and thus I am 100% on board with this. I'd suggest that we reach out to @dims @sdague @ttx and @jakubroztocil though to ensure that some of our larger open source dependencies are quite aware of this discussion.

Thanks for the heads up. It seems pretty reasonable to me that requests 2.x goes into LTS mode for python2.

I think the big question would be on how much the calling interface changes, so how much do we have to actively port to requests v3. Most of the base iaas in OpenStack is stradling both python2 and python3 right now, so understanding what libraries we'd need to embed requests 2 vs. requests 3 logic in would be helpful to know.

Thanks @sigmavirus24 +1 to @sdague 's comment above

I'm +1 on option 2, with some caveats stemming from our discussion last night, namely that rather than attempt to maintain some degree of superficial, possibly source-level API compatibility with the existing API, the change should be *visibly* breaking. Don't leave room for subtle compatibility issues that come about because of the existing users updating with unpinned dependencies.

You may even want to consider a full name change. Here's one question: is it feasible to determine how your dependencies are being pinned from a central location? It would be worth asking PyPi to see how requests is pulled in; is it via `requests>=2.0` or is it via something safer like `requests>=2.0,<3.0`? If not, then you're laying a bit of a time bomb. I suppose you can get away with this using trove classifiers, but it'll be hinky. Possibly pip fixes this for you now?

Short answer: Yes, do a 2.x LTS version, and a 3.x future version. Break 2.x consumers HARD if they use the 3.x version, though.



> I suppose you can get away with this using trove classifiers, but it'll be hinky.

I don't understand how Trove Classifiers would help in this case.

> If not, then you're laying a bit of a time bomb.

If not I think there's plenty of time to advocate that users cap to `<3.0` or more simply pin to their current version.

> Break 2.x consumers HARD if they use the 3.x version, though.

We broke 0.x consumers HARD with 1.x several years ago and people still take the opportunity to complain to me. That said, this is a significantly better reason to do so.

>> I suppose you can get away with this using trove classifiers, but it'll be hinky.

> I don't understand how Trove Classifiers would help in this case.

I'm thinking that you could mark 3.x as only working for certain Python versions. If pip actually heeds those, then "pip install requests >=2.0" will stop at 2.* for Python 2.x and use 3.x for the 3.6+. If it doesn't, then they won't help at all.

>> If not, then you're laying a bit of a time bomb.

> If not I think there's plenty of time to advocate that users cap to <3.0 or more simply pin to their current version.

Not to put too fine a point on it, but we both know that people will ignore this, or use text from old tutorials on the website, or just do the wrong damn thing.

>> Break 2.x consumers HARD if they use the 3.x version, though.

> We broke 0.x consumers HARD with 1.x several years ago and people still take the opportunity to complain to me. That said, this is a significantly better reason to do so.

Indeed it is.

> I'm thinking that you could mark 3.x as only working for certain Python versions. If pip actually heeds those, then "pip install requests >=2.0" will stop at 2.* for Python 2.x and use 3.x for the 3.6+. If it doesn't, then they won't help at all.

Pip doesn't do that. The trove classifiers were always more suggestive than prescriptive and meant for users, not necessarily for tooling.

> Not to put too fine a point on it, but we both know that people will ignore this, or use text from old tutorials on the website, or just do the wrong damn thing.

Oh, I absolutely agree. That doesn't mean we can't say "That tutorial is very old. You should refer to this newer and more correct tutorial."

Starting Pip 9 you can limit the package version that gets installed per Python version. This is how iPython enforces iPython 5 for Python 2.

 - iPython devs wrote up a guide here: http://www.python3statement.org/practicalities/
 - PyCon 2017 talk about it: https://www.youtube.com/watch?v=2DkfPzWWC2Q

We figured this out. 



Requests will (contingient upon reasonable prototyping) depend on Twisted to provide the following:

- an event loop backend
- async support for Python 2 and 3 simultaneouslly
- support for the `async` and `await` keywords in Python 3

It's going to be beautiful, when we're done. 

Expect this work to be completed within the next year or so, unless I *really* get a coding itch soon. Who knows 👍 

```pycon
>>> from requests import async
>>> async.get('...')
```
^ awaitable deferred repr here ^

`async` will also be a Requests session instance, so... automatic connection-pooling. 

:heart:


there's a 10% chance i'll want to give it a more clever name, but that's the working name. 

`async` is a reserved key-word in Python 3.6 onwards.

@SethMichaelLarson thanks! someone brought this up during the conference too, i forgot.

Okay, 100% chance I'll find a more clever name now. 

`requests.concurrent` wouldn't be the end of the world. I'll give it a deep think.