djc / couchdb-python

Python library for working with CouchDB
Other
202 stars 86 forks source link

`'_io.BytesIO' object is not subscriptable` when creating new document #315

Closed jat255 closed 7 years ago

jat255 commented 7 years ago

I'm trying to create a new document on a CouchDB server.

The simple example from the documentation works fine: userdb.save({'type': 'Person', 'name': 'John Doe'})

But if I try to do a realistic example, where I need to set the _id value to a custom name (for the application to use), I get an error:

test = {
  "_id": '33d1dc8b16000a542',
  "name": "Test from couchdb-python"
}
db.save(test)

Error:

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-70-48d3d9c8d167> in <module>()
      3   "name": "Test from couchdb-python"
      4 }
----> 5 db.save(test)

....\site-packages\couchdb\client.py in save(self, doc, **options)
    509             func = self.resource.post_json
    510         _, _, data = func(body=doc, **options)
--> 511         id, rev = data['id'], data.get('rev')
    512         doc['_id'] = id
    513         if rev is not None: # Not present for batch='ok'

TypeError: '_io.BytesIO' object is not subscriptable

This looks like a Python 3 string encoding error, perhaps? Any thoughts?

djc commented 7 years ago

Hmm, this is kind of weird. What version of CouchDB this is? Can you somehow get the exact response, headers and content, on the HTTP level? The code in Resource._request_json() seems to imply that if the Content-Type includes application/json, the response content (which could well be a BytesIO) should get decoded into a dictionary.

jat255 commented 7 years ago

The db is actually a pouchDB, but I think that should be okay. The server replies that it is version 2.0.0:

{
couchdb: "Welcome",
version: "2.0.0",
vendor: {
name: "The Apache Software Foundation"
}
}
jat255 commented 7 years ago

Debugging it a bit, the data value (https://github.com/djc/couchdb-python/blob/master/couchdb/client.py#L511) is indeed a BytesIO, with html content showing a 301 response:

<html>
<head><title>301 Moved Permanently</title></head>
<body bgcolor="white">
<center><h1>301 Moved Permanently</h1></center>
<hr><center>nginx</center>
</body>
</html>

And here's the header content (url removed):

> headers.items()
[('Server', 'nginx'),
 ('Date', 'Sun, 19 Mar 2017 19:25:17 GMT'),
 ('Content-Type', 'text/html'),
 ('Content-Length', '178'),
 ('Connection', 'keep-alive'),
 ('Location',
  'https://xxxx')]
djc commented 7 years ago

I still really want to know the exact HTTP response, including headers.

Also, the welcome object you're showing doesn't look like PouchDB, and I'm pretty sure PouchDB does not offer a HTTP API in any case.

jat255 commented 7 years ago

I updated my above comment with the response. From what I can tell, PouchDB provides a CouchDB-compliant RESTful API

djc commented 7 years ago

So the Content-Type is wrong, this is why it doesn't work.

jat255 commented 7 years ago

The same commands work if I manually do a put request using requests, so I believe this is a bug with the library. Since you closed the issue, I take that to mean you don't have an interest in fixing it?

djc commented 7 years ago

The Content-Type being set to application/json is, for all intents and purposes, part of the CouchDB API contract. As your setup doesn't seem to comply with that API contract, yes, I don't think it makes sense to change couchdb-python to make your setup work.