use pytz instead of our own version
MODIFY
appveyor.yml
appveyor.yml
@@ -26,6 +26,7 @@ test_script:
- "set PYTHONPATH=%cd%"
- "set FASTAVRO_USE_CYTHON=1"
- "%PYTHON%\\python.exe setup.py build_ext --inplace"
+ - "%PYTHON%\\python.exe -m pip install -e ."
- "%PYTHON%\\python.exe -m pytest --cov=fastavro --cov-report=term-missing -v tests"
- "%PYTHON%\\Scripts\\codecov.exe"

MODIFY
benchmark/benchmark.py
benchmark/benchmark.py
@@ -3,7 +3,7 @@ import datetime
import time
from fastavro import writer, reader, schemaless_writer, schemaless_reader, parse_schema
-from fastavro._timezone import utc
+from pytz import utc
from fastavro.validation import validate, validate_many

MODIFY
developer_requirements.txt
developer_requirements.txt
@@ -3,7 +3,8 @@ pytest
flake8
check-manifest
Cython
-numpy
+numpy # used in tests
+pandas; platform_python_implementation!='PyPy' # used in tests; not install on pypy as it takes forver
wheel
twine
coverage

MODIFY
fastavro/_timezone.py
fastavro/_timezone.py
-"""Timezone class for dealing with timezone-aware datetime objects
-Inspired by https://github.com/apache/avro/pull/207"""
from datetime import datetime
-from datetime import timedelta
-from datetime import tzinfo
+from pytz import utc
-class UTCTzinfo(tzinfo):
- """Implementation of abstract base class tzinfo,
- python >= 3.2 can use datetime.timezone.utc instead"""
- def utcoffset(self, dt):
- return timedelta(0)
-
- def tzname(self, dt):
- return "UTC"
-
- def dst(self, dt):
- return timedelta(0)
-
-
-utc = UTCTzinfo()
-
# used to compute timestamp for tz-aware datetime objects
# python >= 3.3 can use datetime.datetime.timestamp() instead
epoch = datetime(1970, 1, 1, tzinfo=utc)

MODIFY
run-tests.sh
run-tests.sh
@@ -17,5 +17,6 @@ check-manifest
# Build Cython modules
FASTAVRO_USE_CYTHON=1 python setup.py build_ext --inplace
+pip install -e .
PYTHONPATH=${PWD} python -m pytest --cov=fastavro -v --cov-report=term-missing --cov-report=html:build/htmlcov $@ tests

MODIFY
setup.py
setup.py
@@ -92,6 +92,7 @@ setup(
'Topic :: Software Development :: Libraries',
'Topic :: Scientific/Engineering :: Information Analysis',
],
+ install_requires=["pytz"],
extras_require={
'codecs': ['python-snappy', 'zstandard', 'lz4'],
'snappy': ['python-snappy'],

MODIFY
tests/conftest.py
tests/conftest.py
@@ -3,7 +3,7 @@ import pytest
import time
from fastavro._schema_common import SCHEMA_DEFS
-from fastavro._timezone import utc
+from pytz import utc
@pytest.fixture(scope="function", autouse=True)

MODIFY
tests/test_logical_types.py
tests/test_logical_types.py
@@ -414,3 +414,35 @@ def test_date_as_string():
binary = serialize(schema, data1)
data2 = deserialize(schema, binary)
assert (datetime.date(2019, 5, 6) == data2)
+
+
+@pytest.mark.skipif(
+ hasattr(sys, 'pypy_version_info'),
+ reason='pandas takes forever to install on pypy'
+)
+def test_pandas_datetime():
+ """https://github.com/gojek/feast/pull/490#issuecomment-590623525"""
+
+ # Import here as pandas is not installed on pypy for testing
+ import pandas as pd
+ import pytz
+
+ schema = {
+ "fields": [
+ {
+ "name": "timestamp-micros",
+ "type": [
+ "null", {'type': 'long', 'logicalType': 'timestamp-micros'}
+ ]
+ }
+ ],
+ "name": "test_pandas_datetime",
+ "type": "record",
+ }
+
+ data1 = {
+ "timestamp-micros": pd.to_datetime(
+ datetime.datetime.utcnow().replace(tzinfo=pytz.utc)
+ )
+ }
+ assert serialize(schema, data1)

MODIFY
tests/test_timezone.py
tests/test_timezone.py
@@ -3,11 +3,11 @@ from io import BytesIO
import fastavro
from fastavro.const import MCS_PER_SECOND, MLS_PER_SECOND
-from fastavro import _timezone as tz
from fastavro._logical_writers_py import prepare_timestamp_micros
from fastavro._logical_writers_py import prepare_timestamp_millis
import pytest
from .conftest import assert_naive_datetime_equal_to_tz_datetime
+from pytz import utc
schema = {
@@ -73,16 +73,13 @@ def timestamp_mls_from_timestamp(timestamp):
def test_tz_attributes():
- assert tz.utc.tzname(None) == 'UTC'
- assert tz.utc.utcoffset(None) == datetime.timedelta(0)
- assert tz.utc.dst(None) == datetime.timedelta(0)
assert tst.tzname(None) == 'TST'
- assert tst.utcoffset(None) != tz.utc.utcoffset(None)
+ assert tst.utcoffset(None) != utc.utcoffset(None)
@pytest.fixture(scope='session')
def timestamp_data():
- timestamp = datetime.datetime.now(tz=tz.utc)
+ timestamp = datetime.datetime.now(tz=utc)
return {
'timestamp-millis': timestamp_mls_from_timestamp(timestamp),
'timestamp-micros': timestamp,
@@ -154,7 +151,7 @@ def test_timestamp_millis_naive_input(timestamp_data_naive, read_data_naive):
def test_prepare_timestamp_micros():
# seconds from epoch == 1234567890
- reference_time = datetime.datetime(2009, 2, 13, 23, 31, 30, tzinfo=tz.utc)
+ reference_time = datetime.datetime(2009, 2, 13, 23, 31, 30, tzinfo=utc)
mcs_from_epoch = 1234567890 * MCS_PER_SECOND
assert prepare_timestamp_micros(reference_time, schema) == mcs_from_epoch
timestamp_tst = reference_time.astimezone(tst)
@@ -166,7 +163,7 @@ def test_prepare_timestamp_micros():
def test_prepare_timestamp_millis():
# seconds from epoch == 1234567890
- reference_time = datetime.datetime(2009, 2, 13, 23, 31, 30, tzinfo=tz.utc)
+ reference_time = datetime.datetime(2009, 2, 13, 23, 31, 30, tzinfo=utc)
mcs_from_epoch = 1234567890 * MLS_PER_SECOND
assert prepare_timestamp_millis(reference_time, schema) == mcs_from_epoch
timestamp_tst = reference_time.astimezone(tst)

use pytz instead of our own version (#396)