Prepared requests don't work with session

If I make a prepared request like:

```
prepped = requests.Request('GET', my_url, params={}).prepare()
```

It doesn't have certain attributes set (cookies, auth, files, data, params from experiment...). If I then pass this prepared request in to a session.prepare_request() it fails because those attributes aren't in the PreparedRequest instance:

```
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python2.6/dist-packages/requests-2.0.0-py2.6.egg/requests/sessions.py", line 261, in prepare_request
    params=merge_setting(request.params, self.params),
AttributeError: 'PreparedRequest' object has no attribute 'params'
```

I think either requests.Request().prepare() needs to set all the attributes as None, or session.prepare_request() needs to be more cautious about how it merges the incoming request (e.g. things like [sessions.py#L238](https://github.com/kennethreitz/requests/blob/master/requests/sessions.py#L238) should be: 

```
 getattr(req, 'cookies', {})
```

That said, it's early in the morning and I've not had a coffee yet, so I could be missing how this stuff should be wired up.


Heh, you're so close to the right flow.

`Session.prepare_request()` doesn't expect a `PreparedRequest` object, it expects a `Request` object. So the expected flow is:

``` python
s = requests.Session()
prepped = s.prepare_request(requests.Request('GET', my_url, params={}))
r = s.send(prepped)
```


I think a argument `request` in `prepare_request` method is for `Request` object.(not `PreparedRequest` object)


Ah, then theres a documentation bug in the [advanced usage docs](http://docs.python-requests.org/en/latest/user/advanced/#prepared-requests) the code sample there is:

```
from requests import Request, Session

s = Session()
prepped = Request('GET',  # or any other method, 'POST', 'PUT', etc.
                  url,
                  data=data
                  headers=headers
                  # ...
                  ).prepare()
# do something with prepped.body
# do something with prepped.headers
resp = s.send(prepped,
              stream=stream,
              verify=verify,
              proxies=proxies,
              cert=cert,
              timeout=timeout,
              # etc.
              )
print(resp.status_code)
```

note the call to `prepare()`.


Sorry, should have been clearer. The reason I started looking at `session.prepare_request()` was because `session.send(prepared_request)` didn't seem to be adding the session auth into the prepared_request.


@drsm79 I agree that there's a documentation problem, but I don't think that is it. Let's start from the start. =)

The standard way to interact with Requests is to ignore `Request/PreparedRequest` objects altogether, and to just use the standard functional API (e.g. `Session.get()`, `Session.post()` etc.). However, some people want additional control over the form of their HTTP requests. For that reason, as part of 1.0, Kenneth made `Request` and `PreparedRequest` objects available. The contract for using them was this: if you use `PreparedRequest` objects, we aren't going to touch them. You give us a `PreparedRequest` and we send it, exactly as is. We don't apply any of our `Session`-level settings, because they might overwrite something you applied to the `PreparedRequest`. After all, that's what it's for!

In 1.0, the expected flow was what you laid out in your comment above.

Towards the 2.0 release date a few people mentioned that they'd like the ability to apply `Session` data before mutating their `PreparedRequest` objects. That seemed reasonable, so we added `Session.prepare_request()`. This essentially replaces the `Request.prepare()` call (though under the covers it does call that method) in your code. As part of what it does it applies relevant `Session` context, then returns you the `PreparedRequest` object to mutate at your leisure.

That's the difference between these two flows. `Request.prepare()` requires you to take full control over preparing your Request objects, including maintaining state. `Session.prepare_request()` does not require you to maintain as much state: we'll apply some for you.

`Session.send()` is a very thin wrapper over the underlying transport layer. It basically does connection pooling and that's about it.

I believe the problem with the documentation is that we don't adequately lay out both flows, and the reasons you'd do one instead of the other.


Thanks @Lukasa that makes a lot of sense. I'll fix up the problem in my code, get it deployed and then try to make a patch to the docs covering what you've got above. 

I think Session.send() not applying things like the session auth is pretty counter intuitive. While I get why you'd want a nice thin wrapper there it needs to be clearer that its not actually going to use much of the session.


That's totally understandable, I'd happily take a patch that makes that clearer as well. =)


Funny, I was just about to open a ticket because of the same issue.

What throw me in the docs was the statement "In some cases you may wish to do some extra work to the body..." which seems to imply that the approach introduced is equivalent to the standard one except for the "extra" customization it allows; it doesn't mention you are skipping essential session features now.


Agreed, we should revise the docs. I'll take a swing at it.


Resolved by #1702, hopefully.


LGTM thanks!