| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316 |
- # 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, make_name
- 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(make_name())
- 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 """
- name = make_name()
- self.f.attrs[name] = 4.0
- assert name in self.f.attrs
- self.assertEqual(self.f.attrs[name], 4.0)
- def test_create_2(self):
- """ Attribute creation by create() method """
- name = make_name()
- self.f.attrs.create(name, 4.0)
- assert name in self.f.attrs
- self.assertEqual(self.f.attrs[name], 4.0)
- def test_modify(self):
- """ Attributes are modified by direct assignment"""
- name = make_name()
- self.f.attrs[name] = 3
- assert name in self.f.attrs
- self.assertEqual(self.f.attrs[name], 3)
- self.f.attrs[name] = 4
- self.assertEqual(self.f.attrs[name], 4)
- def test_modify_2(self):
- """ Attributes are modified by modify() method """
- a = make_name("a")
- b = make_name("b")
- self.f.attrs.modify(a, 3)
- assert a in self.f.attrs
- self.assertEqual(self.f.attrs[a], 3)
- self.f.attrs.modify(a, 4)
- assert a in self.f.attrs
- self.assertEqual(self.f.attrs[a], 4)
- # If the attribute doesn't exist, create new
- self.f.attrs.modify(b, 5)
- assert a in self.f.attrs
- assert b in self.f.attrs
- 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 """
- name = make_name()
- self.f.attrs[name] = 4.0
- self.f.attrs[name] = 5.0
- self.assertEqual(self.f.attrs[name], 5.0)
- def test_rank(self):
- """ Attribute rank is preserved """
- name = make_name()
- self.f.attrs[name] = (4.0, 5.0)
- self.assertEqual(self.f.attrs[name].shape, (2,))
- self.assertArrayEqual(self.f.attrs[name], np.array((4.0,5.0)))
- def test_single(self):
- """ Attributes of shape (1,) don't become scalars """
- name = make_name()
- self.f.attrs[name] = np.ones((1,))
- out = self.f.attrs[name]
- 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['notexist']
- def test_get_id(self):
- name = make_name()
- self.f.attrs[name] = 4.0
- aid = self.f.attrs.get_id(name)
- assert isinstance(aid, h5a.AttrID)
- with self.assertRaises(KeyError):
- self.f.attrs.get_id("notexist")
- class TestDelete(BaseAttrs):
- """
- Feature: Deletion of attributes using __delitem__
- """
- def test_delete(self):
- """ Deletion via "del" """
- name = make_name()
- self.f.attrs[name] = 4.0
- self.assertIn(name, self.f.attrs)
- del self.f.attrs[name]
- self.assertNotIn(name, self.f.attrs)
- def test_delete_exc(self):
- """ Attempt to delete missing item raises KeyError """
- with self.assertRaises(KeyError):
- del self.f.attrs['notexist']
- class TestUnicode(BaseAttrs):
- """
- Feature: Attributes can be accessed via Unicode or byte strings
- """
- def test_ascii(self):
- """ Access via pure-ASCII byte string """
- name = make_name("ascii").encode("ascii")
- self.f.attrs[name] = 42
- out = self.f.attrs[name]
- self.assertEqual(out, 42)
- def test_raw(self):
- """ Access via non-ASCII byte string """
- name = make_name("non-ascii\xfe").encode("utf-8")
- 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 = make_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
- """
- t = make_name("t")
- x = make_name("x")
- self.f[t] = np.dtype('u8')
- self.f.attrs.create(x, 42, dtype=self.f[t])
- self.assertEqual(self.f.attrs[x], 42)
- aid = h5a.open(self.f.id, x.encode('utf-8'))
- htype = aid.get_type()
- htype2 = self.f[t].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
- """
- name = make_name()
- self.f.attrs.create(name, h5py.Empty('f'))
- self.assertEqual(self.f.attrs[name], h5py.Empty('f'))
- self.f.attrs.create(name, h5py.Empty(None))
- self.assertEqual(self.f.attrs[name], 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):
- name = make_name()
- a = np.array([np.arange(3), np.arange(4)],
- dtype=h5t.vlen_dtype(int))
- self.f.attrs[name] = a
- self.assertArrayEqual(self.f.attrs[name][0], a[0])
- def test_vlen_s1(self):
- name = make_name()
- 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(name, a)
- self.assertArrayEqual(self.f.attrs[name][0], a[0])
- class TestTrackOrder(BaseAttrs):
- def fill_attrs(self, track_order):
- attrs = self.f.create_group(make_name(), track_order=track_order).attrs
- for i in range(100):
- attrs[str(i)] = i
- return attrs
- # 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 test_track_order_overwrite_delete(self):
- # issue 1385
- group = self.f.create_group(make_name(), track_order=True)
- for i in range(12):
- group.attrs[str(i)] = i
- 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):
- name = make_name()
- self.f[name] = np.dtype('f')
- dt = self.f[name]
- 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
- name = make_name()
- data = [np.iinfo(np.int64).max, np.iinfo(np.int64).max + 1]
- # Check creating a new attribute
- f.attrs.create(name, data, dtype=np.uint64)
- assert f.attrs[name].dtype == np.dtype(np.uint64)
- np.testing.assert_array_equal(f.attrs[name], np.array(data, dtype=np.uint64))
- # Check modifying an existing attribute
- f.attrs.modify(name, data)
- np.testing.assert_array_equal(f.attrs[name], np.array(data, dtype=np.uint64))
|