0

I would like to get the same dictionary string for both Python 2.7 and Python 3.5 versions. I hardcoded PYTHONHASHSEED as below:

$ source ~/virtualenv/bin/activate
$ python --version
Python 2.7.12
$ PYTHONHASHSEED=0 python -c "print({'one':2,'two':3,'three':4})"
{'three': 4, 'two': 3, 'one': 2}
$ source ~/virtualenv-python3/bin/activate
$ python --version
Python 3.5.2
$ PYTHONHASHSEED=0 python -c "print({'one':2,'two':3,'three':4})"
{'two': 3, 'three': 4, 'one': 2}

Why these two invocations result with different output? Is there any way to find PYTHONHASHSEEDs values giving the same results for both Python 2.7 and Python 3.5?

UPDATE

My real case:

encoding_case.py

import base64
import json


def sth_to_call(b64_of_dict):
    raise NotImplementedError(
        'This is simulation of independent resources '
        'and this should be mocked. That is why I am raising otherwise.'
    )


def f(**kwargs):
    sth_to_call(base64.b64encode(json.dumps(kwargs).encode()))

test_encoding_case.py

import mock
import unittest

import encoding_case


class EncodingCaseTest(unittest.TestCase):
    @mock.patch('encoding_case.sth_to_call')
    def test_f(self, sth_to_call_mock):
        encoding_case.f(**{'one': 2, 'two': 3, 'three': 4})
        sth_to_call_mock\
            .assert_called_with(b'eyJ0d28iOiAzLCAidGhyZWUiOiA0LCAib25lIjogMn0=')

Fails after invocation of PYTHONHASHSEED=0 nosetests test_encoding_case under Python 2.7 with error:

AssertionError: Expected call: sth_to_call('eyJ0d28iOiAzLCAidGhyZWUiOiA0LCAib25lIjogMn0=')
Actual call: sth_to_call('eyJvbmUiOiAyLCAidGhyZWUiOiA0LCAidHdvIjogM30=')

The same invocation under Python 3.5 results with test passing.

pt12lol
  • 2,332
  • 1
  • 22
  • 48
  • Why would you want this ? Testing ? dumping your dicts as json and reloading them from json should solve the problem. – bruno desthuilliers Nov 10 '17 at 11:59
  • Yup, testing. Unfortunately I have function resulting with `base64` and other encodings and compressions applied on a dictionary, so casting to json does not fix it. Even if setting `PYTHONHASHSEED` does not make sense, alternative solutions are welcome, but still it would be nice to understand the issue. – pt12lol Nov 10 '17 at 12:04
  • 1
    Dict's ordering is implementation dependant and can vary even between minor versions (FWIW it could even vary according to the platform, compiler flags, insertion order, phases of the moon or whatever), so you just __cannot__ rely on the string representation for testing. But note that a `dict` is mainly a sequence of `(key, value)` pairs (with a unicity constraint on pairs) and the translation from one representation to the other is trivial (`lst = list(mydict.iteritems())` -> `mydict = dict(lst)`) so you could possibly use a (sorted) list instead of a dict? – bruno desthuilliers Nov 10 '17 at 12:13
  • 2
    But I think you'll have to give more context about your _real_ problem... – bruno desthuilliers Nov 10 '17 at 12:14
  • Possible duplicate of [Equivalent to python's -R option that affects the hash of ints](https://stackoverflow.com/questions/44324494/equivalent-to-pythons-r-option-that-affects-the-hash-of-ints) – Chris_Rands Nov 10 '17 at 12:21
  • @brunodesthuilliers provided to the question my real test case. – pt12lol Nov 10 '17 at 13:00

0 Answers0