22from nose import with_setup
33from nose .plugins .attrib import attr
44
5+ from unittest import TestCase
6+
7+ import math
8+ import pytz
59from datetime import datetime as dt
610import datetime
711import numpy as np
1620from plotly .matplotlylib import Exporter , PlotlyRenderer
1721from plotly .plotly import plot
1822
23+
24+ class TestJSONEncoder (TestCase ):
25+
26+ def test_encode_as_plotly (self ):
27+
28+ # should *fail* when object doesn't have `to_plotly_json` attribute
29+ objs_without_attr = [
30+ 1 , 'one' , {'a' , 'set' }, {'a' : 'dict' }, ['a' , 'list' ]
31+ ]
32+ for obj in objs_without_attr :
33+ self .assertRaises (utils .NotEncodable ,
34+ utils .PlotlyJSONEncoder .encode_as_plotly , obj )
35+
36+ # should return without exception when obj has `to_plotly_josn` attr
37+ expected_res = 'wedidit'
38+
39+ class ObjWithAttr (object ):
40+
41+ def to_plotly_json (self ):
42+ return expected_res
43+
44+ res = utils .PlotlyJSONEncoder .encode_as_plotly (ObjWithAttr ())
45+ self .assertEqual (res , expected_res )
46+
47+ def test_encode_as_list (self ):
48+
49+ # should *fail* when object doesn't have `tolist` method
50+ objs_without_attr = [
51+ 1 , 'one' , {'a' , 'set' }, {'a' : 'dict' }, ['a' , 'list' ]
52+ ]
53+ for obj in objs_without_attr :
54+ self .assertRaises (utils .NotEncodable ,
55+ utils .PlotlyJSONEncoder .encode_as_list , obj )
56+
57+ # should return without exception when obj has `tolist` attr
58+ expected_res = ['some' , 'list' ]
59+
60+ class ObjWithAttr (object ):
61+
62+ def tolist (self ):
63+ return expected_res
64+
65+ res = utils .PlotlyJSONEncoder .encode_as_list (ObjWithAttr ())
66+ self .assertEqual (res , expected_res )
67+
68+ def test_encode_as_pandas (self ):
69+
70+ # should *fail* on things that are not specific pandas objects
71+ not_pandas = ['giraffe' , 6 , float ('nan' ), ['a' , 'list' ]]
72+ for obj in not_pandas :
73+ self .assertRaises (utils .NotEncodable ,
74+ utils .PlotlyJSONEncoder .encode_as_pandas , obj )
75+
76+ # should succeed when we've got specific pandas thingies
77+ res = utils .PlotlyJSONEncoder .encode_as_pandas (pd .NaT )
78+ self .assertIs (res , None )
79+
80+ def test_encode_as_numpy (self ):
81+
82+ # should *fail* on non-numpy-y things
83+ not_numpy = ['hippo' , 8 , float ('nan' ), {'a' : 'dict' }]
84+ for obj in not_numpy :
85+ self .assertRaises (utils .NotEncodable ,
86+ utils .PlotlyJSONEncoder .encode_as_numpy , obj )
87+
88+ # should succeed with numpy-y-thingies
89+ res = utils .PlotlyJSONEncoder .encode_as_numpy (np .ma .core .masked )
90+ self .assertTrue (math .isnan (res ))
91+
92+ def test_encode_as_datetime (self ):
93+
94+ # should *fail* without 'utcoffset' and 'isoformat' and '__sub__' attrs
95+ non_datetimes = [datetime .date (2013 , 10 , 1 ), 'noon' , 56 , '00:00:00' ]
96+ for obj in non_datetimes :
97+ self .assertRaises (utils .NotEncodable ,
98+ utils .PlotlyJSONEncoder .encode_as_datetime , obj )
99+
100+ # should succeed with 'utcoffset', 'isoformat' and '__sub__' attrs
101+ res = utils .PlotlyJSONEncoder .encode_as_datetime (
102+ datetime .datetime (2013 , 10 , 1 )
103+ )
104+ self .assertEqual (res , '2013-10-01' )
105+
106+ # should not include extraneous microsecond info if DNE
107+ res = utils .PlotlyJSONEncoder .encode_as_datetime (
108+ datetime .datetime (2013 , 10 , 1 , microsecond = 0 )
109+ )
110+ self .assertEqual (res , '2013-10-01' )
111+
112+ # should include microsecond info if present
113+ res = utils .PlotlyJSONEncoder .encode_as_datetime (
114+ datetime .datetime (2013 , 10 , 1 , microsecond = 10 )
115+ )
116+ self .assertEqual (res , '2013-10-01 00:00:00.000010' )
117+
118+ # should convert tzinfo to utc. Note that in october, we're in EDT!
119+ # therefore the 4 hour difference is correct.
120+ naive_datetime = datetime .datetime (2013 , 10 , 1 )
121+ aware_datetime = pytz .timezone ('US/Eastern' ).localize (naive_datetime )
122+
123+ res = utils .PlotlyJSONEncoder .encode_as_datetime (aware_datetime )
124+ self .assertEqual (res , '2013-10-01 04:00:00' )
125+
126+ def test_encode_as_date (self ):
127+
128+ # should *fail* without 'utcoffset' and 'isoformat' and '__sub__' attrs
129+ non_datetimes = ['noon' , 56 , '00:00:00' ]
130+ for obj in non_datetimes :
131+ self .assertRaises (utils .NotEncodable ,
132+ utils .PlotlyJSONEncoder .encode_as_date , obj )
133+
134+ # should work with a date
135+ a_date = datetime .date (2013 , 10 , 01 )
136+ res = utils .PlotlyJSONEncoder .encode_as_date (a_date )
137+ self .assertEqual (res , '2013-10-01' )
138+
139+ # should also work with a date time without a utc offset!
140+ # TODO: is this OK? We could raise errors after checking isinstance...
141+ res = utils .PlotlyJSONEncoder .encode_as_date (
142+ datetime .datetime (2013 , 10 , 1 , microsecond = 10 )
143+ )
144+ self .assertEqual (res , '2013-10-01 00:00:00.000010' )
145+
146+
19147## JSON encoding
20148numeric_list = [1 , 2 , 3 ]
21149np_list = np .array ([1 , 2 , 3 , np .NaN , np .NAN , np .Inf , dt (2014 , 1 , 5 )])
@@ -38,7 +166,7 @@ def test_column_json_encoding():
38166 Column (np_list , 'col 3' )
39167 ]
40168 json_columns = json .dumps (
41- columns , cls = utils ._plotlyJSONEncoder , sort_keys = True
169+ columns , cls = utils .PlotlyJSONEncoder , sort_keys = True
42170 )
43171 assert ('[{"data": [1, 2, 3], "name": "col 1"}, '
44172 '{"data": [1, "A", "2014-01-05", '
@@ -56,8 +184,8 @@ def test_figure_json_encoding():
56184 data = Data ([s1 , s2 ])
57185 figure = Figure (data = data )
58186
59- js1 = json .dumps (s1 , cls = utils ._plotlyJSONEncoder , sort_keys = True )
60- js2 = json .dumps (s2 , cls = utils ._plotlyJSONEncoder , sort_keys = True )
187+ js1 = json .dumps (s1 , cls = utils .PlotlyJSONEncoder , sort_keys = True )
188+ js2 = json .dumps (s2 , cls = utils .PlotlyJSONEncoder , sort_keys = True )
61189
62190 assert (js1 == '{"type": "scatter3d", "x": [1, 2, 3], '
63191 '"y": [1, 2, 3, NaN, NaN, Infinity, "2014-01-05"], '
@@ -66,8 +194,8 @@ def test_figure_json_encoding():
66194 assert (js2 == '{"type": "scatter", "x": [1, 2, 3]}' )
67195
68196 # Test JSON encoding works
69- json .dumps (data , cls = utils ._plotlyJSONEncoder , sort_keys = True )
70- json .dumps (figure , cls = utils ._plotlyJSONEncoder , sort_keys = True )
197+ json .dumps (data , cls = utils .PlotlyJSONEncoder , sort_keys = True )
198+ json .dumps (figure , cls = utils .PlotlyJSONEncoder , sort_keys = True )
71199
72200 # Test data wasn't mutated
73201 assert (bool (np .asarray (np_list ==
@@ -79,47 +207,48 @@ def test_figure_json_encoding():
79207
80208
81209def test_datetime_json_encoding ():
82- j1 = json .dumps (dt_list , cls = utils ._plotlyJSONEncoder )
210+ j1 = json .dumps (dt_list , cls = utils .PlotlyJSONEncoder )
83211 assert (j1 == '["2014-01-05", '
84212 '"2014-01-05 01:01:01", '
85213 '"2014-01-05 01:01:01.000001"]' )
86- j2 = json .dumps ({"x" : dt_list }, cls = utils ._plotlyJSONEncoder )
214+ j2 = json .dumps ({"x" : dt_list }, cls = utils .PlotlyJSONEncoder )
87215 assert (j2 == '{"x": ["2014-01-05", '
88216 '"2014-01-05 01:01:01", '
89217 '"2014-01-05 01:01:01.000001"]}' )
90218
91219
92220def test_pandas_json_encoding ():
93- j1 = json .dumps (df ['col 1' ], cls = utils ._plotlyJSONEncoder )
221+ j1 = json .dumps (df ['col 1' ], cls = utils .PlotlyJSONEncoder )
94222 assert (j1 == '[1, 2, 3, "2014-01-05", null, NaN, Infinity]' )
95223
96224 # Test that data wasn't mutated
97225 assert_series_equal (df ['col 1' ],
98226 pd .Series ([1 , 2 , 3 , dt (2014 , 1 , 5 ),
99227 pd .NaT , np .NaN , np .Inf ]))
100228
101- j2 = json .dumps (df .index , cls = utils ._plotlyJSONEncoder )
229+ j2 = json .dumps (df .index , cls = utils .PlotlyJSONEncoder )
102230 assert (j2 == '[0, 1, 2, 3, 4, 5, 6]' )
103231
104232 nat = [pd .NaT ]
105- j3 = json .dumps (nat , cls = utils ._plotlyJSONEncoder )
233+ j3 = json .dumps (nat , cls = utils .PlotlyJSONEncoder )
106234 assert (j3 == '[null]' )
107235 assert (nat [0 ] is pd .NaT )
108236
109- j4 = json .dumps (rng , cls = utils ._plotlyJSONEncoder )
237+ j4 = json .dumps (rng , cls = utils .PlotlyJSONEncoder )
110238 assert (j4 == '["2011-01-01", "2011-01-01 01:00:00"]' )
111239
112- j5 = json .dumps (ts , cls = utils ._plotlyJSONEncoder )
240+ j5 = json .dumps (ts , cls = utils .PlotlyJSONEncoder )
113241 assert (j5 == '[1.5, 2.5]' )
114242 assert_series_equal (ts , pd .Series ([1.5 , 2.5 ], index = rng ))
115243
116- j6 = json .dumps (ts .index , cls = utils ._plotlyJSONEncoder )
244+ j6 = json .dumps (ts .index , cls = utils .PlotlyJSONEncoder )
117245 assert (j6 == '["2011-01-01", "2011-01-01 01:00:00"]' )
118246
119247
120248def test_numpy_masked_json_encoding ():
121249 l = [1 , 2 , np .ma .core .masked ]
122- j1 = json .dumps (l , cls = utils ._plotlyJSONEncoder )
250+ j1 = json .dumps (l , cls = utils .PlotlyJSONEncoder )
251+ print j1
123252 assert (j1 == '[1, 2, NaN]' )
124253 assert (set (l ) == set ([1 , 2 , np .ma .core .masked ]))
125254
@@ -142,23 +271,23 @@ def test_masked_constants_example():
142271 renderer = PlotlyRenderer ()
143272 Exporter (renderer ).run (fig )
144273
145- json .dumps (renderer .plotly_fig , cls = utils ._plotlyJSONEncoder )
274+ json .dumps (renderer .plotly_fig , cls = utils .PlotlyJSONEncoder )
146275
147276 jy = json .dumps (renderer .plotly_fig ['data' ][1 ]['y' ],
148- cls = utils ._plotlyJSONEncoder )
277+ cls = utils .PlotlyJSONEncoder )
149278 assert (jy == '[-398.11793026999999, -398.11792966000002, '
150279 '-398.11786308000001, NaN]' )
151280
152281
153282def test_numpy_dates ():
154283 a = np .arange (np .datetime64 ('2011-07-11' ), np .datetime64 ('2011-07-18' ))
155- j1 = json .dumps (a , cls = utils ._plotlyJSONEncoder )
284+ j1 = json .dumps (a , cls = utils .PlotlyJSONEncoder )
156285 assert (j1 == '["2011-07-11", "2011-07-12", "2011-07-13", '
157286 '"2011-07-14", "2011-07-15", "2011-07-16", '
158287 '"2011-07-17"]' )
159288
160289
161290def test_datetime_dot_date ():
162291 a = [datetime .date (2014 , 1 , 1 ), datetime .date (2014 , 1 , 2 )]
163- j1 = json .dumps (a , cls = utils ._plotlyJSONEncoder )
292+ j1 = json .dumps (a , cls = utils .PlotlyJSONEncoder )
164293 assert (j1 == '["2014-01-01", "2014-01-02"]' )
0 commit comments