Spaces:
Running
Running
File size: 9,878 Bytes
122d3ff |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 |
# This file is part of h5py, a Python interface to the HDF5 library.
#
# http://www.h5py.org
#
# Copyright 2008-2013 Andrew Collette and contributors
#
# License: Standard 3-clause BSD; see "license.txt" for full license terms
# and contributor agreement.
"""
Attributes testing module
Covers all operations which access the .attrs property, with the
exception of data read/write and type conversion. Those operations
are tested by module test_attrs_data.
"""
import numpy as np
from collections.abc import MutableMapping
from .common import TestCase, ut
import h5py
from h5py import File
from h5py import h5a, h5t
from h5py import AttributeManager
class BaseAttrs(TestCase):
def setUp(self):
self.f = File(self.mktemp(), 'w')
def tearDown(self):
if self.f:
self.f.close()
class TestRepr(TestCase):
""" Feature: AttributeManager provide a helpful
__repr__ string
"""
def test_repr(self):
grp = self.f.create_group('grp')
grp.attrs.create('att', 1)
self.assertIsInstance(repr(grp.attrs), str)
grp.id.close()
self.assertIsInstance(repr(grp.attrs), str)
class TestAccess(BaseAttrs):
"""
Feature: Attribute creation/retrieval via special methods
"""
def test_create(self):
""" Attribute creation by direct assignment """
self.f.attrs['a'] = 4.0
self.assertEqual(list(self.f.attrs.keys()), ['a'])
self.assertEqual(self.f.attrs['a'], 4.0)
def test_create_2(self):
""" Attribute creation by create() method """
self.f.attrs.create('a', 4.0)
self.assertEqual(list(self.f.attrs.keys()), ['a'])
self.assertEqual(self.f.attrs['a'], 4.0)
def test_modify(self):
""" Attributes are modified by direct assignment"""
self.f.attrs['a'] = 3
self.assertEqual(list(self.f.attrs.keys()), ['a'])
self.assertEqual(self.f.attrs['a'], 3)
self.f.attrs['a'] = 4
self.assertEqual(list(self.f.attrs.keys()), ['a'])
self.assertEqual(self.f.attrs['a'], 4)
def test_modify_2(self):
""" Attributes are modified by modify() method """
self.f.attrs.modify('a',3)
self.assertEqual(list(self.f.attrs.keys()), ['a'])
self.assertEqual(self.f.attrs['a'], 3)
self.f.attrs.modify('a', 4)
self.assertEqual(list(self.f.attrs.keys()), ['a'])
self.assertEqual(self.f.attrs['a'], 4)
# If the attribute doesn't exist, create new
self.f.attrs.modify('b', 5)
self.assertEqual(list(self.f.attrs.keys()), ['a', 'b'])
self.assertEqual(self.f.attrs['a'], 4)
self.assertEqual(self.f.attrs['b'], 5)
# Shape of new value is incompatible with the previous
new_value = np.arange(5)
with self.assertRaises(TypeError):
self.f.attrs.modify('b', new_value)
def test_overwrite(self):
""" Attributes are silently overwritten """
self.f.attrs['a'] = 4.0
self.f.attrs['a'] = 5.0
self.assertEqual(self.f.attrs['a'], 5.0)
def test_rank(self):
""" Attribute rank is preserved """
self.f.attrs['a'] = (4.0, 5.0)
self.assertEqual(self.f.attrs['a'].shape, (2,))
self.assertArrayEqual(self.f.attrs['a'], np.array((4.0,5.0)))
def test_single(self):
""" Attributes of shape (1,) don't become scalars """
self.f.attrs['a'] = np.ones((1,))
out = self.f.attrs['a']
self.assertEqual(out.shape, (1,))
self.assertEqual(out[()], 1)
def test_access_exc(self):
""" Attempt to access missing item raises KeyError """
with self.assertRaises(KeyError):
self.f.attrs['a']
def test_get_id(self):
self.f.attrs['a'] = 4.0
aid = self.f.attrs.get_id('a')
assert isinstance(aid, h5a.AttrID)
with self.assertRaises(KeyError):
self.f.attrs.get_id('b')
class TestDelete(BaseAttrs):
"""
Feature: Deletion of attributes using __delitem__
"""
def test_delete(self):
""" Deletion via "del" """
self.f.attrs['a'] = 4.0
self.assertIn('a', self.f.attrs)
del self.f.attrs['a']
self.assertNotIn('a', self.f.attrs)
def test_delete_exc(self):
""" Attempt to delete missing item raises KeyError """
with self.assertRaises(KeyError):
del self.f.attrs['a']
class TestUnicode(BaseAttrs):
"""
Feature: Attributes can be accessed via Unicode or byte strings
"""
def test_ascii(self):
""" Access via pure-ASCII byte string """
self.f.attrs[b"ascii"] = 42
out = self.f.attrs[b"ascii"]
self.assertEqual(out, 42)
def test_raw(self):
""" Access via non-ASCII byte string """
name = b"non-ascii\xfe"
self.f.attrs[name] = 42
out = self.f.attrs[name]
self.assertEqual(out, 42)
def test_unicode(self):
""" Access via Unicode string with non-ascii characters """
name = "Omega" + chr(0x03A9)
self.f.attrs[name] = 42
out = self.f.attrs[name]
self.assertEqual(out, 42)
class TestCreate(BaseAttrs):
"""
Options for explicit attribute creation
"""
def test_named(self):
""" Attributes created from named types link to the source type object
"""
self.f['type'] = np.dtype('u8')
self.f.attrs.create('x', 42, dtype=self.f['type'])
self.assertEqual(self.f.attrs['x'], 42)
aid = h5a.open(self.f.id, b'x')
htype = aid.get_type()
htype2 = self.f['type'].id
self.assertEqual(htype, htype2)
self.assertTrue(htype.committed())
def test_empty(self):
# https://github.com/h5py/h5py/issues/1540
""" Create attribute with h5py.Empty value
"""
self.f.attrs.create('empty', h5py.Empty('f'))
self.assertEqual(self.f.attrs['empty'], h5py.Empty('f'))
self.f.attrs.create('empty', h5py.Empty(None))
self.assertEqual(self.f.attrs['empty'], h5py.Empty(None))
class TestMutableMapping(BaseAttrs):
'''Tests if the registration of AttributeManager as a MutableMapping
behaves as expected
'''
def test_resolution(self):
assert issubclass(AttributeManager, MutableMapping)
assert isinstance(self.f.attrs, MutableMapping)
def test_validity(self):
'''
Test that the required functions are implemented.
'''
AttributeManager.__getitem__
AttributeManager.__setitem__
AttributeManager.__delitem__
AttributeManager.__iter__
AttributeManager.__len__
class TestVlen(BaseAttrs):
def test_vlen(self):
a = np.array([np.arange(3), np.arange(4)],
dtype=h5t.vlen_dtype(int))
self.f.attrs['a'] = a
self.assertArrayEqual(self.f.attrs['a'][0], a[0])
def test_vlen_s1(self):
dt = h5py.vlen_dtype(np.dtype('S1'))
a = np.empty((1,), dtype=dt)
a[0] = np.array([b'a', b'b'], dtype='S1')
self.f.attrs.create('test', a)
self.assertArrayEqual(self.f.attrs['test'][0], a[0])
class TestTrackOrder(BaseAttrs):
def fill_attrs(self, track_order):
attrs = self.f.create_group('test', track_order=track_order).attrs
for i in range(100):
attrs[str(i)] = i
return attrs
@ut.skipUnless(h5py.version.hdf5_version_tuple >= (1, 10, 6), 'HDF5 1.10.6 required')
# https://forum.hdfgroup.org/t/bug-h5arename-fails-unexpectedly/4881
def test_track_order(self):
attrs = self.fill_attrs(track_order=True) # creation order
self.assertEqual(list(attrs),
[str(i) for i in range(100)])
def test_no_track_order(self):
attrs = self.fill_attrs(track_order=False) # name alphanumeric
self.assertEqual(list(attrs),
sorted([str(i) for i in range(100)]))
def fill_attrs2(self, track_order):
group = self.f.create_group('test', track_order=track_order)
for i in range(12):
group.attrs[str(i)] = i
return group
@ut.skipUnless(h5py.version.hdf5_version_tuple >= (1, 10, 6), 'HDF5 1.10.6 required')
def test_track_order_overwrite_delete(self):
# issue 1385
group = self.fill_attrs2(track_order=True) # creation order
self.assertEqual(group.attrs["11"], 11)
# overwrite attribute
group.attrs['11'] = 42.0
self.assertEqual(group.attrs["11"], 42.0)
# delete attribute
self.assertIn('10', group.attrs)
del group.attrs['10']
self.assertNotIn('10', group.attrs)
class TestDatatype(BaseAttrs):
def test_datatype(self):
self.f['foo'] = np.dtype('f')
dt = self.f['foo']
self.assertEqual(list(dt.attrs.keys()), [])
dt.attrs.create('a', 4.0)
self.assertEqual(list(dt.attrs.keys()), ['a'])
self.assertEqual(list(dt.attrs.values()), [4.0])
def test_python_int_uint64(writable_file):
f = writable_file
data = [np.iinfo(np.int64).max, np.iinfo(np.int64).max + 1]
# Check creating a new attribute
f.attrs.create('a', data, dtype=np.uint64)
assert f.attrs['a'].dtype == np.dtype(np.uint64)
np.testing.assert_array_equal(f.attrs['a'], np.array(data, dtype=np.uint64))
# Check modifying an existing attribute
f.attrs.modify('a', data)
np.testing.assert_array_equal(f.attrs['a'], np.array(data, dtype=np.uint64))
|