Skip to content

Instantly share code, notes, and snippets.

@mverleg
Created September 18, 2017 19:29
Show Gist options
  • Save mverleg/087111f0b03d99b7c85f5072f0392acc to your computer and use it in GitHub Desktop.
Save mverleg/087111f0b03d99b7c85f5072f0392acc to your computer and use it in GitHub Desktop.
Patch for pyjson_tricks struct_time (doesn't work because structs can have encoders)
Index: tests/test_tz.py
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- tests/test_tz.py (revision 55132d48ee28d59420d153088fad9a0db5648ae3)
+++ tests/test_tz.py (revision )
@@ -7,6 +7,7 @@
"""
from datetime import datetime, date, time, timedelta
+from time import struct_time, localtime
from json_tricks import dumps, loads
from json_tricks.nonp import is_py3
import pytz
@@ -52,3 +53,14 @@
assert dumps(dt, primitives=True).strip('"') == '1988-03-15T08:03:59.000007+00:20'
+def test_struct_time():
+ datemin, datemax = date(year=1, month=1, day=1).timetuple(), date(year=+5000, month=12, day=31).timetuple()
+ for tmstrct in [localtime(),
+ struct_time((1, 1, 1, 0, 0, 0, datemin.tm_wday, datemin.tm_yday, 0)),
+ struct_time((+5000, 12, 31, 23, 59, 59, datemin.tm_yday, datemin.tm_yday, 1))]:
+ json = dumps(tmstrct)
+ back = loads(json)
+ print("JSON: " + json) # todo
+ assert tmstrct == back
+
+
Index: json_tricks/encoders.py
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- json_tricks/encoders.py (revision 55132d48ee28d59420d153088fad9a0db5648ae3)
+++ json_tricks/encoders.py (revision )
@@ -5,6 +5,8 @@
from json import JSONEncoder
from sys import version
from decimal import Decimal
+from time import struct_time
+
from .utils import hashodict, call_with_optional_kwargs, NoPandasException, NoNumpyException
@@ -87,10 +89,22 @@
else:
dct = hashodict([('__timedelta__', None), ('days', obj.days), ('seconds', obj.seconds),
('microseconds', obj.microseconds)])
+ elif isinstance(obj, struct_time):
+ if obj.tm_year <= 0:
+ warning("struct_time year is out of range for '{}'; weekday and day of year information will be lost when decoding".format(obj))
+ else:
+ date_tuple = date(year=obj.tm_year, month=obj.tm_mon, day=obj.tm_mday).timetuple()
+ if obj.tm_wday != date_tuple.tm_wday:
+ warning("struct_time year has an invalid weekday for '{}'; weekday information will be lost when decoding".format(obj))
+ if obj.tm_yday != date_tuple.tm_yday:
+ warning("struct_time year has an invalid day of year for '{}'; day of year information will be lost when decoding".format(obj))
+ dct = hashodict([('__struct_time_iso__', None), ('year', obj.tm_year), ('month', obj.tm_mon),
+ ('day', obj.tm_mday), ('hour', obj.tm_hour), ('minute', obj.tm_min),
+ ('second', obj.tm_sec), ('isdst', obj.tm_isdst)])
else:
return obj
for key, val in tuple(dct.items()):
- if not key.startswith('__') and not val:
+ if not key.startswith('__') and not key == 'isdst' and not val:
del dct[key]
return dct
@@ -100,6 +114,7 @@
Encodes a class instance to json. Note that it can only be recovered if the environment allows the class to be
imported in the same way.
"""
+ # if (isinstance(obj, list) or (isinstance(obj, dict)) and not hasattr(obj, '__dict__')):
if isinstance(obj, list) or isinstance(obj, dict):
return obj
if hasattr(obj, '__class__') and (hasattr(obj, '__dict__') or hasattr(obj, '__slots__')):
@@ -163,7 +178,7 @@
def numeric_types_encode(obj, primitives=False):
"""
Encode Decimal and Fraction.
-
+
:param primitives: Encode decimals and fractions as standard floats. You may lose precision. If you do this, you may need to enable `allow_nan` (decimals always allow NaNs but floats do not).
"""
if isinstance(obj, Decimal):
@@ -260,11 +275,11 @@
def numpy_encode(obj, primitives=False):
"""
Encodes numpy `ndarray`s as lists with meta data.
-
+
Encodes numpy scalar types as Python equivalents. Special encoding is not possible,
because int64 (in py2) and float64 (in py2 and py3) are subclasses of primitives,
which never reach the encoder.
-
+
:param primitives: If True, arrays are serialized as (nested) lists without meta info.
"""
from numpy import ndarray, generic
@@ -293,7 +308,7 @@
JSON encoder for numpy arrays.
"""
SHOW_SCALAR_WARNING = True # show a warning that numpy scalar serialization is experimental
-
+
def default(self, obj, *args, **kwargs):
"""
If input object is a ndarray it will be converted into a dict holding
Index: json_tricks/decoders.py
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- json_tricks/decoders.py (revision 55132d48ee28d59420d153088fad9a0db5648ae3)
+++ json_tricks/decoders.py (revision )
@@ -5,6 +5,8 @@
from collections import OrderedDict
from decimal import Decimal
from logging import warning
+from time import struct_time
+
from json_tricks import NoPandasException, NoNumpyException
@@ -77,6 +79,11 @@
elif '__timedelta__' in dct:
return timedelta(days=dct.get('days', 0), seconds=dct.get('seconds', 0),
microseconds=dct.get('microseconds', 0))
+ elif '__struct_time_iso__' in dct:
+ date_tuple = date(year=dct.get('year', 0), month=dct.get('month', 0), day=dct.get('day', 0)).timetuple()
+ return struct_time(dct.get('year', 0), dct.get('month', 0), dct.get('day', 0),
+ dct.get('hour', 0), dct.get('minute', 0), dct.get('second', 0), date_tuple.tm_wday,
+ date_tuple.tm_yday, dct.get('isdst', 0))
return dct
@@ -158,7 +165,8 @@
for slot,value in dct['slots'].items():
setattr(obj, slot, value)
if 'attributes' in dct:
- obj.__dict__ = dict(dct['attributes'])
+ obj.__dict__.clear()
+ obj.__dict__.update(dct['attributes'])
return obj
return dct
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment