00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 """GridFS is a specification for storing large objects in Mongo.
00016
00017 The :mod:`gridfs` package is an implementation of GridFS on top of
00018 :mod:`pymongo`, exposing a file-like interface.
00019
00020 .. mongodoc:: gridfs
00021 """
00022
00023 from gridfs.errors import (NoFile,
00024 UnsupportedAPI)
00025 from gridfs.grid_file import (GridIn,
00026 GridOut)
00027 from pymongo import (ASCENDING,
00028 DESCENDING)
00029 from pymongo.database import Database
00030
00031
00032 class GridFS(object):
00033 """An instance of GridFS on top of a single Database.
00034 """
00035 def __init__(self, database, collection="fs"):
00036 """Create a new instance of :class:`GridFS`.
00037
00038 Raises :class:`TypeError` if `database` is not an instance of
00039 :class:`~pymongo.database.Database`.
00040
00041 :Parameters:
00042 - `database`: database to use
00043 - `collection` (optional): root collection to use
00044
00045 .. versionadded:: 1.6
00046 The `collection` parameter.
00047
00048 .. mongodoc:: gridfs
00049 """
00050 if not isinstance(database, Database):
00051 raise TypeError("database must be an instance of Database")
00052
00053 self.__database = database
00054 self.__collection = database[collection]
00055 self.__files = self.__collection.files
00056 self.__chunks = self.__collection.chunks
00057 self.__chunks.ensure_index([("files_id", ASCENDING), ("n", ASCENDING)],
00058 unique=True)
00059
00060 def new_file(self, **kwargs):
00061 """Create a new file in GridFS.
00062
00063 Returns a new :class:`~gridfs.grid_file.GridIn` instance to
00064 which data can be written. Any keyword arguments will be
00065 passed through to :meth:`~gridfs.grid_file.GridIn`.
00066
00067 If the ``"_id"`` of the file is manually specified, it must
00068 not already exist in GridFS. Otherwise
00069 :class:`~gridfs.errors.FileExists` is raised.
00070
00071 :Parameters:
00072 - `**kwargs` (optional): keyword arguments for file creation
00073
00074 .. versionadded:: 1.6
00075 """
00076 return GridIn(self.__collection, **kwargs)
00077
00078 def put(self, data, **kwargs):
00079 """Put data in GridFS as a new file.
00080
00081 Equivalent to doing:
00082
00083 >>> f = new_file(**kwargs)
00084 >>> try:
00085 >>> f.write(data)
00086 >>> finally:
00087 >>> f.close()
00088
00089 `data` can be either an instance of :class:`str` or a
00090 file-like object providing a :meth:`read` method. If an
00091 `encoding` keyword argument is passed, `data` can also be a
00092 :class:`unicode` instance, which will be encoded as `encoding`
00093 before being written. Any keyword arguments will be passed
00094 through to the created file - see
00095 :meth:`~gridfs.grid_file.GridIn` for possible
00096 arguments. Returns the ``"_id"`` of the created file.
00097
00098 If the ``"_id"`` of the file is manually specified, it must
00099 not already exist in GridFS. Otherwise
00100 :class:`~gridfs.errors.FileExists` is raised.
00101
00102 :Parameters:
00103 - `data`: data to be written as a file.
00104 - `**kwargs` (optional): keyword arguments for file creation
00105
00106 .. versionadded:: 1.9
00107 The ability to write :class:`unicode`, if an `encoding` has
00108 been specified as a keyword argument.
00109
00110 .. versionadded:: 1.6
00111 """
00112 grid_file = GridIn(self.__collection, **kwargs)
00113 try:
00114 grid_file.write(data)
00115 finally:
00116 grid_file.close()
00117 return grid_file._id
00118
00119 def get(self, file_id):
00120 """Get a file from GridFS by ``"_id"``.
00121
00122 Returns an instance of :class:`~gridfs.grid_file.GridOut`,
00123 which provides a file-like interface for reading.
00124
00125 :Parameters:
00126 - `file_id`: ``"_id"`` of the file to get
00127
00128 .. versionadded:: 1.6
00129 """
00130 return GridOut(self.__collection, file_id)
00131
00132 def get_version(self, filename, version=-1):
00133 """Get a file from GridFS by ``"filename"``.
00134
00135 Returns a version of the file in GridFS with the name
00136 `filename` as an instance of
00137 :class:`~gridfs.grid_file.GridOut`. Version ``-1`` will be the
00138 most recently uploaded, ``-2`` the second most recently
00139 uploaded, etc. Version ``0`` will be the first version
00140 uploaded, ``1`` the second version, etc. So if three versions
00141 have been uploaded, then version ``0`` is the same as version
00142 ``-3``, version ``1`` is the same as version ``-2``, and
00143 version ``2`` is the same as version ``-1``.
00144
00145 Raises :class:`~gridfs.errors.NoFile` if no such version of
00146 that file exists.
00147
00148 An index on ``{filename: 1, uploadDate: -1}`` will
00149 automatically be created when this method is called the first
00150 time.
00151
00152 :Parameters:
00153 - `filename`: ``"filename"`` of the file to get
00154 - `version` (optional): version of the file to get (defualts
00155 to -1, the most recent version uploaded)
00156
00157 .. versionadded:: 1.9
00158 """
00159 self.__files.ensure_index([("filename", ASCENDING),
00160 ("uploadDate", DESCENDING)])
00161
00162 cursor = self.__files.find({"filename": filename})
00163 if version < 0:
00164 skip = abs(version) - 1
00165 cursor.limit(-1).skip(skip).sort("uploadDate", DESCENDING)
00166 else:
00167 cursor.limit(-1).skip(version).sort("uploadDate", ASCENDING)
00168 try:
00169 grid_file = cursor.next()
00170 return GridOut(self.__collection, grid_file["_id"])
00171 except StopIteration:
00172 raise NoFile("no version %d for filename %r" % (version, filename))
00173
00174 def get_last_version(self, filename):
00175 """Get the most recent version of a file in GridFS by ``"filename"``.
00176
00177 Equivalent to calling :meth:`get_version` with the default
00178 `version` (``-1``).
00179
00180 :Parameters:
00181 - `filename`: ``"filename"`` of the file to get
00182
00183 .. versionadded:: 1.6
00184 """
00185 return self.get_version(filename)
00186
00187
00188 def delete(self, file_id):
00189 """Delete a file from GridFS by ``"_id"``.
00190
00191 Removes all data belonging to the file with ``"_id"``:
00192 `file_id`.
00193
00194 .. warning:: Any processes/threads reading from the file while
00195 this method is executing will likely see an invalid/corrupt
00196 file. Care should be taken to avoid concurrent reads to a file
00197 while it is being deleted.
00198
00199 .. note:: Deletes of non-existent files are considered successful
00200 since the end result is the same: no file with that _id remains.
00201
00202 :Parameters:
00203 - `file_id`: ``"_id"`` of the file to delete
00204
00205 .. versionadded:: 1.6
00206 """
00207 self.__files.remove({"_id": file_id}, safe=True)
00208 self.__chunks.remove({"files_id": file_id})
00209
00210 def list(self):
00211 """List the names of all files stored in this instance of
00212 :class:`GridFS`.
00213
00214 .. versionchanged:: 1.6
00215 Removed the `collection` argument.
00216 """
00217 return self.__files.distinct("filename")
00218
00219 def exists(self, document_or_id=None, **kwargs):
00220 """Check if a file exists in this instance of :class:`GridFS`.
00221
00222 The file to check for can be specified by the value of it's
00223 ``_id`` key, or by passing in a query document. A query
00224 document can be passed in as dictionary, or by using keyword
00225 arguments. Thus, the following three calls are equivalent:
00226
00227 >>> fs.exists(file_id)
00228 >>> fs.exists({"_id": file_id})
00229 >>> fs.exists(_id=file_id)
00230
00231 As are the following two calls:
00232
00233 >>> fs.exists({"filename": "mike.txt"})
00234 >>> fs.exists(filename="mike.txt")
00235
00236 And the following two:
00237
00238 >>> fs.exists({"foo": {"$gt": 12}})
00239 >>> fs.exists(foo={"$gt": 12})
00240
00241 Returns ``True`` if a matching file exists, ``False``
00242 otherwise. Calls to :meth:`exists` will not automatically
00243 create appropriate indexes; application developers should be
00244 sure to create indexes if needed and as appropriate.
00245
00246 :Parameters:
00247 - `document_or_id` (optional): query document, or _id of the
00248 document to check for
00249 - `**kwargs` (optional): keyword arguments are used as a
00250 query document, if they're present.
00251
00252 .. versionadded:: 1.8
00253 """
00254 if kwargs:
00255 return self.__files.find_one(kwargs, ["_id"]) is not None
00256 return self.__files.find_one(document_or_id, ["_id"]) is not None
00257
00258 def open(self, *args, **kwargs):
00259 """No longer supported.
00260
00261 .. versionchanged:: 1.6
00262 The open method is no longer supported.
00263 """
00264 raise UnsupportedAPI("The open method is no longer supported.")
00265
00266 def remove(self, *args, **kwargs):
00267 """No longer supported.
00268
00269 .. versionchanged:: 1.6
00270 The remove method is no longer supported.
00271 """
00272 raise UnsupportedAPI("The remove method is no longer supported. "
00273 "Please use the delete method instead.")