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

Code before:
                         delta)

        # Check that loading pickles from 1.6 works
        with pytest.warns(np.exceptions.VisibleDeprecationWarning,
                match=r".*align should be passed"):
            pkl = b"cnumpy\ndtype\np0\n(S'M8'\np1\nI0\nI1\ntp2\nRp3\n"\
                b"(I4\nS'<'\np4\nNNNI-1\nI-1\nI0\n((dp5\n(S'D'\np6\n"\
                b"I7\nI1\nI1\ntp7\ntp8\ntp9\nb."
            assert_equal(pickle.loads(pkl), np.dtype('<M8[7D]'))
            pkl = b"cnumpy\ndtype\np0\n(S'M8'\np1\nI0\nI1\ntp2\nRp3\n"\
                b"(I4\nS'<'\np4\nNNNI-1\nI-1\nI0\n((dp5\n(S'W'\np6\n"\
                b"I1\nI1\nI1\ntp7\ntp8\ntp9\nb."
            assert_equal(pickle.loads(pkl), np.dtype('<M8[W]'))
            pkl = b"cnumpy\ndtype\np0\n(S'M8'\np1\nI0\nI1\ntp2\nRp3\n"\
                b"(I4\nS'>'\np4\nNNNI-1\nI-1\nI0\n((dp5\n(S'us'\np6\n"\
                b"I1\nI1\nI1\ntp7\ntp8\ntp9\nb."
            assert_equal(pickle.loads(pkl), np.dtype('>M8[us]'))

        # check that dtype metadata round-trips when none
        # gh-29555
        dt = np.dtype('>M8[us]')
        assert dt.metadata is None
        for proto in range(2, pickle.HIGHEST_PROTOCOL + 1):
            res = pickle.loads(pickle.dumps(dt, protocol=proto))
            assert_equal(res, dt)
            assert res.metadata is None

    def test_setstate(self):
        "Verify that datetime dtype __setstate__ can handle bad arguments"
        dt = np.dtype('>M8[us]')
        assert_raises(ValueError, dt.__setstate__,
                      (4, '>', None, None, None, -1, -1, 0, 1))
        assert_(dt.__reduce__()[2] == np.dtype('>M8[us]').__reduce__()[2])
        assert_raises(TypeError, dt.__setstate__,
                      (4, '>', None, None, None, -1, -1, 0, ({}, 'xxx')))
        assert_(dt.__reduce__()[2] == np.dtype('>M8[us]').__reduce__()[2])

    def test_dtype_promotion(self):
        # datetime <op> datetime computes the metadata gcd
        # timedelta <op> timedelta computes the metadata gcd
        for mM in ['m', 'M']:
            assert_equal(
                np.promote_types(np.dtype(mM + '8[2Y]'), np.dtype(mM + '8[2Y]')),
                np.dtype(mM + '8[2Y]'))
            assert_equal(
                np.promote_types(np.dtype(mM + '8[12Y]'), np.dtype(mM + '8[15Y]')),
                np.dtype(mM + '8[3Y]'))
            assert_equal(
                np.promote_types(np.dtype(mM + '8[62M]'), np.dtype(mM + '8[24M]')),
                np.dtype(mM + '8[2M]'))
            assert_equal(

Review comment (bug):
Since this test already has 7 other assertions above, any objection to just making it its own regression test:

```diff
--- a/numpy/_core/tests/test_datetime.py
+++ b/numpy/_core/tests/test_datetime.py
@@ -889,8 +889,8 @@ def test_pickle(self):
                 b"I1\nI1\nI1\ntp7\ntp8\ntp9\nb."
             assert_equal(pickle.loads(pkl), np.dtype('>M8[us]'))
 
+    def test_gh_29555(self):
         # check that dtype metadata round-trips when none
-        # gh-29555
         dt = np.dtype('>M8[us]')
```

Beyond that, the regression test does indeed seem to fail before/pass after the patch in my hands locally.

Code after:
                         delta)

        # Check that loading pickles from 1.6 works
        with pytest.warns(np.exceptions.VisibleDeprecationWarning,
                match=r".*align should be passed"):
            pkl = b"cnumpy\ndtype\np0\n(S'M8'\np1\nI0\nI1\ntp2\nRp3\n"\
                b"(I4\nS'<'\np4\nNNNI-1\nI-1\nI0\n((dp5\n(S'D'\np6\n"\
                b"I7\nI1\nI1\ntp7\ntp8\ntp9\nb."
            assert_equal(pickle.loads(pkl), np.dtype('<M8[7D]'))
            pkl = b"cnumpy\ndtype\np0\n(S'M8'\np1\nI0\nI1\ntp2\nRp3\n"\
                b"(I4\nS'<'\np4\nNNNI-1\nI-1\nI0\n((dp5\n(S'W'\np6\n"\
                b"I1\nI1\nI1\ntp7\ntp8\ntp9\nb."
            assert_equal(pickle.loads(pkl), np.dtype('<M8[W]'))
            pkl = b"cnumpy\ndtype\np0\n(S'M8'\np1\nI0\nI1\ntp2\nRp3\n"\
                b"(I4\nS'>'\np4\nNNNI-1\nI-1\nI0\n((dp5\n(S'us'\np6\n"\
                b"I1\nI1\nI1\ntp7\ntp8\ntp9\nb."
            assert_equal(pickle.loads(pkl), np.dtype('>M8[us]'))

    def test_gh_29555(self):
        # check that dtype metadata round-trips when none
        dt = np.dtype('>M8[us]')
        assert dt.metadata is None
        for proto in range(2, pickle.HIGHEST_PROTOCOL + 1):
            res = pickle.loads(pickle.dumps(dt, protocol=proto))
            assert_equal(res, dt)
            assert res.metadata is None

    def test_setstate(self):
        "Verify that datetime dtype __setstate__ can handle bad arguments"
        dt = np.dtype('>M8[us]')
        assert_raises(ValueError, dt.__setstate__,
                      (4, '>', None, None, None, -1, -1, 0, 1))
        assert_(dt.__reduce__()[2] == np.dtype('>M8[us]').__reduce__()[2])
        assert_raises(TypeError, dt.__setstate__,
                      (4, '>', None, None, None, -1, -1, 0, ({}, 'xxx')))
        assert_(dt.__reduce__()[2] == np.dtype('>M8[us]').__reduce__()[2])

    def test_dtype_promotion(self):
        # datetime <op> datetime computes the metadata gcd
        # timedelta <op> timedelta computes the metadata gcd
        for mM in ['m', 'M']:
            assert_equal(
                np.promote_types(np.dtype(mM + '8[2Y]'), np.dtype(mM + '8[2Y]')),
                np.dtype(mM + '8[2Y]'))
            assert_equal(
                np.promote_types(np.dtype(mM + '8[12Y]'), np.dtype(mM + '8[15Y]')),
                np.dtype(mM + '8[3Y]'))
            assert_equal(
                np.promote_types(np.dtype(mM + '8[62M]'), np.dtype(mM + '8[24M]')),
                np.dtype(mM + '8[2M]'))
            assert_equal(