Skip to content
Merged
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
23 changes: 19 additions & 4 deletions Doc/library/enum.rst
Original file line number Diff line number Diff line change
Expand Up @@ -504,16 +504,31 @@ Data Types

.. class:: StrEnum

``StrEnum`` is the same as :class:`Enum`, but its members are also strings and can be used
in most of the same places that a string can be used. The result of any string
operation performed on or with a *StrEnum* member is not part of the enumeration.
*StrEnum* is the same as :class:`Enum`, but its members are also strings and
can be used in most of the same places that a string can be used. The result
of any string operation performed on or with a *StrEnum* member is not part
of the enumeration.

>>> from enum import StrEnum, auto
>>> class Color(StrEnum):
... RED = 'r'
... GREEN = 'g'
... BLUE = 'b'
... UNKNOWN = auto()
...
>>> Color.RED
<Color.RED: 'r'>
>>> Color.UNKNOWN
<Color.UNKNOWN: 'unknown'>
>>> str(Color.UNKNOWN)
'unknown'

.. note::

There are places in the stdlib that check for an exact :class:`str`
instead of a :class:`str` subclass (i.e. ``type(unknown) == str``
instead of ``isinstance(unknown, str)``), and in those locations you
will need to use ``str(StrEnum.member)``.
will need to use ``str(MyStrEnum.MY_MEMBER)``.

.. note::

Expand Down
7 changes: 5 additions & 2 deletions Doc/library/sys.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2191,8 +2191,11 @@ always available. Unless explicitly noted otherwise, all variables are read-only

.. data:: api_version

The C API version for this interpreter. Programmers may find this useful when
debugging version conflicts between Python and extension modules.
The C API version, equivalent to the C macro :c:macro:`PYTHON_API_VERSION`.
Defined for backwards compatibility.

Currently, this constant is not updated in new Python versions, and is not
useful for versioning. This may change in the future.


.. data:: version_info
Expand Down
4 changes: 2 additions & 2 deletions Doc/tutorial/modules.rst
Original file line number Diff line number Diff line change
Expand Up @@ -579,8 +579,8 @@ module for example, you might use::
from .. import formats
from ..filters import equalizer

Note that relative imports are based on the name of the current module. Since
the name of the main module is always ``"__main__"``, modules intended for use
Note that relative imports are based on the name of the current module's package.
Since the main module does not have a package, modules intended for use
as the main module of a Python application must always use absolute imports.


Expand Down
44 changes: 44 additions & 0 deletions Lib/test/test_free_threading/test_syslog.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import unittest
import threading

from test.support import import_helper, threading_helper
from test.support.threading_helper import run_concurrently

syslog = import_helper.import_module("syslog")

NTHREADS = 32

# Similar to Lib/test/test_syslog.py, this test's purpose is to verify that
# the code neither crashes nor leaks.


@threading_helper.requires_working_threading()
class TestSyslog(unittest.TestCase):
def test_racing_syslog(self):
def worker():
"""
The syslog module provides the following functions:
openlog(), syslog(), closelog(), and setlogmask().
"""
thread_id = threading.get_ident()
syslog.openlog(f"thread-id: {thread_id}")
try:
for _ in range(5):
syslog.syslog("logline")
syslog.setlogmask(syslog.LOG_MASK(syslog.LOG_INFO))
syslog.syslog(syslog.LOG_INFO, "logline LOG_INFO")
syslog.setlogmask(syslog.LOG_MASK(syslog.LOG_ERR))
syslog.syslog(syslog.LOG_ERR, "logline LOG_ERR")
syslog.setlogmask(syslog.LOG_UPTO(syslog.LOG_DEBUG))
finally:
syslog.closelog()

# Run the worker concurrently to exercise all these syslog functions
run_concurrently(
worker_func=worker,
nthreads=NTHREADS,
)


if __name__ == "__main__":
unittest.main()
2 changes: 1 addition & 1 deletion Lib/test/test_generated_cases.py
Original file line number Diff line number Diff line change
Expand Up @@ -2037,7 +2037,7 @@ def test_missing_override_failure(self):
"""
output = """
"""
with self.assertRaisesRegex(AssertionError, "All abstract uops"):
with self.assertRaisesRegex(ValueError, "All abstract uops"):
self.run_cases_test(input, input2, output)

def test_validate_uop_input_length_mismatch(self):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Make functions in :mod:`syslog` thread-safe on the :term:`free threaded
<free threading>` build.
8 changes: 7 additions & 1 deletion Modules/syslogmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,13 @@ syslog_setlogmask_impl(PyObject *module, long maskpri)
return -1;
}

return setlogmask(maskpri);
static PyMutex setlogmask_mutex = {0};
PyMutex_Lock(&setlogmask_mutex);
// Linux man page (3): setlogmask() is MT-Unsafe race:LogMask.
long previous_mask = setlogmask(maskpri);
PyMutex_Unlock(&setlogmask_mutex);

return previous_mask;
}

/*[clinic input]
Expand Down
6 changes: 3 additions & 3 deletions Tools/cases_generator/optimizer_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -398,9 +398,9 @@ def generate_abstract_interpreter(
out.emit("\n")
base_uop_names = set([uop.name for uop in base.uops.values()])
for abstract_uop_name in abstract.uops:
assert (
abstract_uop_name in base_uop_names
), f"All abstract uops should override base uops, but {abstract_uop_name} is not."
if abstract_uop_name not in base_uop_names:
raise ValueError(f"All abstract uops should override base uops, "
"but {abstract_uop_name} is not.")

for uop in base.uops.values():
override: Uop | None = None
Expand Down
Loading