Skip to content

add native datetime to pendulum_dt.py #176

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions pydantic_extra_types/pendulum_dt.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
CoreSchema implementation. This allows Pydantic to validate the DateTime object.
"""

import pendulum

try:
from pendulum import Date as _Date
from pendulum import DateTime as _DateTime
Expand All @@ -12,6 +14,7 @@
raise RuntimeError(
'The `pendulum_dt` module requires "pendulum" to be installed. You can install it with "pip install pendulum".'
)
from datetime import date, datetime, timedelta
from typing import Any, List, Type

from pydantic import GetCoreSchemaHandler
Expand Down Expand Up @@ -68,6 +71,9 @@ def _validate(cls, value: Any, handler: core_schema.ValidatorFunctionWrapHandler
if isinstance(value, _DateTime):
return handler(value)

if isinstance(value, datetime):
return handler(DateTime.instance(value))

# otherwise, parse it.
try:
data = parse(value)
Expand Down Expand Up @@ -126,6 +132,9 @@ def _validate(cls, value: Any, handler: core_schema.ValidatorFunctionWrapHandler
if isinstance(value, _Date):
return handler(value)

if isinstance(value, date):
return handler(pendulum.instance(value))

# otherwise, parse it.
try:
data = parse(value)
Expand Down Expand Up @@ -184,6 +193,9 @@ def _validate(cls, value: Any, handler: core_schema.ValidatorFunctionWrapHandler
if isinstance(value, _Duration):
return handler(value)

if isinstance(value, timedelta):
return handler(_Duration(seconds=value.total_seconds()))

# otherwise, parse it.
try:
data = parse(value)
Expand Down
74 changes: 62 additions & 12 deletions tests/test_pendulum_dt.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
from datetime import date, datetime, timedelta
from datetime import timezone as tz

import pendulum
import pytest
from pydantic import BaseModel, ValidationError

from pydantic_extra_types.pendulum_dt import Date, DateTime, Duration

UTC = tz.utc


class DtModel(BaseModel):
dt: DateTime
Expand All @@ -17,32 +22,77 @@ class DurationModel(BaseModel):
delta_t: Duration


def test_pendulum_dt_existing_instance():
@pytest.mark.parametrize(
'instance',
[
pendulum.now(),
datetime.now(),
datetime.now(UTC),
],
)
def test_existing_instance(instance):
"""
Verifies that constructing a model with an existing pendulum dt doesn't throw.
"""
now = pendulum.now()
model = DtModel(dt=now)
assert model.dt == now
model = DtModel(dt=instance)
if isinstance(instance, datetime):
assert model.dt == pendulum.instance(instance)
if instance.tzinfo is None and isinstance(instance, datetime):
instance = model.dt.replace(tzinfo=UTC) # pendulum defaults to UTC
dt = model.dt
else:
assert model.dt == instance
dt = model.dt

assert dt.day == instance.day
assert dt.month == instance.month
assert dt.year == instance.year
assert dt.hour == instance.hour
assert dt.minute == instance.minute
assert dt.second == instance.second
assert dt.microsecond == instance.microsecond
if dt.tzinfo != instance.tzinfo:
assert dt.tzinfo.utcoffset(dt) == instance.tzinfo.utcoffset(instance)


def test_pendulum_date_existing_instance():
@pytest.mark.parametrize(
'instance',
[
pendulum.today(),
date.today(),
],
)
def test_pendulum_date_existing_instance(instance):
"""
Verifies that constructing a model with an existing pendulum date doesn't throw.
"""
today = pendulum.today().date()
model = DateModel(d=today)
assert model.d == today
model = DateModel(d=instance)
if isinstance(instance, datetime):
assert model.d == pendulum.instance(instance).date()
else:
assert model.d == instance
d = model.d
assert d.day == instance.day
assert d.month == instance.month
assert d.year == instance.year


def test_pendulum_duration_existing_instance():
@pytest.mark.parametrize(
'instance',
[
pendulum.duration(days=42, hours=13, minutes=37),
pendulum.duration(days=-42, hours=13, minutes=37),
timedelta(days=42, hours=13, minutes=37),
timedelta(days=-42, hours=13, minutes=37),
],
)
def test_duration_timedelta__existing_instance(instance):
"""
Verifies that constructing a model with an existing pendulum duration doesn't throw.
"""
delta_t = pendulum.duration(days=42, hours=13, minutes=37)
model = DurationModel(delta_t=delta_t)
model = DurationModel(delta_t=instance)

assert model.delta_t.total_seconds() == delta_t.total_seconds()
assert model.delta_t.total_seconds() == instance.total_seconds()


@pytest.mark.parametrize(
Expand Down
Loading