App Engine Python SDK version 1.9.12
[gae.git] / python / lib / django-1.2 / tests / regressiontests / model_fields / imagefield.py
blobdd79e7aefaa61bb72f37ebbb6a371de66d49e180
1 import os
2 import shutil
4 from django.core.files import File
5 from django.core.files.base import ContentFile
6 from django.core.files.images import ImageFile
7 from django.test import TestCase
9 from models import Image, Person, PersonWithHeight, PersonWithHeightAndWidth, \
10 PersonDimensionsFirst, PersonTwoImages, TestImageFieldFile
13 # If PIL available, do these tests.
14 if Image:
16 from models import temp_storage_dir
19 class ImageFieldTestMixin(object):
20 """
21 Mixin class to provide common functionality to ImageField test classes.
22 """
24 # Person model to use for tests.
25 PersonModel = PersonWithHeightAndWidth
26 # File class to use for file instances.
27 File = ImageFile
29 def setUp(self):
30 """
31 Creates a pristine temp directory (or deletes and recreates if it
32 already exists) that the model uses as its storage directory.
34 Sets up two ImageFile instances for use in tests.
35 """
36 if os.path.exists(temp_storage_dir):
37 shutil.rmtree(temp_storage_dir)
38 os.mkdir(temp_storage_dir)
40 file_path1 = os.path.join(os.path.dirname(__file__), "4x8.png")
41 self.file1 = self.File(open(file_path1, 'rb'))
43 file_path2 = os.path.join(os.path.dirname(__file__), "8x4.png")
44 self.file2 = self.File(open(file_path2, 'rb'))
46 def tearDown(self):
47 """
48 Removes temp directory and all its contents.
49 """
50 shutil.rmtree(temp_storage_dir)
52 def check_dimensions(self, instance, width, height,
53 field_name='mugshot'):
54 """
55 Asserts that the given width and height values match both the
56 field's height and width attributes and the height and width fields
57 (if defined) the image field is caching to.
59 Note, this method will check for dimension fields named by adding
60 "_width" or "_height" to the name of the ImageField. So, the
61 models used in these tests must have their fields named
62 accordingly.
64 By default, we check the field named "mugshot", but this can be
65 specified by passing the field_name parameter.
66 """
67 field = getattr(instance, field_name)
68 # Check height/width attributes of field.
69 if width is None and height is None:
70 self.assertRaises(ValueError, getattr, field, 'width')
71 self.assertRaises(ValueError, getattr, field, 'height')
72 else:
73 self.assertEqual(field.width, width)
74 self.assertEqual(field.height, height)
76 # Check height/width fields of model, if defined.
77 width_field_name = field_name + '_width'
78 if hasattr(instance, width_field_name):
79 self.assertEqual(getattr(instance, width_field_name), width)
80 height_field_name = field_name + '_height'
81 if hasattr(instance, height_field_name):
82 self.assertEqual(getattr(instance, height_field_name), height)
85 class ImageFieldTests(ImageFieldTestMixin, TestCase):
86 """
87 Tests for ImageField that don't need to be run with each of the
88 different test model classes.
89 """
91 def test_equal_notequal_hash(self):
92 """
93 Bug #9786: Ensure '==' and '!=' work correctly.
94 Bug #9508: make sure hash() works as expected (equal items must
95 hash to the same value).
96 """
97 # Create two Persons with different mugshots.
98 p1 = self.PersonModel(name="Joe")
99 p1.mugshot.save("mug", self.file1)
100 p2 = self.PersonModel(name="Bob")
101 p2.mugshot.save("mug", self.file2)
102 self.assertEqual(p1.mugshot == p2.mugshot, False)
103 self.assertEqual(p1.mugshot != p2.mugshot, True)
105 # Test again with an instance fetched from the db.
106 p1_db = self.PersonModel.objects.get(name="Joe")
107 self.assertEqual(p1_db.mugshot == p2.mugshot, False)
108 self.assertEqual(p1_db.mugshot != p2.mugshot, True)
110 # Instance from db should match the local instance.
111 self.assertEqual(p1_db.mugshot == p1.mugshot, True)
112 self.assertEqual(hash(p1_db.mugshot), hash(p1.mugshot))
113 self.assertEqual(p1_db.mugshot != p1.mugshot, False)
115 def test_instantiate_missing(self):
117 If the underlying file is unavailable, still create instantiate the
118 object without error.
120 p = self.PersonModel(name="Joan")
121 p.mugshot.save("shot", self.file1)
122 p = self.PersonModel.objects.get(name="Joan")
123 path = p.mugshot.path
124 shutil.move(path, path + '.moved')
125 p2 = self.PersonModel.objects.get(name="Joan")
127 def test_delete_when_missing(self):
129 Bug #8175: correctly delete an object where the file no longer
130 exists on the file system.
132 p = self.PersonModel(name="Fred")
133 p.mugshot.save("shot", self.file1)
134 os.remove(p.mugshot.path)
135 p.delete()
137 def test_size_method(self):
139 Bug #8534: FileField.size should not leave the file open.
141 p = self.PersonModel(name="Joan")
142 p.mugshot.save("shot", self.file1)
144 # Get a "clean" model instance
145 p = self.PersonModel.objects.get(name="Joan")
146 # It won't have an opened file.
147 self.assertEqual(p.mugshot.closed, True)
149 # After asking for the size, the file should still be closed.
150 _ = p.mugshot.size
151 self.assertEqual(p.mugshot.closed, True)
153 def test_pickle(self):
155 Tests that ImageField can be pickled, unpickled, and that the
156 image of the unpickled version is the same as the original.
158 import pickle
160 p = Person(name="Joe")
161 p.mugshot.save("mug", self.file1)
162 dump = pickle.dumps(p)
164 p2 = Person(name="Bob")
165 p2.mugshot = self.file1
167 loaded_p = pickle.loads(dump)
168 self.assertEqual(p.mugshot, loaded_p.mugshot)
171 class ImageFieldTwoDimensionsTests(ImageFieldTestMixin, TestCase):
173 Tests behavior of an ImageField and its dimensions fields.
176 def test_constructor(self):
178 Tests assigning an image field through the model's constructor.
180 p = self.PersonModel(name='Joe', mugshot=self.file1)
181 self.check_dimensions(p, 4, 8)
182 p.save()
183 self.check_dimensions(p, 4, 8)
185 def test_image_after_constructor(self):
187 Tests behavior when image is not passed in constructor.
189 p = self.PersonModel(name='Joe')
190 # TestImageField value will default to being an instance of its
191 # attr_class, a TestImageFieldFile, with name == None, which will
192 # cause it to evaluate as False.
193 self.assertEqual(isinstance(p.mugshot, TestImageFieldFile), True)
194 self.assertEqual(bool(p.mugshot), False)
196 # Test setting a fresh created model instance.
197 p = self.PersonModel(name='Joe')
198 p.mugshot = self.file1
199 self.check_dimensions(p, 4, 8)
201 def test_create(self):
203 Tests assigning an image in Manager.create().
205 p = self.PersonModel.objects.create(name='Joe', mugshot=self.file1)
206 self.check_dimensions(p, 4, 8)
208 def test_default_value(self):
210 Tests that the default value for an ImageField is an instance of
211 the field's attr_class (TestImageFieldFile in this case) with no
212 name (name set to None).
214 p = self.PersonModel()
215 self.assertEqual(isinstance(p.mugshot, TestImageFieldFile), True)
216 self.assertEqual(bool(p.mugshot), False)
218 def test_assignment_to_None(self):
220 Tests that assigning ImageField to None clears dimensions.
222 p = self.PersonModel(name='Joe', mugshot=self.file1)
223 self.check_dimensions(p, 4, 8)
225 # If image assigned to None, dimension fields should be cleared.
226 p.mugshot = None
227 self.check_dimensions(p, None, None)
229 p.mugshot = self.file2
230 self.check_dimensions(p, 8, 4)
232 def test_field_save_and_delete_methods(self):
234 Tests assignment using the field's save method and deletion using
235 the field's delete method.
237 p = self.PersonModel(name='Joe')
238 p.mugshot.save("mug", self.file1)
239 self.check_dimensions(p, 4, 8)
241 # A new file should update dimensions.
242 p.mugshot.save("mug", self.file2)
243 self.check_dimensions(p, 8, 4)
245 # Field and dimensions should be cleared after a delete.
246 p.mugshot.delete(save=False)
247 self.assertEqual(p.mugshot, None)
248 self.check_dimensions(p, None, None)
250 def test_dimensions(self):
252 Checks that dimensions are updated correctly in various situations.
254 p = self.PersonModel(name='Joe')
256 # Dimensions should get set if file is saved.
257 p.mugshot.save("mug", self.file1)
258 self.check_dimensions(p, 4, 8)
260 # Test dimensions after fetching from database.
261 p = self.PersonModel.objects.get(name='Joe')
262 # Bug 11084: Dimensions should not get recalculated if file is
263 # coming from the database. We test this by checking if the file
264 # was opened.
265 self.assertEqual(p.mugshot.was_opened, False)
266 self.check_dimensions(p, 4, 8)
267 # After checking dimensions on the image field, the file will have
268 # opened.
269 self.assertEqual(p.mugshot.was_opened, True)
270 # Dimensions should now be cached, and if we reset was_opened and
271 # check dimensions again, the file should not have opened.
272 p.mugshot.was_opened = False
273 self.check_dimensions(p, 4, 8)
274 self.assertEqual(p.mugshot.was_opened, False)
276 # If we assign a new image to the instance, the dimensions should
277 # update.
278 p.mugshot = self.file2
279 self.check_dimensions(p, 8, 4)
280 # Dimensions were recalculated, and hence file should have opened.
281 self.assertEqual(p.mugshot.was_opened, True)
284 class ImageFieldNoDimensionsTests(ImageFieldTwoDimensionsTests):
286 Tests behavior of an ImageField with no dimension fields.
289 PersonModel = Person
292 class ImageFieldOneDimensionTests(ImageFieldTwoDimensionsTests):
294 Tests behavior of an ImageField with one dimensions field.
297 PersonModel = PersonWithHeight
300 class ImageFieldDimensionsFirstTests(ImageFieldTwoDimensionsTests):
302 Tests behavior of an ImageField where the dimensions fields are
303 defined before the ImageField.
306 PersonModel = PersonDimensionsFirst
309 class ImageFieldUsingFileTests(ImageFieldTwoDimensionsTests):
311 Tests behavior of an ImageField when assigning it a File instance
312 rather than an ImageFile instance.
315 PersonModel = PersonDimensionsFirst
316 File = File
319 class TwoImageFieldTests(ImageFieldTestMixin, TestCase):
321 Tests a model with two ImageFields.
324 PersonModel = PersonTwoImages
326 def test_constructor(self):
327 p = self.PersonModel(mugshot=self.file1, headshot=self.file2)
328 self.check_dimensions(p, 4, 8, 'mugshot')
329 self.check_dimensions(p, 8, 4, 'headshot')
330 p.save()
331 self.check_dimensions(p, 4, 8, 'mugshot')
332 self.check_dimensions(p, 8, 4, 'headshot')
334 def test_create(self):
335 p = self.PersonModel.objects.create(mugshot=self.file1,
336 headshot=self.file2)
337 self.check_dimensions(p, 4, 8)
338 self.check_dimensions(p, 8, 4, 'headshot')
340 def test_assignment(self):
341 p = self.PersonModel()
342 self.check_dimensions(p, None, None, 'mugshot')
343 self.check_dimensions(p, None, None, 'headshot')
345 p.mugshot = self.file1
346 self.check_dimensions(p, 4, 8, 'mugshot')
347 self.check_dimensions(p, None, None, 'headshot')
348 p.headshot = self.file2
349 self.check_dimensions(p, 4, 8, 'mugshot')
350 self.check_dimensions(p, 8, 4, 'headshot')
352 # Clear the ImageFields one at a time.
353 p.mugshot = None
354 self.check_dimensions(p, None, None, 'mugshot')
355 self.check_dimensions(p, 8, 4, 'headshot')
356 p.headshot = None
357 self.check_dimensions(p, None, None, 'mugshot')
358 self.check_dimensions(p, None, None, 'headshot')
360 def test_field_save_and_delete_methods(self):
361 p = self.PersonModel(name='Joe')
362 p.mugshot.save("mug", self.file1)
363 self.check_dimensions(p, 4, 8, 'mugshot')
364 self.check_dimensions(p, None, None, 'headshot')
365 p.headshot.save("head", self.file2)
366 self.check_dimensions(p, 4, 8, 'mugshot')
367 self.check_dimensions(p, 8, 4, 'headshot')
369 # We can use save=True when deleting the image field with null=True
370 # dimension fields and the other field has an image.
371 p.headshot.delete(save=True)
372 self.check_dimensions(p, 4, 8, 'mugshot')
373 self.check_dimensions(p, None, None, 'headshot')
374 p.mugshot.delete(save=False)
375 self.check_dimensions(p, None, None, 'mugshot')
376 self.check_dimensions(p, None, None, 'headshot')
378 def test_dimensions(self):
380 Checks that dimensions are updated correctly in various situations.
382 p = self.PersonModel(name='Joe')
384 # Dimensions should get set for the saved file.
385 p.mugshot.save("mug", self.file1)
386 p.headshot.save("head", self.file2)
387 self.check_dimensions(p, 4, 8, 'mugshot')
388 self.check_dimensions(p, 8, 4, 'headshot')
390 # Test dimensions after fetching from database.
391 p = self.PersonModel.objects.get(name='Joe')
392 # Bug 11084: Dimensions should not get recalculated if file is
393 # coming from the database. We test this by checking if the file
394 # was opened.
395 self.assertEqual(p.mugshot.was_opened, False)
396 self.assertEqual(p.headshot.was_opened, False)
397 self.check_dimensions(p, 4, 8,'mugshot')
398 self.check_dimensions(p, 8, 4, 'headshot')
399 # After checking dimensions on the image fields, the files will
400 # have been opened.
401 self.assertEqual(p.mugshot.was_opened, True)
402 self.assertEqual(p.headshot.was_opened, True)
403 # Dimensions should now be cached, and if we reset was_opened and
404 # check dimensions again, the file should not have opened.
405 p.mugshot.was_opened = False
406 p.headshot.was_opened = False
407 self.check_dimensions(p, 4, 8,'mugshot')
408 self.check_dimensions(p, 8, 4, 'headshot')
409 self.assertEqual(p.mugshot.was_opened, False)
410 self.assertEqual(p.headshot.was_opened, False)
412 # If we assign a new image to the instance, the dimensions should
413 # update.
414 p.mugshot = self.file2
415 p.headshot = self.file1
416 self.check_dimensions(p, 8, 4, 'mugshot')
417 self.check_dimensions(p, 4, 8, 'headshot')
418 # Dimensions were recalculated, and hence file should have opened.
419 self.assertEqual(p.mugshot.was_opened, True)
420 self.assertEqual(p.headshot.was_opened, True)