1
- from typing import cast
1
+ import inspect
2
+ import sys
3
+ from typing import Generator , cast
2
4
3
5
from django .core .files .storage import default_storage
6
+ from django .db import models
4
7
import pytest
5
8
6
9
from s3_file_field import _registry
@@ -15,6 +18,21 @@ def s3ff_field() -> S3FileField:
15
18
return cast (S3FileField , Resource ._meta .get_field ("blob" ))
16
19
17
20
21
+ @pytest .fixture ()
22
+ def ephemeral_s3ff_field () -> Generator [S3FileField , None , None ]:
23
+ # Declaring this will implicitly register the field
24
+ class EphemeralResource (models .Model ):
25
+ class Meta :
26
+ app_label = "test_app"
27
+
28
+ blob = S3FileField ()
29
+
30
+ field = cast (S3FileField , EphemeralResource ._meta .get_field ("blob" ))
31
+ yield field
32
+ # The registry state is global to the process, so attempt to clean up
33
+ del _registry ._fields [field .id ]
34
+
35
+
18
36
def test_field_id (s3ff_field : S3FileField ) -> None :
19
37
assert s3ff_field .id == "test_app.Resource.blob"
20
38
@@ -41,3 +59,28 @@ def test_registry_iter_storages() -> None:
41
59
42
60
assert len (fields ) == 1
43
61
assert fields [0 ] is default_storage
62
+
63
+
64
+ @pytest .mark .skipif (sys .version_info < (3 , 9 ), reason = "Bug bpo-35113" )
65
+ def test_registry_register_field_multiple (ephemeral_s3ff_field : S3FileField ) -> None :
66
+ with pytest .warns (
67
+ RuntimeWarning , match = r"Overwriting existing S3FileField declaration"
68
+ ) as records :
69
+ # Try to create a field with the same id
70
+ class EphemeralResource (models .Model ):
71
+ class Meta :
72
+ app_label = "test_app"
73
+
74
+ blob = S3FileField ()
75
+
76
+ # Ensure the warning is attributed to the re-defined model, since stacklevel is set empirically
77
+ warning = next (record for record in records if str (record .message ).startswith ("Overwriting" ))
78
+ assert warning .filename == inspect .getsourcefile (EphemeralResource )
79
+ assert warning .lineno == inspect .getsourcelines (EphemeralResource )[1 ]
80
+
81
+ duplicate_field = cast (S3FileField , EphemeralResource ._meta .get_field ("blob" ))
82
+ # Sanity check
83
+ assert duplicate_field .id == ephemeral_s3ff_field .id
84
+ assert duplicate_field is not ephemeral_s3ff_field
85
+ # The most recently registered field should by stored
86
+ assert _registry .get_field (duplicate_field .id ) is duplicate_field
0 commit comments