Skip to content

Commit

Permalink
Add PastDatetime provider
Browse files Browse the repository at this point in the history
  • Loading branch information
sinecode committed Dec 13, 2019
1 parent 2b66578 commit 0a8018b
Show file tree
Hide file tree
Showing 5 changed files with 195 additions and 59 deletions.
2 changes: 2 additions & 0 deletions mimesis/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
Hardware,
Internet,
Numbers,
PastDatetime,
Path,
Payment,
Person,
Expand All @@ -51,6 +52,7 @@
'Hardware',
'Internet',
'Numbers',
'PastDatetime',
'Path',
'Payment',
'Person',
Expand Down
3 changes: 2 additions & 1 deletion mimesis/providers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from mimesis.providers.clothing import Clothing
from mimesis.providers.code import Code
from mimesis.providers.cryptographic import Cryptographic
from mimesis.providers.date import Datetime, FutureDatetime
from mimesis.providers.date import Datetime, FutureDatetime, PastDatetime
from mimesis.providers.development import Development
from mimesis.providers.file import File
from mimesis.providers.food import Food
Expand Down Expand Up @@ -48,6 +48,7 @@
'Hardware',
'Internet',
'Numbers',
'PastDatetime',
'Path',
'Payment',
'Person',
Expand Down
125 changes: 96 additions & 29 deletions mimesis/providers/date.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from mimesis.providers.base import BaseDataProvider
from mimesis.typing import Date, DateTime, Time

__all__ = ['Datetime', 'FutureDatetime']
__all__ = ['Datetime', 'FutureDatetime', 'PastDatetime']


class Datetime(BaseDataProvider):
Expand Down Expand Up @@ -290,34 +290,6 @@ def _validate_future_year(self, year: int) -> int:
if year < self.future.year:
raise ValueError(f'Year {year} is before the current future')

def week_date(self, end: int = None) -> str:
"""Get week number with year from the year of the current future.
:param end: To end.
:raises ValueError: When ``end`` is before the year of the
current future.
:return: Week number.
"""
if not end:
end = self.future.year + 1
else:
self._validate_future_year(end)
return self._dt.week_date(start=self.future.year, end=end)

def year(self, maximum: int = None) -> int:
"""Generate a random year from the year of the current future.
:param maximum: Maximum value.
:raises ValueError: When ``maximum`` is before the year of the
current future.
:return: Year.
"""
if not maximum:
maximum = self.future.year + 65
else:
self._validate_future_year(maximum)
return self._dt.year(minimum=self.future.year, maximum=maximum)

def date(self, end: int = None) -> Date:
"""Generate random date object from the year of the current future.
Expand Down Expand Up @@ -377,3 +349,98 @@ def timestamp(self, posix: bool = True, **kwargs) -> Union[str, int]:
"""
return self._dt.timestamp(
posix=posix, start=self.future.year, end=self.future.year + 19)


class PastDatetime(BaseDataProvider):
"""Class for generating data related to the date and time in the past."""

def __init__(self, days: int = 1, weeks: int = 0, hours: int = 0,
minutes: int = 0, seconds: int = 0, *args, **kwargs):
"""Initialize attributes.
:param days: Number of days to subtract to the current date.
:param weeks: Number of weeks to subtract to the current date.
:param hours: Number of hours to subtract to the current date.
:param minutes: Number of minutes to subtract to the current date.
:param seconds: Number of seconds to subtract to the current date.
"""
super().__init__(*args, **kwargs)
self.past = datetime.now() - timedelta(
days=days, weeks=weeks, hours=hours, minutes=minutes,
seconds=seconds)
self._dt = Datetime(*args, **kwargs)

class Meta:
"""Class for metadata."""

name = 'past_datetime'

def _validate_past_year(self, year: int) -> int:
"""Check if the year is after the year of the current past.
:param year: Year to validate.
:raise ValueError: If ``year`` is after the year of the
current past
"""
if year > self.past.year:
raise ValueError(f'Year {year} is after the current past')

def date(self, start: int = None) -> Date:
"""Generate random date object from the year of the current past.
:param start: Maximum value of year.
:raises ValueError: When ``start`` is after the year of the
current past.
:return: Formatted date.
"""
if not start:
start = self.past.year - 19
else:
self._validate_past_year(start)
return self._dt.date(start=start, end=self.past.year)

def formatted_date(self, fmt: str = '', **kwargs) -> str:
"""Generate random date as string.
:param fmt: The format of date, if None then use standard
accepted in the current locale.
:param kwargs: Keyword arguments for :meth:`~Datetime.date()`
:return: Formatted date.
"""
return self._dt.formatted_date(fmt=fmt, start=self.past.year)

def datetime(self, start: int = None,
timezone: Optional[str] = None) -> DateTime:
"""Generate random datetime from the year of the current past.
:param start: Maximum value of year.
:raises ValueError: When ``start`` is after the year of the
current past.
:param timezone: Set custom timezone (pytz required).
:return: Datetime
"""
if not start:
start = self.past.year - 19
else:
self._validate_past_year(start)
return self._dt.datetime(
start=start, end=self.past.year, timezone=timezone)

def formatted_datetime(self, fmt: str = '', **kwargs) -> str:
"""Generate datetime string in human readable format.
:param fmt: Custom format (default is format for current locale)
:param kwargs: Keyword arguments for :meth:`~Datetime.datetime()`
:return: Formatted datetime string.
"""
return self._dt.formatted_datetime(fmt=fmt, end=self.past.year)

def timestamp(self, posix: bool = True, **kwargs) -> Union[str, int]:
"""Generate random timestamp.
:param posix: POSIX time.
:param kwargs: Kwargs for :meth:`~pastDatetime.datetime()`.
:return: Timestamp.
"""
return self._dt.timestamp(
posix=posix, start=self.past.year - 19, end=self.past.year)
29 changes: 0 additions & 29 deletions tests/test_providers/test_future_datetime.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,25 +19,6 @@ def future_dt(self):
def test_str(self, dt):
assert re.match(patterns.DATA_PROVIDER_STR_REGEX, str(dt))

def test_week_date(self, future_dt):
result = future_dt.week_date()
result = result.replace('-', ' ').replace('W', '')
year, week = result.split(' ')
assert int(year) >= future_dt.future.year
assert int(year) <= future_dt.future.year + 1
assert int(week) <= 52

with pytest.raises(ValueError):
future_dt.week_date(end=datetime.MINYEAR)

def test_year(self, future_dt):
result = future_dt.year()
assert result >= future_dt.future.year
assert result <= future_dt.future.year + 65

with pytest.raises(ValueError):
future_dt.year(maximum=datetime.MINYEAR)

def test_date(self, future_dt):
date_object = future_dt.date()
assert isinstance(date_object, datetime.date)
Expand Down Expand Up @@ -93,16 +74,6 @@ def d1(self, seed):
def d2(self, seed):
return FutureDatetime(seed=seed)

def test_week_date(self, d1, d2):
assert d1.week_date() == d2.week_date()
assert d1.week_date(end=datetime.MAXYEAR) == \
d2.week_date(end=datetime.MAXYEAR)

def test_year(self, d1, d2):
assert d1.year() == d2.year()
assert d1.year(maximum=datetime.MAXYEAR) == \
d2.year(maximum=datetime.MAXYEAR)

def test_date(self, d1, d2):
assert d1.date() == d2.date()
assert d1.date(end=datetime.MAXYEAR) == d2.date(end=datetime.MAXYEAR)
Expand Down
95 changes: 95 additions & 0 deletions tests/test_providers/test_past_datetime.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# -*- coding: utf-8 -*-
import datetime
import re

import pytest

from mimesis import PastDatetime
from mimesis.data import GMT_OFFSETS, TIMEZONES

from . import patterns


class TestPastDatetime(object):

@pytest.fixture
def past_dt(self):
return PastDatetime()

def test_str(self, dt):
assert re.match(patterns.DATA_PROVIDER_STR_REGEX, str(dt))

def test_date(self, past_dt):
date_object = past_dt.date()
assert isinstance(date_object, datetime.date)
assert date_object.year >= past_dt.past.year - 19
assert date_object.year <= past_dt.past.year

with pytest.raises(ValueError):
past_dt.date(start=datetime.MAXYEAR)

def test_formatted_date(self, past_dt):
fmt_date = past_dt.formatted_date('%Y', start=datetime.MINYEAR)
assert int(fmt_date) >= past_dt.past.year
assert isinstance(fmt_date, str)

@pytest.mark.parametrize(
'start, timezone', [
(datetime.MINYEAR, 'Europe/Paris'),
(datetime.MINYEAR, None),
],
)
def test_datetime(self, past_dt, start, timezone):
dt_obj = past_dt.datetime(start=start, timezone=timezone)

assert datetime.MINYEAR <= dt_obj.year <= past_dt.past.year
assert isinstance(dt_obj, datetime.datetime)

with pytest.raises(ValueError):
past_dt.datetime(start=datetime.MAXYEAR)

def test_formatted_datetime(self, past_dt):
dt_obj = past_dt.formatted_datetime('%Y', start=datetime.MINYEAR)
assert int(dt_obj) <= past_dt.past.year
assert isinstance(dt_obj, str)

def test_timestamp(self, past_dt):
result = past_dt.timestamp(start=datetime.MINYEAR)
assert result is not None
assert isinstance(result, int)
year = datetime.datetime.fromtimestamp(int(result)).year
assert year <= past_dt.past.year

result = past_dt.timestamp(posix=False, start=datetime.MINYEAR)
assert isinstance(result, str)


class TestSeededPastDatetime(object):

@pytest.fixture
def d1(self, seed):
return PastDatetime(seed=seed)

@pytest.fixture
def d2(self, seed):
return PastDatetime(seed=seed)

def test_date(self, d1, d2):
assert d1.date() == d2.date()
assert d1.date(start=datetime.MINYEAR) == \
d2.date(start=datetime.MINYEAR)

def test_formatted_date(self, d1, d2):
assert d1.formatted_date() == d2.formatted_date()

def test_datetime(self, d1, d2):
assert d1.datetime() == d2.datetime()
assert d1.datetime(start=datetime.MINYEAR) == \
d2.datetime(start=datetime.MINYEAR)

def test_formatted_datetime(self, d1, d2):
assert d1.formatted_datetime() == d2.formatted_datetime()

def test_timestamp(self, d1, d2):
assert d1.timestamp() == d2.timestamp()
assert d1.timestamp(posix=False) == d2.timestamp(posix=False)

0 comments on commit 0a8018b

Please sign in to comment.