-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Expand file tree
/
Copy pathtest_datetime_field.py
More file actions
248 lines (191 loc) · 7 KB
/
test_datetime_field.py
File metadata and controls
248 lines (191 loc) · 7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
import datetime as dt
from datetime import timezone
import pytest
from mongoengine import *
from mongoengine import connection
from tests.utils import MongoDBTestCase, get_as_pymongo
try:
import dateutil
except ImportError:
dateutil = None
class TestDateTimeField(MongoDBTestCase):
def test_datetime_from_empty_string(self):
"""
Ensure an exception is raised when trying to
cast an empty string to datetime.
"""
class MyDoc(Document):
dt = DateTimeField()
md = MyDoc(dt="")
with pytest.raises(ValidationError):
md.save()
def test_datetime_from_whitespace_string(self):
"""
Ensure an exception is raised when trying to
cast a whitespace-only string to datetime.
"""
class MyDoc(Document):
dt = DateTimeField()
md = MyDoc(dt=" ")
with pytest.raises(ValidationError):
md.save()
def test_default_value_utcnow(self):
"""Ensure that default field values are used when creating
a document.
"""
class Person(Document):
created = DateTimeField(default=lambda: dt.datetime.now(dt.timezone.utc))
utcnow = dt.datetime.now(timezone.utc)
person = Person()
person.validate()
person_created_t0 = person.created
assert person.created - utcnow < dt.timedelta(seconds=1)
assert person_created_t0 == person.created # make sure it does not change
assert person._data["created"] == person.created
def test_set_using_callable(self):
# Weird feature but it's there for a while so let's make sure we don't break it
class Person(Document):
created = DateTimeField()
Person.drop_collection()
person = Person()
frozen_dt = dt.datetime(2020, 7, 25, 9, 56, 1)
person.created = lambda: frozen_dt
person.save()
assert callable(person.created)
assert get_as_pymongo(person) == {"_id": person.id, "created": frozen_dt}
def test_handling_microseconds(self):
"""Tests showing pymongo datetime fields handling of microseconds.
Microseconds are rounded to the nearest millisecond and pre UTC
handling is wonky.
See: http://api.mongodb.org/python/current/api/bson/son.html#dt
"""
class LogEntry(Document):
date = DateTimeField()
LogEntry.drop_collection()
# Test can save dates
log = LogEntry()
log.date = dt.date.today()
log.save()
log.reload()
assert log.date.date() == dt.date.today()
# Post UTC - microseconds are rounded (down) nearest millisecond and
# dropped
d1 = dt.datetime(1970, 1, 1, 0, 0, 1, 999)
d2 = dt.datetime(1970, 1, 1, 0, 0, 1)
log = LogEntry()
log.date = d1
log.save()
log.reload()
assert log.date != d1
assert log.date == d2
# Post UTC - microseconds are rounded (down) nearest millisecond
d1 = dt.datetime(1970, 1, 1, 0, 0, 1, 9999)
d2 = dt.datetime(1970, 1, 1, 0, 0, 1, 9000)
log.date = d1
log.save()
log.reload()
assert log.date != d1
assert log.date == d2
def test_regular_usage(self):
"""Tests for regular datetime fields"""
class LogEntry(Document):
date = DateTimeField()
LogEntry.drop_collection()
d1 = dt.datetime(1970, 1, 1, 0, 0, 1)
log = LogEntry()
log.date = d1
log.validate()
log.save()
for query in (d1, d1.isoformat(" ")):
log1 = LogEntry.objects.get(date=query)
assert log == log1
if dateutil:
log1 = LogEntry.objects.get(date=d1.isoformat("T"))
assert log == log1
# create additional 19 log entries for a total of 20
for i in range(1971, 1990):
d = dt.datetime(i, 1, 1, 0, 0, 1)
LogEntry(date=d).save()
assert LogEntry.objects.count() == 20
# Test ordering
logs = LogEntry.objects.order_by("date")
i = 0
while i < 19:
assert logs[i].date <= logs[i + 1].date
i += 1
logs = LogEntry.objects.order_by("-date")
i = 0
while i < 19:
assert logs[i].date >= logs[i + 1].date
i += 1
# Test searching
logs = LogEntry.objects.filter(date__gte=dt.datetime(1980, 1, 1))
assert logs.count() == 10
logs = LogEntry.objects.filter(date__lte=dt.datetime(1980, 1, 1))
assert logs.count() == 10
logs = LogEntry.objects.filter(
date__lte=dt.datetime(1980, 1, 1), date__gte=dt.datetime(1975, 1, 1)
)
assert logs.count() == 5
def test_datetime_validation(self):
"""Ensure that invalid values cannot be assigned to datetime
fields.
"""
class LogEntry(Document):
time = DateTimeField()
log = LogEntry()
log.time = dt.datetime.now()
log.validate()
log.time = dt.date.today()
log.validate()
log.time = dt.datetime.now().isoformat(" ")
log.validate()
log.time = "2019-05-16 21:42:57.897847"
log.validate()
if dateutil:
log.time = dt.datetime.now().isoformat("T")
log.validate()
log.time = -1
with pytest.raises(ValidationError):
log.validate()
log.time = "ABC"
with pytest.raises(ValidationError):
log.validate()
log.time = "2019-05-16 21:GARBAGE:12"
with pytest.raises(ValidationError):
log.validate()
log.time = "2019-05-16 21:42:57.GARBAGE"
with pytest.raises(ValidationError):
log.validate()
log.time = "2019-05-16 21:42:57.123.456"
with pytest.raises(ValidationError):
log.validate()
def test_parse_datetime_as_str(self):
class DTDoc(Document):
date = DateTimeField()
date_str = "2019-03-02 22:26:01"
# make sure that passing a parsable datetime works
dtd = DTDoc()
dtd.date = date_str
assert isinstance(dtd.date, str)
dtd.save()
dtd.reload()
assert isinstance(dtd.date, dt.datetime)
assert str(dtd.date) == date_str
dtd.date = "January 1st, 9999999999"
with pytest.raises(ValidationError):
dtd.validate()
class TestDateTimeTzAware(MongoDBTestCase):
def test_datetime_tz_aware_mark_as_changed(self):
# Reset the connections
connection._connection_settings = {}
connection._connections = {}
connection._dbs = {}
connect(db="mongoenginetest", tz_aware=True)
class LogEntry(Document):
time = DateTimeField()
LogEntry.drop_collection()
LogEntry(time=dt.datetime(2013, 1, 1, 0, 0, 0)).save()
log = LogEntry.objects.first()
log.time = dt.datetime(2013, 1, 1, 0, 0, 0)
assert ["time"] == log._changed_fields