-
Notifications
You must be signed in to change notification settings - Fork 33
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
Datetimes have a UTC timezone by default #601
Changes from 4 commits
5e5fe2a
84d2bf4
93ed95d
298b772
b622e7c
09f197b
25d51df
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
- object: Contact | ||
fields: | ||
FirstName: | ||
fake: FirstName | ||
LastName: | ||
fake: LastName | ||
EmailBouncedDate: | ||
fake.datetime: | ||
start_date: -10y | ||
end_date: now | ||
timezone: | ||
relativedelta: | ||
hours: +8 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
- object: Contact | ||
fields: | ||
FirstName: | ||
fake: FirstName | ||
LastName: | ||
fake: LastName | ||
EmailBouncedDate: | ||
fake: DateTime |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -27,9 +27,8 @@ def generated_rows(request): | |
def row_values(index, value): | ||
return mockobj.mock_calls[index][1][1][value] | ||
|
||
def table_values(tablename, index, field=None): | ||
def table_values(tablename, index=None, field=None): | ||
"""Look up a value from a table.""" | ||
index = index - 1 # use 1-based indexing like Snowfakery does | ||
|
||
# create and cache a dict of table names to lists of rows | ||
if type(mockobj._index) != dict: | ||
|
@@ -38,10 +37,17 @@ def table_values(tablename, index, field=None): | |
table = row[1][0] | ||
mockobj._index.setdefault(table, []).append(row[1][1]) | ||
|
||
if field: # return just one field | ||
return mockobj._index[tablename][index][field] | ||
else: # return a full row | ||
return mockobj._index[tablename][index] | ||
if index is None: # return all rows | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These are some improvements to the testing infrastructure to make certain kinds of assertions easier to write. It doesn't require a deep review because it isn't user-facing code and it gets well-tested by virtue of being a test suite. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔬 🕵🏾♂️ |
||
if field is None: # return full rows | ||
return mockobj._index[tablename] | ||
else: # return a single field | ||
return [row[field] for row in mockobj._index[tablename]] | ||
else: # return data from just one row | ||
index = index - 1 # use 1-based indexing like Snowfakery does | ||
if field: # return just one field | ||
return mockobj._index[tablename][index][field] | ||
else: # return a full row | ||
return mockobj._index[tablename][index] | ||
|
||
with patch( | ||
"snowfakery.output_streams.DebugOutputStream.write_single_row" | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
- object: Contact | ||
fields: | ||
LastName: | ||
fake: LastName | ||
EmailBouncedDate: 2020-11-29 08:33:39+00:00 | ||
|
||
- object: Contact | ||
fields: | ||
LastName: | ||
fake: LastName | ||
EmailBouncedDate: | ||
fake: DateTime | ||
|
||
- object: Contact | ||
fields: | ||
LastName: | ||
fake: LastName | ||
EmailBouncedDate: | ||
fake.datetime: | ||
timezone: | ||
relativedelta: | ||
hours: 8 | ||
|
||
- object: Contact | ||
fields: | ||
LastName: | ||
fake: LastName | ||
EmailBouncedDate: | ||
fake.DateTimeBetween: | ||
start_date: -10y | ||
end_date: now | ||
|
||
- object: Contact | ||
fields: | ||
LastName: | ||
fake: LastName | ||
EmailBouncedDate: | ||
fake.DateTimeBetween: | ||
start_date: now | ||
end_date: +20y | ||
|
||
- object: Contact | ||
fields: | ||
LastName: | ||
fake: LastName | ||
EmailBouncedDate: | ||
fake: DateTime | ||
|
||
- object: Contact | ||
fields: | ||
LastName: | ||
fake: LastName | ||
EmailBouncedDate: | ||
fake: FutureDatetime | ||
|
||
- object: Contact | ||
fields: | ||
LastName: | ||
fake: LastName | ||
EmailBouncedDate: | ||
fake: iso8601 | ||
|
||
- object: Contact | ||
fields: | ||
LastName: | ||
fake: LastName | ||
EmailBouncedDate: ${{fake.iso8601(timezone=False)}}Z |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,9 @@ | ||
from io import StringIO | ||
from unittest import mock | ||
from datetime import date | ||
from datetime import date, datetime, timezone | ||
|
||
import pytest | ||
|
||
from dateutil import parser as dateparser | ||
from snowfakery.data_generator import generate | ||
from snowfakery import data_gen_exceptions as exc | ||
|
||
|
@@ -123,6 +123,65 @@ def test_months_past(self, write_row_mock): | |
assert (date.today() - the_date).days > 80 | ||
assert (date.today() - the_date).days < 130 | ||
|
||
def test_date_times(self, generated_rows): | ||
with open("tests/test_datetimes.yml") as yaml: | ||
generate(yaml) | ||
|
||
for dt in generated_rows.table_values("Contact", field="EmailBouncedDate"): | ||
assert "+0" in dt or dt.endswith("Z"), dt | ||
assert dateparser.parse(dt).tzinfo | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What about using There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
|
||
def test_hidden_fakers(self): | ||
yaml = """ | ||
- object: A | ||
fields: | ||
date: | ||
fake: DateTimeThisCentury | ||
""" | ||
with pytest.raises(exc.DataGenError) as e: | ||
generate(StringIO(yaml)) | ||
|
||
assert e | ||
|
||
def test_bad_tz_param(self): | ||
yaml = """ | ||
- object: A | ||
fields: | ||
date: | ||
fake.datetime: | ||
timezone: PST | ||
""" | ||
with pytest.raises(exc.DataGenError) as e: | ||
generate(StringIO(yaml)) | ||
|
||
assert "timezone" in str(e.value) | ||
assert "relativedelta" in str(e.value) | ||
|
||
def test_no_timezone(self, generated_rows): | ||
yaml = """ | ||
- object: A | ||
fields: | ||
date: | ||
fake.datetime: | ||
timezone: False | ||
""" | ||
generate(StringIO(yaml)) | ||
date = generated_rows.table_values("A", 0, "date") | ||
assert dateparser.parse(date).tzinfo is None | ||
|
||
def test_relative_dates(self, generated_rows): | ||
with open("tests/test_relative_dates.yml") as f: | ||
generate(f) | ||
now = datetime.now(timezone.utc) | ||
# there is a miniscule chance that FutureDateTime picks a DateTime 1 second in the future | ||
# and then by the time we get here it isn't the future anymore. We'll see if it ever | ||
# happens in practice | ||
assert dateparser.parse(generated_rows.table_values("Test", 1, "future")) >= now | ||
assert ( | ||
dateparser.parse(generated_rows.table_values("Test", 1, "future2")) >= now | ||
) | ||
assert dateparser.parse(generated_rows.table_values("Test", 1, "past")) <= now | ||
|
||
@mock.patch(write_row_path) | ||
def test_snowfakery_names(self, write_row_mock): | ||
yaml = """ | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
- object: Test | ||
fields: | ||
future: | ||
fake.date_time_between: | ||
start_date: +1m | ||
end_date: +1h | ||
|
||
past: | ||
fake.date_time_between: | ||
start_date: -1h | ||
end_date: now | ||
|
||
future2: | ||
fake: FutureDateTime |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can use
typing.get_args()
here instead:There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't do it exactly that way but: b622e7c
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@prescod Did you mean to replace this with
ScalarTypes
?