|
9 | 9 |
|
10 | 10 | UTC = tz.utc
|
11 | 11 |
|
| 12 | +DtTypeAdapter = TypeAdapter(datetime) |
| 13 | + |
12 | 14 |
|
13 | 15 | class DtModel(BaseModel):
|
14 | 16 | dt: DateTime
|
15 | 17 |
|
16 | 18 |
|
| 19 | +class DateTimeNonStrict(DateTime, strict=False): |
| 20 | + pass |
| 21 | + |
| 22 | + |
| 23 | +class DtModelNotStrict(BaseModel): |
| 24 | + dt: DateTimeNonStrict |
| 25 | + |
| 26 | + |
17 | 27 | class DateModel(BaseModel):
|
18 | 28 | d: Date
|
19 | 29 |
|
@@ -119,6 +129,91 @@ def test_pendulum_dt_from_serialized(dt):
|
119 | 129 | assert isinstance(model.dt, pendulum.DateTime)
|
120 | 130 |
|
121 | 131 |
|
| 132 | +@pytest.mark.parametrize( |
| 133 | + 'dt', |
| 134 | + [ |
| 135 | + pendulum.now().to_iso8601_string(), |
| 136 | + pendulum.now().to_w3c_string(), |
| 137 | + 'Sat Oct 11 17:13:46 UTC 2003', # date util parsing |
| 138 | + pendulum.now().to_iso8601_string()[:5], # actualy valid or pendulum.parse(dt, strict=False) would fail here |
| 139 | + ], |
| 140 | +) |
| 141 | +def test_pendulum_dt_not_strict_from_serialized(dt): |
| 142 | + """ |
| 143 | + Verifies that building an instance from serialized, well-formed strings decode properly. |
| 144 | + """ |
| 145 | + dt_actual = pendulum.parse(dt, strict=False) |
| 146 | + model = DtModelNotStrict(dt=dt) |
| 147 | + assert model.dt == dt_actual |
| 148 | + assert type(model.dt) is DateTime |
| 149 | + assert isinstance(model.dt, pendulum.DateTime) |
| 150 | + |
| 151 | + |
| 152 | +@pytest.mark.parametrize( |
| 153 | + 'dt', |
| 154 | + [ |
| 155 | + pendulum.now().to_iso8601_string(), |
| 156 | + pendulum.now().to_w3c_string(), |
| 157 | + 1718096578, |
| 158 | + 1718096578.5, |
| 159 | + -5, |
| 160 | + -5.5, |
| 161 | + float('-0'), |
| 162 | + '1718096578', |
| 163 | + '1718096578.5', |
| 164 | + '-5', |
| 165 | + '-5.5', |
| 166 | + '-0', |
| 167 | + '-0.0', |
| 168 | + '+0.0', |
| 169 | + '+1718096578.5', |
| 170 | + float('-2e10') - 1.0, |
| 171 | + float('2e10') + 1.0, |
| 172 | + -2e10 - 1, |
| 173 | + 2e10 + 1, |
| 174 | + ], |
| 175 | +) |
| 176 | +def test_pendulum_dt_from_str_unix_timestamp(dt): |
| 177 | + """ |
| 178 | + Verifies that building an instance from serialized, well-formed strings decode properly. |
| 179 | + """ |
| 180 | + dt_actual = pendulum.instance(DtTypeAdapter.validate_python(dt)) |
| 181 | + model = DtModel(dt=dt) |
| 182 | + assert model.dt == dt_actual |
| 183 | + assert type(model.dt) is DateTime |
| 184 | + assert isinstance(model.dt, pendulum.DateTime) |
| 185 | + |
| 186 | + |
| 187 | +@pytest.mark.parametrize( |
| 188 | + 'dt', |
| 189 | + [ |
| 190 | + 1718096578, |
| 191 | + 1718096578.5, |
| 192 | + -5, |
| 193 | + -5.5, |
| 194 | + float('-0'), |
| 195 | + '1718096578', |
| 196 | + '1718096578.5', |
| 197 | + '-5', |
| 198 | + '-5.5', |
| 199 | + '-0', |
| 200 | + '-0.0', |
| 201 | + '+0.0', |
| 202 | + '+1718096578.5', |
| 203 | + float('-2e10') - 1.0, |
| 204 | + float('2e10') + 1.0, |
| 205 | + -2e10 - 1, |
| 206 | + 2e10 + 1, |
| 207 | + ], |
| 208 | +) |
| 209 | +def test_pendulum_dt_from_str_unix_timestamp_is_utc(dt): |
| 210 | + """ |
| 211 | + Verifies that without timezone information, it is coerced to UTC. As in pendulum |
| 212 | + """ |
| 213 | + model = DtModel(dt=dt) |
| 214 | + assert model.dt.tzinfo.tzname(model.dt) == 'UTC' |
| 215 | + |
| 216 | + |
122 | 217 | @pytest.mark.parametrize(
|
123 | 218 | 'd',
|
124 | 219 | [pendulum.now().date().isoformat(), pendulum.now().to_w3c_string(), pendulum.now().to_iso8601_string()],
|
@@ -155,22 +250,68 @@ def test_pendulum_duration_from_serialized(delta_t_str):
|
155 | 250 | assert isinstance(model.delta_t, pendulum.Duration)
|
156 | 251 |
|
157 | 252 |
|
158 |
| -@pytest.mark.parametrize('dt', [None, 'malformed', pendulum.now().to_iso8601_string()[:5], 42, 'P10Y10M10D']) |
| 253 | +def get_invalid_dt_common(): |
| 254 | + return [ |
| 255 | + None, |
| 256 | + 'malformed', |
| 257 | + 'P10Y10M10D', |
| 258 | + float('inf'), |
| 259 | + float('-inf'), |
| 260 | + 'inf', |
| 261 | + '-inf', |
| 262 | + 'INF', |
| 263 | + '-INF', |
| 264 | + '+inf', |
| 265 | + 'Infinity', |
| 266 | + '+Infinity', |
| 267 | + '-Infinity', |
| 268 | + 'INFINITY', |
| 269 | + '+INFINITY', |
| 270 | + '-INFINITY', |
| 271 | + 'infinity', |
| 272 | + '+infinity', |
| 273 | + '-infinity', |
| 274 | + float('nan'), |
| 275 | + 'nan', |
| 276 | + 'NaN', |
| 277 | + 'NAN', |
| 278 | + '+nan', |
| 279 | + '-nan', |
| 280 | + ] |
| 281 | + |
| 282 | + |
| 283 | +dt_strict = get_invalid_dt_common() |
| 284 | +dt_strict.append(pendulum.now().to_iso8601_string()[:5]) |
| 285 | + |
| 286 | + |
| 287 | +@pytest.mark.parametrize( |
| 288 | + 'dt', |
| 289 | + dt_strict, |
| 290 | +) |
159 | 291 | def test_pendulum_dt_malformed(dt):
|
160 | 292 | """
|
161 |
| - Verifies that the instance fails to validate if malformed dt are passed. |
| 293 | + Verifies that the instance fails to validate if malformed dt is passed. |
162 | 294 | """
|
163 | 295 | with pytest.raises(ValidationError):
|
164 | 296 | DtModel(dt=dt)
|
165 | 297 |
|
166 | 298 |
|
167 |
| -@pytest.mark.parametrize('date', [None, 'malformed', pendulum.today().to_iso8601_string()[:5], 42, 'P10Y10M10D']) |
168 |
| -def test_pendulum_date_malformed(date): |
| 299 | +@pytest.mark.parametrize('dt', get_invalid_dt_common()) |
| 300 | +def test_pendulum_dt_non_strict_malformed(dt): |
| 301 | + """ |
| 302 | + Verifies that the instance fails to validate if malformed dt are passed. |
| 303 | + """ |
| 304 | + with pytest.raises(ValidationError): |
| 305 | + DtModelNotStrict(dt=dt) |
| 306 | + |
| 307 | + |
| 308 | +@pytest.mark.parametrize('invalid_value', [None, 'malformed', pendulum.today().to_iso8601_string()[:5], 'P10Y10M10D']) |
| 309 | +def test_pendulum_date_malformed(invalid_value): |
169 | 310 | """
|
170 | 311 | Verifies that the instance fails to validate if malformed date are passed.
|
171 | 312 | """
|
172 | 313 | with pytest.raises(ValidationError):
|
173 |
| - DateModel(d=date) |
| 314 | + DateModel(d=invalid_value) |
174 | 315 |
|
175 | 316 |
|
176 | 317 | @pytest.mark.parametrize(
|
|
0 commit comments