diff --git a/gridfs/__init__.py b/gridfs/__init__.py index 9fcba2af4..a9afc7968 100644 --- a/gridfs/__init__.py +++ b/gridfs/__init__.py @@ -132,11 +132,13 @@ class GridFS(object): self.__files.ensure_index([("filename", ASCENDING), ("uploadDate", DESCENDING)]) - grid_file = self.__files.find({"filename": filename}, - limit=-1).sort("uploadDate", DESCENDING) - if grid_file: + cursor = self.__files.find({"filename": filename}) + cursor.limit(-1).sort("uploadDate", DESCENDING) + try: + grid_file = cursor.next() return GridOut(self.__collection, grid_file["_id"]) - return None + except StopIteration: + return None # TODO add optional safe mode for chunk removal? def delete(self, file_id): diff --git a/gridfs/grid_file.py b/gridfs/grid_file.py index b3453d535..d966a9cf6 100644 --- a/gridfs/grid_file.py +++ b/gridfs/grid_file.py @@ -58,11 +58,14 @@ def _create_property(field_name, docstring, self._file[field_name] = value if read_only: - docstring = docstring + "\n\nThis attribute is read-only.""" + docstring = docstring + "\n\nThis attribute is read-only." elif not closed_only: - docstring = docstring + "\n\nThis attribute can only be set before :meth:`close` has been called.""" + docstring = "%s\n\n%s" % (docstring, "This attribute can only be " + "set before :meth:`close` has been called.") else: - docstring = docstring + "\n\nThis attribute is read-only and can only be read after :meth:`close` has been called.""" + docstring = "%s\n\n%s" % (docstring, "This attribute is read-only and " + "can only be read after :meth:`close` " + "has been called.") if not read_only and not closed_only: return property(getter, setter, doc=docstring) diff --git a/test/gridfs15.py b/test/gridfs15.py deleted file mode 100644 index f9ad6f244..000000000 --- a/test/gridfs15.py +++ /dev/null @@ -1,25 +0,0 @@ -# Copyright 2009-2010 10gen, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Some tests for the gridfs package that only work under Python >= 1.5. -""" - -from __future__ import with_statement - -def test_with_statement(test): - with test.fs.open("test", "w") as f: - f.write("hello world") - - with test.fs.open("test") as f: - test.assertEqual("hello world", f.read()) diff --git a/test/gridfs16.py b/test/gridfs16.py deleted file mode 100644 index aa48d9638..000000000 --- a/test/gridfs16.py +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright 2009-2010 10gen, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Some tests for the gridfs package that only work under Python >= 1.6. -""" - -def test_with_statement(test): - with test.fs.open("test", "w") as f: - f.write("hello world") - - with test.fs.open("test") as f: - test.assertEqual("hello world", f.read()) diff --git a/test/test_grid_file.py b/test/test_grid_file.py index cac0f6001..46ebf1d27 100644 --- a/test/test_grid_file.py +++ b/test/test_grid_file.py @@ -245,6 +245,13 @@ class TestGridFile(unittest.TestCase): self.assertEqual("hello world and mongodb", GridOut(self.db.fs, e._id).read()) + def test_write_lines(self): + a = GridIn(self.db.fs) + a.writelines(["hello ", "world"]) + a.close() + + self.assertEqual("hello world", GridOut(self.db.fs, a._id).read()) + def test_close(self): f = GridIn(self.db.fs) f.close() diff --git a/test/test_gridfs.py b/test/test_gridfs.py index 147864ccf..7b472f91a 100644 --- a/test/test_gridfs.py +++ b/test/test_gridfs.py @@ -15,9 +15,14 @@ """Tests for the gridfs package. """ +try: + from cStringIO import StringIO +except ImportError: + from StringIO import StringIO import datetime import unittest import threading +import time import sys sys.path[0:0] = [""] @@ -34,7 +39,7 @@ class JustWrite(threading.Thread): def run(self): for _ in range(10): - file = self.fs.open("test", "w") + file = self.fs.new_file(filename="test") file.write("hello") file.close() @@ -47,9 +52,8 @@ class JustRead(threading.Thread): def run(self): for _ in range(10): - file = self.fs.open("test") + file = self.fs.get("test") assert file.read() == "hello" - file.close() class TestGridfs(unittest.TestCase): @@ -58,10 +62,14 @@ class TestGridfs(unittest.TestCase): self.db = get_connection().pymongo_test self.db.drop_collection("fs.files") self.db.drop_collection("fs.chunks") - self.db.drop_collection("pymongo_test.files") - self.db.drop_collection("pymongo_test.chunks") + self.db.drop_collection("alt.files") + self.db.drop_collection("alt.chunks") self.fs = gridfs.GridFS(self.db) - self.alt = gridfs.GridFS(self.db, "pymongo_test") + self.alt = gridfs.GridFS(self.db, "alt") + + def test_gridfs(self): + self.assertRaises(TypeError, gridfs.GridFS, "foo") + self.assertRaises(TypeError, gridfs.GridFS, self.db, 5) def test_basic(self): oid = self.fs.put("hello world") @@ -105,139 +113,75 @@ class TestGridfs(unittest.TestCase): self.assertEqual(256*1024, raw["chunkSize"]) self.assert_(isinstance(raw["md5"], basestring)) + def test_alt_collection(self): + oid = self.alt.put("hello world") + self.assertEqual("hello world", self.alt.get(oid).read()) + self.assertEqual(1, self.db.alt.files.count()) + self.assertEqual(1, self.db.alt.chunks.count()) - # def test_remove(self): - # self.assertRaises(TypeError, self.fs.remove, 5) - # self.assertRaises(TypeError, self.fs.remove, None) - # self.assertRaises(TypeError, self.fs.remove, []) + self.alt.delete(oid) + self.assertRaises(NoFile, self.alt.get, oid) + self.assertEqual(0, self.db.alt.files.count()) + self.assertEqual(0, self.db.alt.chunks.count()) - # f = self.fs.open("mike", "w") - # f.write("hi") - # f.close() - # f = self.fs.open("test", "w") - # f.write("bye") - # f.close() - # f = self.fs.open("hello world", "w") - # f.write("fly") - # f.close() - # self.assertEqual(set(["mike", "test", "hello world"]), - # set(self.fs.list())) - # self.assertEqual(self.db.fs.files.find().count(), 3) - # self.assertEqual(self.db.fs.chunks.find().count(), 3) + self.assertRaises(NoFile, self.alt.get, "foo") + oid = self.alt.put("hello world", _id="foo") + self.assertEqual("foo", oid) + self.assertEqual("hello world", self.alt.get("foo").read()) - # self.fs.remove("test") + self.alt.put("", filename="mike") + self.alt.put("foo", filename="test") + self.alt.put("", filename="hello world") - # self.assertEqual(set(["mike", "hello world"]), set(self.fs.list())) - # self.assertEqual(self.db.fs.files.find().count(), 2) - # self.assertEqual(self.db.fs.chunks.find().count(), 2) - # f = self.fs.open("mike") - # self.assertEqual(f.read(), "hi") - # f.close() - # f = self.fs.open("hello world") - # self.assertEqual(f.read(), "fly") - # f.close() - # self.assertRaises(IOError, self.fs.open, "test") + self.assertEqual(set(["mike", "test", "hello world"]), + set(self.alt.list())) - # self.fs.remove({}) + def test_threaded_reads(self): + self.fs.put("hello", _id="test") - # self.assertEqual([], self.fs.list()) - # self.assertEqual(self.db.fs.files.find().count(), 0) - # self.assertEqual(self.db.fs.chunks.find().count(), 0) - # self.assertRaises(IOError, self.fs.open, "test") - # self.assertRaises(IOError, self.fs.open, "mike") - # self.assertRaises(IOError, self.fs.open, "hello world") + threads = [] + for i in range(10): + threads.append(JustRead(self.fs)) + threads[i].start() - # def test_open_alt_coll(self): - # f = self.fs.open("my file", "w", "pymongo_test") - # f.write("hello gridfs world!") - # f.close() + for i in range(10): + threads[i].join() - # self.assertRaises(IOError, self.fs.open, "my file", "r") - # g = self.fs.open("my file", "r", "pymongo_test") - # self.assertEqual("hello gridfs world!", g.read()) - # g.close() + def test_threaded_writes(self): + threads = [] + for i in range(10): + threads.append(JustWrite(self.fs)) + threads[i].start() - # def test_list_alt_coll(self): - # f = self.fs.open("mike", "w", "pymongo_test") - # f.close() + for i in range(10): + threads[i].join() - # f = self.fs.open("test", "w", "pymongo_test") - # f.close() + f = self.fs.get_last_version("test") + self.assertEqual(f.read(), "hello") - # f = self.fs.open("hello world", "w", "pymongo_test") - # f.close() + def test_get_last_version(self): + a = self.fs.put("foo", filename="test") + time.sleep(0.01) + b = self.fs.new_file(filename="test") + b.write("bar") + b.close() + time.sleep(0.01) + b = b._id + c = self.fs.put("baz", filename="test") - # self.assertEqual([], self.fs.list()) - # self.assertEqual(set(["mike", "test", "hello world"]), - # set(self.fs.list("pymongo_test"))) + self.assertEqual("baz", self.fs.get_last_version("test").read()) + self.fs.delete(c) + self.assertEqual("bar", self.fs.get_last_version("test").read()) + self.fs.delete(b) + self.assertEqual("foo", self.fs.get_last_version("test").read()) + self.fs.delete(a) + self.assertEqual(None, self.fs.get_last_version("test")) - # def test_remove_alt_coll(self): - # f = self.fs.open("mike", "w", "pymongo_test") - # f.write("hi") - # f.close() - # f = self.fs.open("test", "w", "pymongo_test") - # f.write("bye") - # f.close() - # f = self.fs.open("hello world", "w", "pymongo_test") - # f.write("fly") - # f.close() + def test_put_filelike(self): + oid = self.fs.put(StringIO("hello world"), chunk_size=1) + self.assertEqual(11, self.db.fs.chunks.count()) + self.assertEqual("hello world", self.fs.get(oid).read()) - # self.fs.remove("test") - # self.assertEqual(set(["mike", "test", "hello world"]), - # set(self.fs.list("pymongo_test"))) - # self.fs.remove("test", "pymongo_test") - # self.assertEqual(set(["mike", "hello world"]), - # set(self.fs.list("pymongo_test"))) - - # f = self.fs.open("mike", collection="pymongo_test") - # self.assertEqual(f.read(), "hi") - # f.close() - # f = self.fs.open("hello world", collection="pymongo_test") - # self.assertEqual(f.read(), "fly") - # f.close() - - # self.fs.remove({}, "pymongo_test") - - # self.assertEqual([], self.fs.list("pymongo_test")) - # self.assertEqual(self.db.pymongo_test.files.find().count(), 0) - # self.assertEqual(self.db.pymongo_test.chunks.find().count(), 0) - - # def test_threaded_reads(self): - # f = self.fs.open("test", "w") - # f.write("hello") - # f.close() - - # threads = [] - # for i in range(10): - # threads.append(JustRead(self.fs)) - # threads[i].start() - - # for i in range(10): - # threads[i].join() - - # def test_threaded_writes(self): - # threads = [] - # for i in range(10): - # threads.append(JustWrite(self.fs)) - # threads[i].start() - - # for i in range(10): - # threads[i].join() - - # f = self.fs.open("test") - # self.assertEqual(f.read(), "hello") - # f.close() - - # # NOTE I do recognize how gross this is. There is no good way to - # # test the with statement because it is a syntax error in older - # # python versions. One option would be to use eval and skip the - # # test if it is a syntax error. - # if sys.version_info[:2] == (2, 5): - # import gridfs15 - # test_with_statement = gridfs15.test_with_statement - # elif sys.version_info[:3] >= (2, 6, 0): - # import gridfs16 - # test_with_statement = gridfs16.test_with_statement if __name__ == "__main__": unittest.main()