Better diagnostics when trying to send unprepared request

When trying to send unprepared request like

```
import requests

requests.Session().send(requests.Request(url='http://example.com'))
```

one gets rather meaningless error

```
Traceback (most recent call last):
  File "y.py", line 3, in <module>
    requests.Session().send(requests.Request(url='http://example.com'))
  File "c:\python\venvs\sandbox\lib\site-packages\requests\sessions.py", line 374, in send
    r = adapter.send(request, **kwargs)
  File "c:\python\venvs\sandbox\lib\site-packages\requests\adapters.py", line 158, in send
    url = self.request_url(request, proxies)
  File "c:\python\venvs\sandbox\lib\site-packages\requests\adapters.py", line 148, in request_url
    url = request.path_url
AttributeError: 'Request' object has no attribute 'path_url'
```

It would be nice to check if the request is prepared before trying to send and inform user what's wrong if the request is not prepared.


+1


When writing the code for this, I considered automatically preparing unprepared requests. 

Thoughts?


I'm not keen on it. If you're separating requests from sending in such a way that you can submit an unprepared request to a transport adapter, you're probably doing something with the prepared request. The above error suggests a code path where you don't prepare the request, and that code path is probably also missing the other stuff you wanted to do to the prepared request.

It would actually be worse to throw no error in this case than to throw the meaningless one above


That kind of preserves pre 1.x behaviour right? And the code for that should be simple, e.g., 

```
prepare = getattr(request, 'prepare', None)
if prepare and isinstance(prepare, Callable):
   request = request.prepare()
```

Then yeah, that makes sense. Seems a bit too convenient, but I wouldn't fight against it.


@sigmavirus24 that's exactly what i was thinking.

Need to think about if more. @Lukasa makes a point.


I agree with @Lukasa 's point, and we've already broken the pre 1.x behaviour, so restoring it is not a must. Raising a `ValueError` seems to be the pythonic thing to do here, otherwise.


@kennethreitz: You didn't seem to have checked in any code for this, so I decided to give you an easy option. =)

I feel like the `getattr` check is overbroad, users might want to use custom PreparedRequest objects where the `prepare()` method simply mutates the current object as opposed to returning a new one. Normally I wouldn't use it, but as we're testing for 'user makes a boo-boo', maybe we should use it.


The test failures are arbitrary: the `test_links` test case is failing with a `KeyError`. Pretty sure it's transient.


So, over two test runs all versions of Python passed. I call that a win.


Victory!


Can you rebase?


also, this functionality should be in session.send i think, not the adapter.


@Lukasa I rebased and made the changes for you [here](https://github.com/sigmavirus24/requests/tree/lukasa/diags)


I meant to bring this up yesterday and got stuck in traffic: I wasn't sure that this should be in `Session.send()`. It seemed like any user accidentally `Session.send`ing an unprepared Request could just as easily `HTTPAdapter.send` it by accident. This way we catch both cases.


This failure isn't my fault, this is totally mergeable. =D


should this be happening at the session level


I don't think so. It seems to me that if you're manually preparing requests, it's quite possible that you're going to immediately plug them into a Transport Adapter, and not just try to session.send() them. In fact, I feel like if you're going to hit `prepare()` you're _way_ more likely to use a transport adapter instead of the session. This way catches both.


basically, if you're using an unmounted transport adapter, you're going to be working at a really low level, and will know that it needs to be prepared already.

I also don't want everyone who creates a connection adapter to have to implement this.


Fair enough, I'll take another swing at this tomorrow as well. =)


Hooray, moved code! :grin:


@Lukasa rebase again please? ;P


Done. =)


Merging, but changing this.


Go for it. =)