Bug 2349447 - python-orjson fails to build with Python 3.14: multiple AssertionError, mostly related to dict objects
Summary: python-orjson fails to build with Python 3.14: multiple AssertionError, mostl...
Keywords:
Status: CLOSED ERRATA
Alias: None
Product: Fedora
Classification: Fedora
Component: python-orjson
Version: rawhide
Hardware: Unspecified
OS: Unspecified
unspecified
unspecified
Target Milestone: ---
Assignee: Ben Beasley
QA Contact:
URL:
Whiteboard:
Depends On: 2354600
Blocks: PYTHON3.14
TreeView+ depends on / blocked
 
Reported: 2025-03-03 09:09 UTC by Karolina Surma
Modified: 2025-04-13 01:42 UTC (History)
6 users (show)

Fixed In Version: python-orjson-3.10.16-1.fc43 python-orjson-3.10.16-1.fc42 python-orjson-3.10.16-1.fc41 python-orjson-3.10.16-1.fc40
Clone Of:
Environment:
Last Closed: 2025-04-03 13:24:57 UTC
Type: Bug
Embargoed:


Attachments (Terms of Use)

Description Karolina Surma 2025-03-03 09:09:45 UTC
python-orjson fails to build with Python 3.14.0a5.

______________________________ TestDict.test_dict ______________________________
self = <test.test_dict.TestDict object at 0x7f87e8c7de50>

    def test_dict(self):
        """
        dict
        """
        obj = {"key": "value"}
        ref = '{"key":"value"}'
        assert orjson.dumps(obj) == ref.encode("utf-8")
>       assert orjson.loads(ref) == obj
E       AssertionError: assert {'key': 'value'} == {'key': 'value'}
E         
E         Left contains 1 more item:
E         {'key': 'value'}
E         Right contains 1 more item:
E         {'key': 'value'}
E         Use -v to get more diff

test/test_dict.py:16: AssertionError
______________________ TestDict.test_dict_duplicate_loads ______________________
self = <test.test_dict.TestDict object at 0x7f87e8c7df90>

    def test_dict_duplicate_loads(self):
>       assert orjson.loads(b'{"1":true,"1":false}') == {"1": False}
E       AssertionError: assert {'1': False} == {'1': False}
E         
E         Left contains 1 more item:
E         {'1': False}
E         Right contains 1 more item:
E         {'1': False}
E         Use -v to get more diff

test/test_dict.py:19: AssertionError
___________________________ TestDict.test_dict_empty ___________________________
self = <test.test_dict.TestDict object at 0x7f87e8ca8770>

    def test_dict_empty(self):
        obj = [{"key": [{}] * 4096}] * 4096  # type:ignore
>       assert orjson.loads(orjson.dumps(obj)) == obj
E       AssertionError: assert [{'key': [{},...}, ...]}, ...] == [{'key': [{},...}, ...]}, ...]
E         
E         At index 0 diff: {'key': [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}...
E         
E         ...Full output truncated (2 lines hidden), use '-vv' to show

test/test_dict.py:23: AssertionError
________________________ TestDict.test_dict_large_dict _________________________
self = <test.test_dict.TestDict object at 0x7f87e8ca88a0>

    def test_dict_large_dict(self):
        """
        dict with >512 keys
        """
        obj = {"key_%s" % idx: [{}, {"a": [{}, {}, {}]}, {}] for idx in range(513)}  # type: ignore
        assert len(obj) == 513
>       assert orjson.loads(orjson.dumps(obj)) == obj
E       AssertionError: assert {'key_0': [{}...}]}, {}], ...} == {'key_0': [{}...}]}, {}], ...}
E         
E         Left contains 513 more items:
E         {'key_0': [{}, {'a': [{}, {}, {}]}, {}],
E          'key_1': [{}, {'a': [{}, {}, {}]}, {}],
E          'key_10': [{}, {'a': [{}, {}, {}]}, {}],
E          'key_100': [{}, {'a': [{}, {}, {}]}, {}],
E          'key_101': [{}, {'a': [{}, {}, {}]}, {}],...
E         
E         ...Full output truncated (1023 lines hidden), use '-vv' to show

test/test_dict.py:31: AssertionError
________________________ TestDict.test_dict_large_4096 _________________________
self = <test.test_dict.TestDict object at 0x7f8809736210>

    def test_dict_large_4096(self):
        """
        dict with >4096 keys
        """
        obj = {"key_%s" % idx: "value_%s" % idx for idx in range(4097)}
        assert len(obj) == 4097
>       assert orjson.loads(orjson.dumps(obj)) == obj
E       AssertionError: assert {'key_0': 'va...lue_100', ...} == {'key_0': 'va...lue_100', ...}
E         
E         Left contains 4097 more items:
E         {'key_0': 'value_0',
E          'key_1': 'value_1',
E          'key_10': 'value_10',
E          'key_100': 'value_100',
E          'key_1000': 'value_1000',...
E         
E         ...Full output truncated (8191 lines hidden), use '-vv' to show

test/test_dict.py:39: AssertionError
________________________ TestDict.test_dict_large_65536 ________________________
self = <test.test_dict.TestDict object at 0x7f8809706690>

    def test_dict_large_65536(self):
        """
        dict with >65536 keys
        """
        obj = {"key_%s" % idx: "value_%s" % idx for idx in range(65537)}
        assert len(obj) == 65537
>       assert orjson.loads(orjson.dumps(obj)) == obj
E       AssertionError: assert {'key_0': 'va...lue_100', ...} == {'key_0': 'va...lue_100', ...}
E         
E         Left contains 65537 more items:
E         {'key_0': 'value_0',
E          'key_1': 'value_1',
E          'key_10': 'value_10',
E          'key_100': 'value_100',
E          'key_1000': 'value_1000',...
E         
E         ...Full output truncated (131071 lines hidden), use '-vv' to show

test/test_dict.py:47: AssertionError
________________________ TestDict.test_dict_large_keys _________________________
self = <test.test_dict.TestDict object at 0x7f88097067a0>

    def test_dict_large_keys(self):
        """
        dict with keys too large to cache
        """
        obj = {
            "keeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeey": "value"
        }
        ref = '{"keeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeey":"value"}'
        assert orjson.dumps(obj) == ref.encode("utf-8")
>       assert orjson.loads(ref) == obj
E       AssertionError: assert {'keeeeeeeeee...eey': 'value'} == {'keeeeeeeeee...eey': 'value'}
E         
E         Left contains 1 more item:
E         {'keeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeey': 'value'}
E         Right contains 1 more item:
E         {'keeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeey': 'value'}
E         Use -v to get more diff

test/test_dict.py:58: AssertionError
__________________________ TestDict.test_dict_unicode __________________________
self = <test.test_dict.TestDict object at 0x7f87e8c7b250>

    def test_dict_unicode(self):
        """
        dict unicode keys
        """
        obj = {"🐈": "value"}
        ref = b'{"\xf0\x9f\x90\x88":"value"}'
        assert orjson.dumps(obj) == ref
>       assert orjson.loads(ref) == obj
E       AssertionError: assert {'🐈': 'value'} == {'🐈': 'value'}
E         
E         Left contains 1 more item:
E         {'🐈': 'value'}
E         Right contains 1 more item:
E         {'🐈': 'value'}
E         Use -v to get more diff

test/test_dict.py:67: AssertionError
_______________________ TestDict.test_dict_similar_keys ________________________
self = <test.test_dict.TestDict object at 0x7f87e8d14050>

    def test_dict_similar_keys(self):
        """
        loads() similar keys
    
        This was a regression in 3.4.2 caused by using
        the implementation in wy instead of wyhash.
        """
>       assert orjson.loads(
            '{"cf_status_firefox67": "---", "cf_status_firefox57": "verified"}'
        ) == {"cf_status_firefox57": "verified", "cf_status_firefox67": "---"}
E       AssertionError: assert {'cf_status_f...fox67': '---'} == {'cf_status_f...fox67': '---'}
E         
E         Left contains 2 more items:
E         {'cf_status_firefox57': 'verified', 'cf_status_firefox67': '---'}
E         Right contains 2 more items:
E         {'cf_status_firefox57': 'verified', 'cf_status_firefox67': '---'}
E         Use -v to get more diff

test/test_dict.py:95: AssertionError
___________________________ TestDict.test_dict_0xff ____________________________
self = <test.test_dict.TestDict object at 0x7f880971df10>

    def test_dict_0xff(self):
        "dk_size <= 0xff"
        data = {str(idx): idx for idx in range(0, 0xFF)}
        data.pop("112")
        data["112"] = 1
        data["113"] = 2
>       assert orjson.loads(orjson.dumps(data)) == data
E       AssertionError: assert {'0': 0, '1':...00': 100, ...} == {'0': 0, '1':...00': 100, ...}
E         
E         Left contains 255 more items:
E         {'0': 0,
E          '1': 1,
E          '10': 10,
E          '100': 100,
E          '101': 101,...
E         
E         ...Full output truncated (507 lines hidden), use '-vv' to show

test/test_dict.py:135: AssertionError
_______________________ TestDict.test_dict_0xff_repeated _______________________
self = <test.test_dict.TestDict object at 0x7f880e162e60>

    def test_dict_0xff_repeated(self):
        "dk_size <= 0xff repeated"
        for _ in range(0, 100):
            data = {str(idx): idx for idx in range(0, 0xFF)}
            data.pop("112")
            data["112"] = 1
            data["113"] = 2
>           assert orjson.loads(orjson.dumps(data)) == data
E           AssertionError: assert {'0': 0, '1':...00': 100, ...} == {'0': 0, '1':...00': 100, ...}
E             
E             Left contains 255 more items:
E             {'0': 0,
E              '1': 1,
E              '10': 10,
E              '100': 100,
E              '101': 101,...
E             
E             ...Full output truncated (507 lines hidden), use '-vv' to show

test/test_dict.py:144: AssertionError
__________________________ TestDict.test_dict_0xffff ___________________________
self = <test.test_dict.TestDict object at 0x7f880e1635f0>

    def test_dict_0xffff(self):
        "dk_size <= 0xffff"
        data = {str(idx): idx for idx in range(0, 0xFFFF)}
        data.pop("112")
        data["112"] = 1
        data["113"] = 2
>       assert orjson.loads(orjson.dumps(data)) == data
E       AssertionError: assert {'0': 0, '1':...00': 100, ...} == {'0': 0, '1':...00': 100, ...}
E         
E         Left contains 65535 more items:
E         {'0': 0,
E          '1': 1,
E          '10': 10,
E          '100': 100,
E          '1000': 1000,...
E         
E         ...Full output truncated (131067 lines hidden), use '-vv' to show

test/test_dict.py:152: AssertionError
______________________ TestDict.test_dict_0xffff_repeated ______________________
self = <test.test_dict.TestDict object at 0x7f87e8c762b0>

    def test_dict_0xffff_repeated(self):
        "dk_size <= 0xffff repeated"
        for _ in range(0, 100):
            data = {str(idx): idx for idx in range(0, 0xFFFF)}
            data.pop("112")
            data["112"] = 1
            data["113"] = 2
>           assert orjson.loads(orjson.dumps(data)) == data
E           AssertionError: assert {'0': 0, '1':...00': 100, ...} == {'0': 0, '1':...00': 100, ...}
E             
E             Left contains 65535 more items:
E             {'0': 0,
E              '1': 1,
E              '10': 10,
E              '100': 100,
E              '1000': 1000,...
E             
E             ...Full output truncated (131067 lines hidden), use '-vv' to show

test/test_dict.py:161: AssertionError
_____________________________ TestFaker.test_faker _____________________________
self = <test.test_fake.TestFaker object at 0x7f87e8c7ead0>

    @pytest.mark.skipif(Faker is None, reason="faker not available")
    def test_faker(self):
        fake = Faker(FAKER_LOCALES)
        profile_keys = list(
            set(fake.profile().keys()) - {"birthdate", "current_location"}
        )
        for _ in range(0, NUM_LOOPS):
            data = [
                {
                    "person": fake.profile(profile_keys),
                    "emoji": fake.emoji(),
                    "text": fake.paragraphs(),
                }
                for _ in range(0, NUM_ENTRIES)
            ]
            for _ in range(0, NUM_SHUFFLES):
                random.shuffle(data)
                output = orjson.dumps(data)
>               assert orjson.loads(output) == data
E               AssertionError: assert [{'emoji': '🤦...đúng.']}, ...] == [{'emoji': '🤦...đúng.']}, ...]
E                 
E                 At index 0 diff: {'person': {'job': 'Lập trình viên', 'company': 'Hoàng và Bùi Doanh nghiệp tư nhân', 'ssn': '384-57-1927', 'residence': '609 Nguyễn Ngõ\nJanePhường, 945667', 'blood_group': 'AB+', 'website': ['http://mai.com/', 'https://nguyen.com/', 'http://tran.org/'], 'username': 'janeduong', 'name': 'An Quang Lê', 'sex': 'M', 'address': '4 Jane Đường\nJaneQuận, 623733', 'mail': 'jane20'}, 'emoji': '🤦🏾', 'text': ['ตอใดเขยื้อนดอกไม้ น้องขี่ธนาคารทั่วใบไม้พับ ', 'สหกรณ์เช้าชะนีกิจกรรมกิจกรรมสถานีห่อข้าว ผสมแรงงานแต่สบายไอโอเอสข้าว ', 'คู่บาดธนาคารหยักเศษอาหาร...
E                 
E                 ...Full output truncated (2 lines hidden), use '-vv' to show

test/test_fake.py:50: AssertionError
______________________________ TestType.test_list ______________________________
self = <test.test_type.TestType object at 0x7f87e5d51860>

    def test_list(self):
        """
        list
        """
        obj = ["a", "😊", True, {"b": 1.1}, 2]
        ref = '["a","😊",true,{"b":1.1},2]'
        assert orjson.dumps(obj) == ref.encode("utf-8")
>       assert orjson.loads(ref) == obj
E       AssertionError: assert ['a', '😊', Tr...{'b': 1.1}, 2] == ['a', '😊', Tr...{'b': 1.1}, 2]
E         
E         At index 3 diff: {'b': 1.1} != {'b': 1.1}
E         Use -v to get more diff

test/test_type.py:518: AssertionError
_____________________________ TestType.test_tuple ______________________________
self = <test.test_type.TestType object at 0x7f87e5d51950>

    def test_tuple(self):
        """
        tuple
        """
        obj = ("a", "😊", True, {"b": 1.1}, 2)
        ref = '["a","😊",true,{"b":1.1},2]'
        assert orjson.dumps(obj) == ref.encode("utf-8")
>       assert orjson.loads(ref) == list(obj)
E       AssertionError: assert ['a', '😊', Tr...{'b': 1.1}, 2] == ['a', '😊', Tr...{'b': 1.1}, 2]
E         
E         At index 3 diff: {'b': 1.1} != {'b': 1.1}
E         Use -v to get more diff

test/test_type.py:527: AssertionError
______________________ TestUltraJSON.test_doubleLongIssue ______________________
self = <test.test_ujson.TestUltraJSON object at 0x7f87e6108f50>

    def test_doubleLongIssue(self):
        sut = {"a": -4342969734183514}
        encoded = orjson.dumps(sut)
        decoded = orjson.loads(encoded)
>       assert sut == decoded
E       AssertionError: assert {'a': -4342969734183514} == {'a': -4342969734183514}
E         
E         Left contains 1 more item:
E         {'a': -4342969734183514}
E         Right contains 1 more item:
E         {'a': -4342969734183514}
E         Use -v to get more diff

test/test_ujson.py:16: AssertionError
__________________ TestUltraJSON.test_doubleLongDecimalIssue ___________________
self = <test.test_ujson.TestUltraJSON object at 0x7f87e61091d0>

    def test_doubleLongDecimalIssue(self):
        sut = {"a": -12345678901234.56789012}
        encoded = orjson.dumps(sut)
        decoded = orjson.loads(encoded)
>       assert sut == decoded
E       AssertionError: assert {'a': -12345678901234.568} == {'a': -12345678901234.568}
E         
E         Left contains 1 more item:
E         {'a': -12345678901234.568}
E         Right contains 1 more item:
E         {'a': -12345678901234.568}
E         Use -v to get more diff

test/test_ujson.py:25: AssertionError
_____________________ TestUltraJSON.test_decimalDecodeTest _____________________
self = <test.test_ujson.TestUltraJSON object at 0x7f87e59c4510>

    def test_decimalDecodeTest(self):
        sut = {"a": 4.56}
        encoded = orjson.dumps(sut)
        decoded = orjson.loads(encoded)
>       pytest.approx(sut["a"], decoded["a"])
E       KeyError: 'a'

test/test_ujson.py:39: KeyError
___________________ TestUltraJSON.test_encodeDictConversion ____________________
self = <test.test_ujson.TestUltraJSON object at 0x7f87e59891d0>

    def test_encodeDictConversion(self):
        val = {"k1": 1, "k2": 2, "k3": 3, "k4": 4}
        output = orjson.dumps(val)
>       assert val == orjson.loads(output)
E       AssertionError: assert {'k1': 1, 'k2...': 3, 'k4': 4} == {'k1': 1, 'k2...': 3, 'k4': 4}
E         
E         Left contains 4 more items:
E         {'k1': 1, 'k2': 2, 'k3': 3, 'k4': 4}
E         Right contains 4 more items:
E         {'k1': 1, 'k2': 2, 'k3': 3, 'k4': 4}
E         Use -v to get more diff


https://docs.python.org/3.14/whatsnew/3.14.html

For the build logs, see:
https://copr-be.cloud.fedoraproject.org/results/@python/python3.14/fedora-rawhide-x86_64/08671078-python-orjson/

For all our attempts to build python-orjson with Python 3.14, see:
https://copr.fedorainfracloud.org/coprs/g/python/python3.14/package/python-orjson/

Testing and mass rebuild of packages is happening in copr.
You can follow these instructions to test locally in mock if your package builds with Python 3.14:
https://copr.fedorainfracloud.org/coprs/g/python/python3.14/

Let us know here if you have any questions.

Python 3.14 is planned to be included in Fedora 43.
To make that update smoother, we're building Fedora packages with all pre-releases of Python 3.14.
A build failure prevents us from testing all dependent packages (transitive [Build]Requires),
so if this package is required a lot, it's important for us to get it fixed soon.

We'd appreciate help from the people who know this package best,
but if you don't want to work on this now, let us know so we can try to work around it on our side.

Comment 1 Ben Beasley 2025-04-01 09:11:19 UTC
There is some potentially relevant upstream work in 3.10.16, https://github.com/ijl/orjson/releases/tag/3.10.16, bug 2354600. I should have a chance to try it out within the next week or so.

Comment 2 Ben Beasley 2025-04-03 11:29:05 UTC
Fixed upstream in 3.10.16.

Comment 3 Fedora Update System 2025-04-03 13:20:27 UTC
FEDORA-2025-a1b8663939 (python-orjson-3.10.16-1.fc43 and rust-itoap-1.0.1-7.fc43) has been submitted as an update to Fedora 43.
https://bodhi.fedoraproject.org/updates/FEDORA-2025-a1b8663939

Comment 4 Fedora Update System 2025-04-03 13:24:57 UTC
FEDORA-2025-a1b8663939 (python-orjson-3.10.16-1.fc43 and rust-itoap-1.0.1-7.fc43) has been pushed to the Fedora 43 stable repository.
If problem still persists, please make note of it in this bug report.

Comment 5 Fedora Update System 2025-04-03 14:09:09 UTC
FEDORA-2025-f147559b4f (python-orjson-3.10.16-1.fc42 and rust-itoap-1.0.1-7.fc42) has been submitted as an update to Fedora 42.
https://bodhi.fedoraproject.org/updates/FEDORA-2025-f147559b4f

Comment 6 Fedora Update System 2025-04-03 14:09:53 UTC
FEDORA-2025-5771d6e32e (python-orjson-3.10.16-1.fc41 and rust-itoap-1.0.1-7.fc41) has been submitted as an update to Fedora 41.
https://bodhi.fedoraproject.org/updates/FEDORA-2025-5771d6e32e

Comment 7 Fedora Update System 2025-04-03 14:12:13 UTC
FEDORA-2025-af0b2662cb (python-orjson-3.10.16-1.fc40 and rust-itoap-1.0.1-7.fc40) has been submitted as an update to Fedora 40.
https://bodhi.fedoraproject.org/updates/FEDORA-2025-af0b2662cb

Comment 8 Fedora Update System 2025-04-04 01:15:43 UTC
FEDORA-2025-af0b2662cb has been pushed to the Fedora 40 testing repository.
Soon you'll be able to install the update with the following command:
`sudo dnf upgrade --enablerepo=updates-testing --refresh --advisory=FEDORA-2025-af0b2662cb`
You can provide feedback for this update here: https://bodhi.fedoraproject.org/updates/FEDORA-2025-af0b2662cb

See also https://fedoraproject.org/wiki/QA:Updates_Testing for more information on how to test updates.

Comment 9 Fedora Update System 2025-04-04 01:24:29 UTC
FEDORA-2025-f147559b4f has been pushed to the Fedora 42 testing repository.
Soon you'll be able to install the update with the following command:
`sudo dnf upgrade --enablerepo=updates-testing --refresh --advisory=FEDORA-2025-f147559b4f`
You can provide feedback for this update here: https://bodhi.fedoraproject.org/updates/FEDORA-2025-f147559b4f

See also https://fedoraproject.org/wiki/QA:Updates_Testing for more information on how to test updates.

Comment 10 Fedora Update System 2025-04-04 02:21:33 UTC
FEDORA-2025-5771d6e32e has been pushed to the Fedora 41 testing repository.
Soon you'll be able to install the update with the following command:
`sudo dnf upgrade --enablerepo=updates-testing --refresh --advisory=FEDORA-2025-5771d6e32e`
You can provide feedback for this update here: https://bodhi.fedoraproject.org/updates/FEDORA-2025-5771d6e32e

See also https://fedoraproject.org/wiki/QA:Updates_Testing for more information on how to test updates.

Comment 11 Fedora Update System 2025-04-11 18:27:59 UTC
FEDORA-2025-f147559b4f (python-orjson-3.10.16-1.fc42 and rust-itoap-1.0.1-7.fc42) has been pushed to the Fedora 42 stable repository.
If problem still persists, please make note of it in this bug report.

Comment 12 Fedora Update System 2025-04-13 01:38:57 UTC
FEDORA-2025-5771d6e32e (python-orjson-3.10.16-1.fc41 and rust-itoap-1.0.1-7.fc41) has been pushed to the Fedora 41 stable repository.
If problem still persists, please make note of it in this bug report.

Comment 13 Fedora Update System 2025-04-13 01:42:28 UTC
FEDORA-2025-af0b2662cb (python-orjson-3.10.16-1.fc40 and rust-itoap-1.0.1-7.fc40) has been pushed to the Fedora 40 stable repository.
If problem still persists, please make note of it in this bug report.


Note You need to log in before you can comment on or make changes to this bug.