22
if sys.version_info[0] == 3:
23
from io import BytesIO as StringIO
25
# 2to3 will turn cStringIO into io. That's okay
26
# since we'll never get here under python3.
27
from cStringIO import StringIO
29
21
from bson.binary import Binary
30
22
from bson.objectid import ObjectId
31
from bson.py3compat import b, binary_type, string_types, text_type
23
from bson.py3compat import b, binary_type, string_types, text_type, StringIO
32
24
from gridfs.errors import (CorruptGridFile,
70
62
def setter(self, value):
72
64
self._coll.files.update({"_id": self._file["_id"]},
73
{"$set": {field_name: value}}, safe=True)
65
{"$set": {field_name: value}},
66
**self._coll._get_wc_override())
74
67
self._file[field_name] = value
122
115
that is written to the file will be converted to
118
If you turn off write-acknowledgment for performance reasons, it is
119
critical to wrap calls to :meth:`write` and :meth:`close` within a
122
>>> from pymongo import MongoClient
123
>>> from gridfs import GridFS
124
>>> client = MongoClient(w=0) # turn off write acknowledgment
125
>>> fs = GridFS(client)
126
>>> gridin = fs.new_file()
127
>>> request = client.start_request()
129
... for i in range(10):
130
... gridin.write('foo')
135
In Python 2.5 and later this code can be simplified with a
136
with-statement, see :doc:`/examples/requests` for more information.
126
139
- `root_collection`: root collection to write to
127
140
- `**kwargs` (optional): file level options (see above)
160
173
_id = _create_property("_id", "The ``'_id'`` value for this file.",
162
175
filename = _create_property("filename", "Name of this file.")
176
name = _create_property("filename", "Alias for `filename`.")
163
177
content_type = _create_property("contentType", "Mime-type for this file.")
164
178
length = _create_property("length", "Length (in bytes) of this file.",
165
179
closed_only=True)
178
192
raise AttributeError("GridIn object has no attribute '%s'" % name)
180
194
def __setattr__(self, name, value):
181
object.__setattr__(self, name, value)
183
self._coll.files.update({"_id": self._file["_id"]},
184
{"$set": {name: value}}, safe=True)
195
# For properties of this instance like _buffer, or descriptors set on
196
# the class like filename, use regular __setattr__
197
if name in self.__dict__ or name in self.__class__.__dict__:
198
object.__setattr__(self, name, value)
200
# All other attributes are part of the document in db.fs.files.
201
# Store them to be sent to server on close() or if closed, send
203
self._file[name] = value
205
self._coll.files.update({"_id": self._file["_id"]},
206
{"$set": {name: value}},
207
**self._coll._get_wc_override())
186
209
def __flush_data(self, data):
187
210
"""Flush `data` to a chunk.
194
217
"n": self._chunk_number,
195
218
"data": Binary(data)}
197
self._chunks.insert(chunk)
221
self._chunks.insert(chunk)
222
except DuplicateKeyError:
223
self._raise_file_exists(self._file['_id'])
198
224
self._chunk_number += 1
199
225
self._position += len(data)
208
234
def __flush(self):
209
235
"""Flush the file to the database.
211
self.__flush_buffer()
213
md5 = self._coll.database.command("filemd5", self._id,
214
root=self._coll.name)["md5"]
216
self._file["md5"] = md5
217
self._file["length"] = self._position
218
self._file["uploadDate"] = datetime.datetime.utcnow()
221
return self._coll.files.insert(self._file, safe=True)
238
self.__flush_buffer()
240
db = self._coll.database
242
# See PYTHON-417, "Sharded GridFS fails with exception: chunks out
243
# of order." Inserts via mongos, even if they use a single
244
# connection, can succeed out-of-order due to the writebackListener.
245
# We mustn't call "filemd5" until all inserts are complete, which
246
# we ensure by calling getLastError (and ignoring the result).
250
"filemd5", self._id, root=self._coll.name)["md5"]
252
self._file["md5"] = md5
253
self._file["length"] = self._position
254
self._file["uploadDate"] = datetime.datetime.utcnow()
256
return self._coll.files.insert(self._file,
257
**self._coll._get_wc_override())
222
258
except DuplicateKeyError:
223
raise FileExists("file with _id %r already exists" % self._id)
259
self._raise_file_exists(self._id)
261
def _raise_file_exists(self, file_id):
262
"""Raise a FileExists exception for the given file_id."""
263
raise FileExists("file with _id %r already exists" % file_id)
226
266
"""Flush the file and close it.
307
347
def __exit__(self, exc_type, exc_val, exc_tb):
308
348
"""Support for the context manager protocol.
310
Close the file and allow exceptions to propogate.
350
Close the file and allow exceptions to propagate.
314
# propogate exceptions
354
# propagate exceptions
355
395
self.__position = 0
357
397
_id = _create_property("_id", "The ``'_id'`` value for this file.", True)
358
name = _create_property("filename", "Name of this file.", True)
398
filename = _create_property("filename", "Name of this file.", True)
399
name = _create_property("filename", "Alias for `filename`.", True)
359
400
content_type = _create_property("contentType", "Mime-type for this file.",
361
402
length = _create_property("length", "Length (in bytes) of this file.",