1010import  iris .tests  as  tests 
1111
1212from  unittest  import  mock 
13+ import  numpy  as  np 
1314
1415from  iris .fileformats .pp  import  PPDataProxy , SplittableInt 
1516
@@ -21,7 +22,7 @@ def test_lbpack_SplittableInt(self):
2122        self .assertEqual (proxy .lbpack , lbpack )
2223        self .assertIs (proxy .lbpack , lbpack )
2324
24-     def  test_lnpack_raw (self ):
25+     def  test_lbpack_raw (self ):
2526        lbpack  =  4321 
2627        proxy  =  PPDataProxy (None , None , None , None , None , lbpack , None , None )
2728        self .assertEqual (proxy .lbpack , lbpack )
@@ -33,5 +34,128 @@ def test_lnpack_raw(self):
3334        self .assertEqual (proxy .lbpack .n4 , lbpack  //  1000  %  10 )
3435
3536
37+ class  SliceTranslator :
38+     """ 
39+     Class to translate an array-indexing expression into a tuple of keys. 
40+ 
41+     An instance just returns the argument of its __getitem__ call. 
42+ 
43+     """ 
44+ 
45+     def  __getitem__ (self , keys ):
46+         return  keys 
47+ 
48+ 
49+ # A multidimensional-indexable object that returns its index keys, so we can 
50+ # use multidimensional-indexing notation to specify a slicing expression. 
51+ Slices  =  SliceTranslator ()
52+ 
53+ 
54+ class  Test__getitem__slicing (tests .IrisTest ):
55+     def  _check_slicing (
56+         self , test_shape , indices , result_shape , data_was_fetched = True 
57+     ):
58+         # Check behaviour of the getitem call with specific slicings. 
59+         # Especially: check cases where a fetch does *not* read from the file. 
60+         # This is necessary because, since Dask 2.0, the "from_array" function 
61+         # takes a zero-length slice of its array argument, to capture array 
62+         # metadata, and in those cases we want to avoid file access. 
63+         test_dtype  =  np .dtype (np .float32 )
64+         proxy  =  PPDataProxy (
65+             shape = test_shape ,
66+             src_dtype = test_dtype ,
67+             path = None ,
68+             offset = None ,
69+             data_len = None ,
70+             lbpack = 0 ,  # Note: a 'real' value is needed. 
71+             boundary_packing = None ,
72+             mdi = None ,
73+         )
74+ 
75+         # Mock out the file-open call, to see if the file would be read. 
76+         builtin_open_func_name  =  "builtins.open" 
77+         mock_fileopen  =  self .patch (builtin_open_func_name )
78+ 
79+         # Also mock out the 'databytes_to_shaped_array' call, to fake minimal 
80+         # operation in the cases where file-open *does* get called. 
81+         fake_data  =  np .zeros (test_shape , dtype = test_dtype )
82+         self .patch (
83+             "iris.fileformats.pp._data_bytes_to_shaped_array" ,
84+             mock .MagicMock (return_value = fake_data ),
85+         )
86+ 
87+         # Test the requested indexing operation. 
88+         result  =  proxy .__getitem__ (indices )
89+ 
90+         # Check the behaviour and results were as expected. 
91+         self .assertEqual (mock_fileopen .called , data_was_fetched )
92+         self .assertIsInstance (result , np .ndarray )
93+         self .assertEqual (result .dtype , test_dtype )
94+         self .assertEqual (result .shape , result_shape )
95+ 
96+     def  test_slicing_1d_normal (self ):
97+         # A 'normal' 1d testcase with no empty slices. 
98+         self ._check_slicing (
99+             test_shape = (3 ,),
100+             indices = Slices [1 :10 ],
101+             result_shape = (2 ,),
102+             data_was_fetched = True ,
103+         )
104+ 
105+     def  test_slicing_1d_empty (self ):
106+         # A 1d testcase with an empty slicing. 
107+         self ._check_slicing (
108+             test_shape = (3 ,),
109+             indices = Slices [0 :0 ],
110+             result_shape = (0 ,),
111+             data_was_fetched = False ,
112+         )
113+ 
114+     def  test_slicing_2d_normal (self ):
115+         # A 2d testcase with no empty slices. 
116+         self ._check_slicing (
117+             test_shape = (3 , 4 ),
118+             indices = Slices [2 , :3 ],
119+             result_shape = (3 ,),
120+             data_was_fetched = True ,
121+         )
122+ 
123+     def  test_slicing_2d_allempty (self ):
124+         # A 2d testcase with all empty slices. 
125+         self ._check_slicing (
126+             test_shape = (3 , 4 ),
127+             indices = Slices [0 :0 , 0 :0 ],
128+             result_shape = (0 , 0 ),
129+             data_was_fetched = False ,
130+         )
131+ 
132+     def  test_slicing_2d_empty_dim0 (self ):
133+         # A 2d testcase with an empty slice. 
134+         self ._check_slicing (
135+             test_shape = (3 , 4 ),
136+             indices = Slices [0 :0 ],
137+             result_shape = (0 , 4 ),
138+             data_was_fetched = False ,
139+         )
140+ 
141+     def  test_slicing_2d_empty_dim1 (self ):
142+         # A 2d testcase with an empty slice, and an integer index. 
143+         self ._check_slicing (
144+             test_shape = (3 , 4 ),
145+             indices = Slices [1 , 0 :0 ],
146+             result_shape = (0 ,),
147+             data_was_fetched = False ,
148+         )
149+ 
150+     def  test_slicing_complex (self ):
151+         # Multiple dimensions with multiple empty slices. 
152+         self ._check_slicing (
153+             test_shape = (3 , 4 , 2 , 5 , 6 , 3 , 7 ),
154+             indices = Slices [1 :3 , 2 , 0 :0 , :, 1 :1 , :100 ],
155+             result_shape = (2 , 0 , 5 , 0 , 3 , 7 ),
156+             data_was_fetched = False ,
157+         )
158+ 
159+ 
36160if  __name__  ==  "__main__" :
37161    tests .main ()
0 commit comments