11#!/usr/bin/env python
22
3+ import warnings
4+ import operator
35from itertools import product
46from distutils .version import LooseVersion
57
2830from pandas .util .testing import (assert_frame_equal , randbool ,
2931 assertRaisesRegexp ,
3032 assert_produces_warning , assert_series_equal )
31- from pandas .compat import PY3 , u
33+ from pandas .compat import PY3 , u , reduce
3234
3335_series_frame_incompatible = _bool_ops_syms
3436_scalar_skip = 'in' , 'not in'
@@ -699,6 +701,16 @@ def check_chained_cmp_op(self, lhs, cmp1, mid, cmp2, rhs):
699701#-------------------------------------
700702# basic and complex alignment
701703
704+ def _is_datetime (x ):
705+ return issubclass (x .dtype .type , np .datetime64 )
706+
707+
708+ def should_warn (* args ):
709+ not_mono = not any (map (operator .attrgetter ('is_monotonic' ), args ))
710+ only_one_dt = reduce (operator .xor , map (_is_datetime , args ))
711+ return not_mono and only_one_dt
712+
713+
702714class TestAlignment (object ):
703715
704716 index_types = 'i' , 'u' , 'dt'
@@ -719,13 +731,20 @@ def check_basic_frame_alignment(self, engine, parser):
719731 tm .skip_if_no_ne (engine )
720732 args = product (self .lhs_index_types , self .index_types ,
721733 self .index_types )
722- for lr_idx_type , rr_idx_type , c_idx_type in args :
723- df = mkdf (10 , 10 , data_gen_f = f , r_idx_type = lr_idx_type ,
724- c_idx_type = c_idx_type )
725- df2 = mkdf (20 , 10 , data_gen_f = f , r_idx_type = rr_idx_type ,
726- c_idx_type = c_idx_type )
727- res = pd .eval ('df + df2' , engine = engine , parser = parser )
728- assert_frame_equal (res , df + df2 )
734+ with warnings .catch_warnings (record = True ):
735+ warnings .simplefilter ('always' , RuntimeWarning )
736+ for lr_idx_type , rr_idx_type , c_idx_type in args :
737+ df = mkdf (10 , 10 , data_gen_f = f , r_idx_type = lr_idx_type ,
738+ c_idx_type = c_idx_type )
739+ df2 = mkdf (20 , 10 , data_gen_f = f , r_idx_type = rr_idx_type ,
740+ c_idx_type = c_idx_type )
741+ # only warns if not monotonic and not sortable
742+ if should_warn (df .index , df2 .index ):
743+ with tm .assert_produces_warning (RuntimeWarning ):
744+ res = pd .eval ('df + df2' , engine = engine , parser = parser )
745+ else :
746+ res = pd .eval ('df + df2' , engine = engine , parser = parser )
747+ assert_frame_equal (res , df + df2 )
729748
730749 def test_basic_frame_alignment (self ):
731750 for engine , parser in ENGINES_PARSERS :
@@ -754,12 +773,20 @@ def check_medium_complex_frame_alignment(self, engine, parser):
754773 args = product (self .lhs_index_types , self .index_types ,
755774 self .index_types , self .index_types )
756775
757- for r1 , c1 , r2 , c2 in args :
758- df = mkdf (3 , 2 , data_gen_f = f , r_idx_type = r1 , c_idx_type = c1 )
759- df2 = mkdf (4 , 2 , data_gen_f = f , r_idx_type = r2 , c_idx_type = c2 )
760- df3 = mkdf (5 , 2 , data_gen_f = f , r_idx_type = r2 , c_idx_type = c2 )
761- res = pd .eval ('df + df2 + df3' , engine = engine , parser = parser )
762- assert_frame_equal (res , df + df2 + df3 )
776+ with warnings .catch_warnings (record = True ):
777+ warnings .simplefilter ('always' , RuntimeWarning )
778+
779+ for r1 , c1 , r2 , c2 in args :
780+ df = mkdf (3 , 2 , data_gen_f = f , r_idx_type = r1 , c_idx_type = c1 )
781+ df2 = mkdf (4 , 2 , data_gen_f = f , r_idx_type = r2 , c_idx_type = c2 )
782+ df3 = mkdf (5 , 2 , data_gen_f = f , r_idx_type = r2 , c_idx_type = c2 )
783+ if should_warn (df .index , df2 .index , df3 .index ):
784+ with tm .assert_produces_warning (RuntimeWarning ):
785+ res = pd .eval ('df + df2 + df3' , engine = engine ,
786+ parser = parser )
787+ else :
788+ res = pd .eval ('df + df2 + df3' , engine = engine , parser = parser )
789+ assert_frame_equal (res , df + df2 + df3 )
763790
764791 @slow
765792 def test_medium_complex_frame_alignment (self ):
@@ -775,20 +802,24 @@ def testit(r_idx_type, c_idx_type, index_name):
775802 index = getattr (df , index_name )
776803 s = Series (np .random .randn (5 ), index [:5 ])
777804
778- res = pd .eval ('df + s' , engine = engine , parser = parser )
805+ if should_warn (df .index , s .index ):
806+ with tm .assert_produces_warning (RuntimeWarning ):
807+ res = pd .eval ('df + s' , engine = engine , parser = parser )
808+ else :
809+ res = pd .eval ('df + s' , engine = engine , parser = parser )
810+
779811 if r_idx_type == 'dt' or c_idx_type == 'dt' :
780- if engine == 'numexpr' :
781- expected = df .add (s )
782- else :
783- expected = df + s
812+ expected = df .add (s ) if engine == 'numexpr' else df + s
784813 else :
785814 expected = df + s
786815 assert_frame_equal (res , expected )
787816
788817 args = product (self .lhs_index_types , self .index_types ,
789818 ('index' , 'columns' ))
790- for r_idx_type , c_idx_type , index_name in args :
791- testit (r_idx_type , c_idx_type , index_name )
819+ with warnings .catch_warnings (record = True ):
820+ warnings .simplefilter ('always' , RuntimeWarning )
821+ for r_idx_type , c_idx_type , index_name in args :
822+ testit (r_idx_type , c_idx_type , index_name )
792823
793824 def test_basic_frame_series_alignment (self ):
794825 for engine , parser in ENGINES_PARSERS :
@@ -802,13 +833,14 @@ def testit(r_idx_type, c_idx_type, index_name):
802833 c_idx_type = c_idx_type )
803834 index = getattr (df , index_name )
804835 s = Series (np .random .randn (5 ), index [:5 ])
836+ if should_warn (s .index , df .index ):
837+ with tm .assert_produces_warning (RuntimeWarning ):
838+ res = pd .eval ('s + df' , engine = engine , parser = parser )
839+ else :
840+ res = pd .eval ('s + df' , engine = engine , parser = parser )
805841
806- res = pd .eval ('s + df' , engine = engine , parser = parser )
807842 if r_idx_type == 'dt' or c_idx_type == 'dt' :
808- if engine == 'numexpr' :
809- expected = df .add (s )
810- else :
811- expected = s + df
843+ expected = df .add (s ) if engine == 'numexpr' else s + df
812844 else :
813845 expected = s + df
814846 assert_frame_equal (res , expected )
@@ -820,8 +852,10 @@ def testit(r_idx_type, c_idx_type, index_name):
820852
821853 # dt with dt
822854 args = product (['dt' ], ['dt' ], ('index' , 'columns' ))
823- for r_idx_type , c_idx_type , index_name in args :
824- testit (r_idx_type , c_idx_type , index_name )
855+ with warnings .catch_warnings (record = True ):
856+ warnings .simplefilter ('always' , RuntimeWarning )
857+ for r_idx_type , c_idx_type , index_name in args :
858+ testit (r_idx_type , c_idx_type , index_name )
825859
826860 def test_basic_series_frame_alignment (self ):
827861 for engine , parser in ENGINES_PARSERS :
@@ -831,20 +865,29 @@ def check_series_frame_commutativity(self, engine, parser):
831865 tm .skip_if_no_ne (engine )
832866 args = product (self .lhs_index_types , self .index_types , ('+' , '*' ),
833867 ('index' , 'columns' ))
834- for r_idx_type , c_idx_type , op , index_name in args :
835- df = mkdf (10 , 10 , data_gen_f = f , r_idx_type = r_idx_type ,
836- c_idx_type = c_idx_type )
837- index = getattr (df , index_name )
838- s = Series (np .random .randn (5 ), index [:5 ])
839868
840- lhs = 's {0} df' .format (op )
841- rhs = 'df {0} s' .format (op )
842- a = pd .eval (lhs , engine = engine , parser = parser )
843- b = pd .eval (rhs , engine = engine , parser = parser )
869+ with warnings .catch_warnings (record = True ):
870+ warnings .simplefilter ('always' , RuntimeWarning )
871+ for r_idx_type , c_idx_type , op , index_name in args :
872+ df = mkdf (10 , 10 , data_gen_f = f , r_idx_type = r_idx_type ,
873+ c_idx_type = c_idx_type )
874+ index = getattr (df , index_name )
875+ s = Series (np .random .randn (5 ), index [:5 ])
876+
877+ lhs = 's {0} df' .format (op )
878+ rhs = 'df {0} s' .format (op )
879+ if should_warn (df .index , s .index ):
880+ with tm .assert_produces_warning (RuntimeWarning ):
881+ a = pd .eval (lhs , engine = engine , parser = parser )
882+ with tm .assert_produces_warning (RuntimeWarning ):
883+ b = pd .eval (rhs , engine = engine , parser = parser )
884+ else :
885+ a = pd .eval (lhs , engine = engine , parser = parser )
886+ b = pd .eval (rhs , engine = engine , parser = parser )
844887
845- if r_idx_type != 'dt' and c_idx_type != 'dt' :
846- if engine == 'numexpr' :
847- assert_frame_equal (a , b )
888+ if r_idx_type != 'dt' and c_idx_type != 'dt' :
889+ if engine == 'numexpr' :
890+ assert_frame_equal (a , b )
848891
849892 def test_series_frame_commutativity (self ):
850893 for engine , parser in ENGINES_PARSERS :
@@ -860,34 +903,41 @@ def check_complex_series_frame_alignment(self, engine, parser):
860903 m1 = 5
861904 m2 = 2 * m1
862905
863- for r1 , r2 , c1 , c2 in args :
864- index_name = random .choice (['index' , 'columns' ])
865- obj_name = random .choice (['df' , 'df2' ])
866-
867- df = mkdf (m1 , n , data_gen_f = f , r_idx_type = r1 , c_idx_type = c1 )
868- df2 = mkdf (m2 , n , data_gen_f = f , r_idx_type = r2 , c_idx_type = c2 )
869- index = getattr (locals ().get (obj_name ), index_name )
870- s = Series (np .random .randn (n ), index [:n ])
871-
872- if r2 == 'dt' or c2 == 'dt' :
873- if engine == 'numexpr' :
874- expected2 = df2 .add (s )
906+ with warnings .catch_warnings (record = True ):
907+ warnings .simplefilter ('always' , RuntimeWarning )
908+ for r1 , r2 , c1 , c2 in args :
909+ index_name = random .choice (['index' , 'columns' ])
910+ obj_name = random .choice (['df' , 'df2' ])
911+
912+ df = mkdf (m1 , n , data_gen_f = f , r_idx_type = r1 , c_idx_type = c1 )
913+ df2 = mkdf (m2 , n , data_gen_f = f , r_idx_type = r2 , c_idx_type = c2 )
914+ index = getattr (locals ().get (obj_name ), index_name )
915+ s = Series (np .random .randn (n ), index [:n ])
916+
917+ if r2 == 'dt' or c2 == 'dt' :
918+ if engine == 'numexpr' :
919+ expected2 = df2 .add (s )
920+ else :
921+ expected2 = df2 + s
875922 else :
876923 expected2 = df2 + s
877- else :
878- expected2 = df2 + s
879924
880- if r1 == 'dt' or c1 == 'dt' :
881- if engine == 'numexpr' :
882- expected = expected2 .add (df )
925+ if r1 == 'dt' or c1 == 'dt' :
926+ if engine == 'numexpr' :
927+ expected = expected2 .add (df )
928+ else :
929+ expected = expected2 + df
883930 else :
884931 expected = expected2 + df
885- else :
886- expected = expected2 + df
887932
888- res = pd .eval ('df2 + s + df' , engine = engine , parser = parser )
889- tm .assert_equal (res .shape , expected .shape )
890- assert_frame_equal (res , expected )
933+ if should_warn (df2 .index , s .index , df .index ):
934+ with tm .assert_produces_warning (RuntimeWarning ):
935+ res = pd .eval ('df2 + s + df' , engine = engine ,
936+ parser = parser )
937+ else :
938+ res = pd .eval ('df2 + s + df' , engine = engine , parser = parser )
939+ tm .assert_equal (res .shape , expected .shape )
940+ assert_frame_equal (res , expected )
891941
892942 @slow
893943 def test_complex_series_frame_alignment (self ):
0 commit comments