Repository: numpy/numpy
File: numpy/_core/tests/test_dtype.py (Python)

Code before:
        self.check(PaddedStruct, expected)

    def test_simple_endian_types(self):
        self.check(ctypes.c_uint16.__ctype_le__, np.dtype('<u2'))
        self.check(ctypes.c_uint16.__ctype_be__, np.dtype('>u2'))
        self.check(ctypes.c_uint8.__ctype_le__, np.dtype('u1'))
        self.check(ctypes.c_uint8.__ctype_be__, np.dtype('u1'))

    all_types = set(np.typecodes['All'])
    all_pairs = permutations(all_types, 2)

    @pytest.mark.parametrize("pair", all_pairs)
    def test_pairs(self, pair):
        """
        Check that np.dtype('x,y') matches [np.dtype('x'), np.dtype('y')]
        Example: np.dtype('d,I') -> dtype([('f0', '<f8'), ('f1', '<u4')])
        """
        # gh-5645: check that np.dtype('i,L') can be used
        pair_type = np.dtype('{},{}'.format(*pair))
        expected = np.dtype([('f0', pair[0]), ('f1', pair[1])])
        assert_equal(pair_type, expected)


class TestUserDType:
    @pytest.mark.leaks_references(reason="dynamically creates custom dtype.")
    @pytest.mark.thread_unsafe(reason="crashes when GIL disabled")
    def test_custom_structured_dtype(self):
        class mytype:
            pass

        blueprint = np.dtype([("field", object)])
        dt = create_custom_field_dtype(blueprint, mytype, 0)
        assert dt.type == mytype
        # We cannot (currently) *create* this dtype with `np.dtype` because
        # mytype does not inherit from `np.generic`.  This seems like an
        # unnecessary restriction, but one that has been around forever:
        assert np.dtype(mytype) == np.dtype("O")

        if HAS_REFCOUNT:
            # Create an array and test that memory gets cleaned up (gh-25949)
            o = object()
            startcount = sys.getrefcount(o)
            a = np.array([o], dtype=dt)
            del a
            assert sys.getrefcount(o) == startcount

    @pytest.mark.thread_unsafe(reason="crashes when GIL disabled")
    def test_custom_structured_dtype_errors(self):
        class mytype:
            pass


Review comment (bug):
I think the crash is because legacy user dtype setup isn't thread-safe? I think we should explain why the crash is happening in this message.

Code after:
            ]
        expected = np.dtype([
            ('a', '>B'),
            ('b', '>H')
        ], align=True)
        self.check(PaddedStruct, expected)

    def test_simple_endian_types(self):
        self.check(ctypes.c_uint16.__ctype_le__, np.dtype('<u2'))
        self.check(ctypes.c_uint16.__ctype_be__, np.dtype('>u2'))
        self.check(ctypes.c_uint8.__ctype_le__, np.dtype('u1'))
        self.check(ctypes.c_uint8.__ctype_be__, np.dtype('u1'))

    all_types = set(np.typecodes['All'])
    all_pairs = permutations(all_types, 2)

    @pytest.mark.parametrize("pair", all_pairs)
    def test_pairs(self, pair):
        """
        Check that np.dtype('x,y') matches [np.dtype('x'), np.dtype('y')]
        Example: np.dtype('d,I') -> dtype([('f0', '<f8'), ('f1', '<u4')])
        """
        # gh-5645: check that np.dtype('i,L') can be used
        pair_type = np.dtype('{},{}'.format(*pair))
        expected = np.dtype([('f0', pair[0]), ('f1', pair[1])])
        assert_equal(pair_type, expected)


class TestUserDType:
    @pytest.mark.leaks_references(reason="dynamically creates custom dtype.")
    @pytest.mark.thread_unsafe(reason="crashes when GIL disabled, dtype setup is thread-unsafe")
    def test_custom_structured_dtype(self):
        class mytype:
            pass

        blueprint = np.dtype([("field", object)])
        dt = create_custom_field_dtype(blueprint, mytype, 0)
        assert dt.type == mytype
        # We cannot (currently) *create* this dtype with `np.dtype` because
        # mytype does not inherit from `np.generic`.  This seems like an
        # unnecessary restriction, but one that has been around forever:
        assert np.dtype(mytype) == np.dtype("O")

        if HAS_REFCOUNT:
            # Create an array and test that memory gets cleaned up (gh-25949)
            o = object()
            startcount = sys.getrefcount(o)
            a = np.array([o], dtype=dt)
            del a
            assert sys.getrefcount(o) == startcount