Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 28 additions & 21 deletions Doc/library/sys.rst
Original file line number Diff line number Diff line change
Expand Up @@ -729,34 +729,41 @@ always available.
implementation. For more details about hashing of numeric types, see
:ref:`numeric-hash`.

+---------------------+--------------------------------------------------+
| attribute | explanation |
+=====================+==================================================+
| :const:`width` | width in bits used for hash values |
+---------------------+--------------------------------------------------+
| :const:`modulus` | prime modulus P used for numeric hash scheme |
+---------------------+--------------------------------------------------+
| :const:`inf` | hash value returned for a positive infinity |
+---------------------+--------------------------------------------------+
| :const:`nan` | hash value returned for a nan |
+---------------------+--------------------------------------------------+
| :const:`imag` | multiplier used for the imaginary part of a |
| | complex number |
+---------------------+--------------------------------------------------+
| :const:`algorithm` | name of the algorithm for hashing of str, bytes, |
| | and memoryview |
+---------------------+--------------------------------------------------+
| :const:`hash_bits` | internal output size of the hash algorithm |
+---------------------+--------------------------------------------------+
| :const:`seed_bits` | size of the seed key of the hash algorithm |
+---------------------+--------------------------------------------------+
+------------------------+-----------------------------------------------+
| attribute | explanation |
+========================+===============================================+
| :const:`width` | width in bits used for hash values |
+------------------------+-----------------------------------------------+
| :const:`modulus` | prime modulus P used for numeric hash scheme |
+------------------------+-----------------------------------------------+
| :const:`inf` | hash value returned for a positive infinity |
+------------------------+-----------------------------------------------+
| :const:`nan` | hash value returned for a nan |
+------------------------+-----------------------------------------------+
| :const:`imag` | multiplier used for the imaginary part of a |
| | complex number |
+------------------------+-----------------------------------------------+
| :const:`algorithm` | name of the algorithm for hashing of str, |
| | bytes, and memoryview |
+------------------------+-----------------------------------------------+
| :const:`hash_bits` | internal output size of the hash algorithm |
+------------------------+-----------------------------------------------+
| :const:`seed_bits` | size of the seed key of the hash algorithm |
+------------------------+-----------------------------------------------+
| :const:`use_hash_seed` | Whether to use :envvar:`PYTHONHASHSEED` |
+------------------------+-----------------------------------------------+
| :const:`hash_seed` | The value from :envvar:`PYTHONHASHSEED` |

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At the C level, we need two fields, since it's not possible to distinguish "value set" to "value unset". But at the Python level, we can use None when the hash seed is unset.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems like the seed is always in the range [0; 4294967295], _Py_ReadHashSeed:

        if (*endptr != '\0'
            || seed > 4294967295UL
            || (errno == ERANGE && seed == ULONG_MAX))
        {
            return -1;
        }

It may be worth to document the value range.

+------------------------+-----------------------------------------------+


.. versionadded:: 3.2

.. versionchanged:: 3.4
Added *algorithm*, *hash_bits* and *seed_bits*

.. versionchanged:: 3.8
Added *use_hash_seed* and *hash_seed*


.. data:: hexversion

Expand Down
4 changes: 3 additions & 1 deletion Lib/test/test_sys.py
Original file line number Diff line number Diff line change
Expand Up @@ -427,7 +427,7 @@ def test_attributes(self):
self.assertEqual(type(sys.int_info.sizeof_digit), int)
self.assertIsInstance(sys.hexversion, int)

self.assertEqual(len(sys.hash_info), 9)
self.assertEqual(len(sys.hash_info), 11)
self.assertLess(sys.hash_info.modulus, 2**sys.hash_info.width)
# sys.hash_info.modulus should be a prime; we do a quick
# probable primality test (doesn't exclude the possibility of
Expand Down Expand Up @@ -458,6 +458,8 @@ def test_attributes(self):
self.assertEqual(algo, 0)
self.assertGreaterEqual(sys.hash_info.cutoff, 0)
self.assertLess(sys.hash_info.cutoff, 8)
self.assertIsInstance(sys.hash_info.use_hash_seed, bool)
self.assertIsInstance(sys.hash_info.hash_seed, int)

self.assertIsInstance(sys.maxsize, int)
self.assertIsInstance(sys.maxunicode, int)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Attributes ``use_hash_seed`` and ``hash_seed`` have been added to
``sys.hash_info``. These reflect the setting of the
:envvar:`PYTHONHASHSEED` environment variable.
10 changes: 9 additions & 1 deletion Python/sysmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -932,25 +932,29 @@ static PyStructSequence_Field hash_info_fields[] = {
{"hash_bits", "internal output size of hash algorithm"},
{"seed_bits", "seed size of hash algorithm"},
{"cutoff", "small string optimization cutoff"},
{"use_hash_seed", "whether the hash seed should be used or not"},
{"hash_seed", "the value of the hash seed"},
{NULL, NULL}
};

static PyStructSequence_Desc hash_info_desc = {
"sys.hash_info",
hash_info_doc,
hash_info_fields,
9,
11,
};

static PyObject *
get_hash_info(void)
{
_PyCoreConfig *core_config = &_PyGILState_GetInterpreterStateUnsafe()->core_config;
PyObject *hash_info;
int field = 0;
PyHash_FuncDef *hashfunc;
hash_info = PyStructSequence_New(&Hash_InfoType);
if (hash_info == NULL)
return NULL;

hashfunc = PyHash_GetFuncDef();
PyStructSequence_SET_ITEM(hash_info, field++,
PyLong_FromLong(8*sizeof(Py_hash_t)));
Expand All @@ -970,6 +974,10 @@ get_hash_info(void)
PyLong_FromLong(hashfunc->seed_bits));
PyStructSequence_SET_ITEM(hash_info, field++,
PyLong_FromLong(Py_HASH_CUTOFF));
PyStructSequence_SET_ITEM(hash_info, field++,
PyBool_FromLong(core_config->use_hash_seed));
PyStructSequence_SET_ITEM(hash_info, field++,
PyLong_FromLong(core_config->hash_seed));
if (PyErr_Occurred()) {
Py_CLEAR(hash_info);
return NULL;
Expand Down