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
20 changes: 20 additions & 0 deletions Doc/library/math.rst
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ noted otherwise, all return values are floats.
:func:`frexp(x) <frexp>` Mantissa and exponent of *x*
:func:`isclose(a, b, rel_tol, abs_tol) <isclose>` Check if the values *a* and *b* are close to each other
:func:`isfinite(x) <isfinite>` Check if *x* is neither an infinity nor a NaN
:func:`isnormal(x) <isnormal>` Check if *x* is a normal number
:func:`issubnormal(x) <issubnormal>` Check if *x* is a subnormal number
:func:`isinf(x) <isinf>` Check if *x* is a positive or negative infinity
:func:`isnan(x) <isnan>` Check if *x* is a NaN (not a number)
:func:`ldexp(x, i) <ldexp>` ``x * (2**i)``, inverse of function :func:`frexp`
Expand Down Expand Up @@ -373,6 +375,24 @@ Floating point manipulation functions
.. versionadded:: 3.2


.. function:: isnormal(x)

Return ``True`` if *x* is a normal number, that is a finite
nonzero number that is not a subnormal (see :func:`issubnormal`).
Return ``False`` otherwise.

.. versionadded:: next


.. function:: issubnormal(x)

Return ``True`` if *x* is a subnormal number, that is a finite
nonzero number with a magnitude smaller than the smallest positive normal
number, see :data:`sys.float_info.min`. Return ``False`` otherwise.

.. versionadded:: next


.. function:: isinf(x)

Return ``True`` if *x* is a positive or negative infinity, and
Expand Down
6 changes: 3 additions & 3 deletions Doc/library/socket.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1492,7 +1492,7 @@ The :mod:`socket` module also offers various network-related services:
The *fds* parameter is a sequence of file descriptors.
Consult :meth:`~socket.sendmsg` for the documentation of these parameters.

.. availability:: Unix, Windows, not WASI.
.. availability:: Unix, not WASI.

Unix platforms supporting :meth:`~socket.sendmsg`
and :const:`SCM_RIGHTS` mechanism.
Expand All @@ -1506,9 +1506,9 @@ The :mod:`socket` module also offers various network-related services:
Return ``(msg, list(fds), flags, addr)``.
Consult :meth:`~socket.recvmsg` for the documentation of these parameters.

.. availability:: Unix, Windows, not WASI.
.. availability:: Unix, not WASI.

Unix platforms supporting :meth:`~socket.sendmsg`
Unix platforms supporting :meth:`~socket.recvmsg`
and :const:`SCM_RIGHTS` mechanism.

.. versionadded:: 3.9
Expand Down
2 changes: 1 addition & 1 deletion Doc/library/string.rst
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,7 @@ The general form of a *standard format specifier* is:
sign: "+" | "-" | " "
width_and_precision: [`width_with_grouping`][`precision_with_grouping`]
width_with_grouping: [`width`][`grouping`]
precision_with_grouping: "." [`precision`][`grouping`]
precision_with_grouping: "." [`precision`][`grouping`] | "." `grouping`
width: `~python-grammar:digit`+
precision: `~python-grammar:digit`+
grouping: "," | "_"
Expand Down
2 changes: 1 addition & 1 deletion Doc/whatsnew/3.14.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1454,7 +1454,7 @@ math
----

* Added more detailed error messages for domain errors in the module.
(Contributed by by Charlie Zhao and Sergey B Kirpichev in :gh:`101410`.)
(Contributed by Charlie Zhao and Sergey B Kirpichev in :gh:`101410`.)


mimetypes
Expand Down
7 changes: 7 additions & 0 deletions Doc/whatsnew/3.15.rst
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,13 @@ difflib
(Contributed by Jiahao Li in :gh:`134580`.)


math
----

* Add :func:`math.isnormal` and :func:`math.issubnormal` functions.
(Contributed by Sergey B Kirpichev in :gh:`132908`.)


shelve
------

Expand Down
4 changes: 2 additions & 2 deletions Lib/_pydecimal.py
Original file line number Diff line number Diff line change
Expand Up @@ -6120,9 +6120,9 @@ def _convert_for_comparison(self, other, equality_op=False):
(?P<no_neg_0>z)?
(?P<alt>\#)?
(?P<zeropad>0)?
(?P<minimumwidth>(?!0)\d+)?
(?P<minimumwidth>\d+)?
(?P<thousands_sep>[,_])?
(?:\.(?P<precision>0|(?!0)\d+))?
(?:\.(?P<precision>\d+))?
(?P<type>[eEfFgGn%])?
\z
""", re.VERBOSE|re.DOTALL)
Expand Down
4 changes: 2 additions & 2 deletions Lib/fractions.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,9 +168,9 @@ def _round_to_figures(n, d, figures):
# A '0' that's *not* followed by another digit is parsed as a minimum width
# rather than a zeropad flag.
(?P<zeropad>0(?=[0-9]))?
(?P<minimumwidth>0|[1-9][0-9]*)?
(?P<minimumwidth>[0-9]+)?
(?P<thousands_sep>[,_])?
(?:\.(?P<precision>0|[1-9][0-9]*))?
(?:\.(?P<precision>[0-9]+))?
(?P<presentation_type>[eEfFgG%])
""", re.DOTALL | re.VERBOSE).fullmatch

Expand Down
9 changes: 9 additions & 0 deletions Lib/test/test_asyncgen.py
Original file line number Diff line number Diff line change
Expand Up @@ -2021,6 +2021,15 @@ async def gen():
g.athrow(RuntimeError)
gc_collect()

def test_athrow_throws_immediately(self):
async def gen():
yield 1

g = gen()
msg = "athrow expected at least 1 argument, got 0"
with self.assertRaisesRegex(TypeError, msg):
g.athrow()

def test_aclose(self):
async def gen():
yield 1
Expand Down
2 changes: 2 additions & 0 deletions Lib/test/test_decimal.py
Original file line number Diff line number Diff line change
Expand Up @@ -981,6 +981,7 @@ def test_formatting(self):
('.0f', '0e-2', '0'),
('.0f', '3.14159265', '3'),
('.1f', '3.14159265', '3.1'),
('.01f', '3.14159265', '3.1'), # leading zero in precision
('.4f', '3.14159265', '3.1416'),
('.6f', '3.14159265', '3.141593'),
('.7f', '3.14159265', '3.1415926'), # round-half-even!
Expand Down Expand Up @@ -1066,6 +1067,7 @@ def test_formatting(self):
('8,', '123456', ' 123,456'),
('08,', '123456', '0,123,456'), # special case: extra 0 needed
('+08,', '123456', '+123,456'), # but not if there's a sign
('008,', '123456', '0,123,456'), # leading zero in width
(' 08,', '123456', ' 123,456'),
('08,', '-123456', '-123,456'),
('+09,', '123456', '+0,123,456'),
Expand Down
8 changes: 2 additions & 6 deletions Lib/test/test_fractions.py
Original file line number Diff line number Diff line change
Expand Up @@ -1518,6 +1518,8 @@ def test_format_f_presentation_type(self):
(F(51, 1000), '.1f', '0.1'),
(F(149, 1000), '.1f', '0.1'),
(F(151, 1000), '.1f', '0.2'),
(F(22, 7), '.02f', '3.14'), # issue gh-130662
(F(22, 7), '005.02f', '03.14'),
]
for fraction, spec, expected in testcases:
with self.subTest(fraction=fraction, spec=spec):
Expand Down Expand Up @@ -1616,12 +1618,6 @@ def test_invalid_formats(self):
'=010%',
'>00.2f',
'>00f',
# Too many zeros - minimum width should not have leading zeros
'006f',
# Leading zeros in precision
'.010f',
'.02f',
'.000f',
# Missing precision
'.e',
'.f',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import unittest
from threading import Thread, Barrier
from itertools import batched
from itertools import batched, cycle
from test.support import threading_helper


threading_helper.requires_working_threading(module=True)

class EnumerateThreading(unittest.TestCase):
class ItertoolsThreading(unittest.TestCase):

@threading_helper.reap_threads
def test_threading(self):
def test_batched(self):
number_of_threads = 10
number_of_iterations = 20
barrier = Barrier(number_of_threads)
Expand All @@ -34,5 +34,31 @@ def work(it):

barrier.reset()

@threading_helper.reap_threads
def test_cycle(self):
number_of_threads = 6
number_of_iterations = 10
number_of_cycles = 400

barrier = Barrier(number_of_threads)
def work(it):
barrier.wait()
for _ in range(number_of_cycles):
_ = next(it)

data = (1, 2, 3, 4)
for it in range(number_of_iterations):
cycle_iterator = cycle(data)
worker_threads = []
for ii in range(number_of_threads):
worker_threads.append(
Thread(target=work, args=[cycle_iterator]))

with threading_helper.start_threads(worker_threads):
pass

barrier.reset()


if __name__ == "__main__":
unittest.main()
22 changes: 22 additions & 0 deletions Lib/test/test_math.py
Original file line number Diff line number Diff line change
Expand Up @@ -1973,6 +1973,28 @@ def testIsfinite(self):
self.assertFalse(math.isfinite(float("inf")))
self.assertFalse(math.isfinite(float("-inf")))

def testIsnormal(self):
self.assertTrue(math.isnormal(1.25))
self.assertTrue(math.isnormal(-1.0))
self.assertFalse(math.isnormal(0.0))
self.assertFalse(math.isnormal(-0.0))
self.assertFalse(math.isnormal(INF))
self.assertFalse(math.isnormal(NINF))
self.assertFalse(math.isnormal(NAN))
self.assertFalse(math.isnormal(FLOAT_MIN/2))
self.assertFalse(math.isnormal(-FLOAT_MIN/2))

def testIssubnormal(self):
self.assertFalse(math.issubnormal(1.25))
self.assertFalse(math.issubnormal(-1.0))
self.assertFalse(math.issubnormal(0.0))
self.assertFalse(math.issubnormal(-0.0))
self.assertFalse(math.issubnormal(INF))
self.assertFalse(math.issubnormal(NINF))
self.assertFalse(math.issubnormal(NAN))
self.assertTrue(math.issubnormal(FLOAT_MIN/2))
self.assertTrue(math.issubnormal(-FLOAT_MIN/2))

def testIsnan(self):
self.assertTrue(math.isnan(float("nan")))
self.assertTrue(math.isnan(float("-nan")))
Expand Down
11 changes: 11 additions & 0 deletions Lib/test/test_pyrepl/test_pyrepl.py
Original file line number Diff line number Diff line change
Expand Up @@ -1672,6 +1672,17 @@ def test_null_byte(self):
self.assertEqual(exit_code, 0)
self.assertNotIn("TypeError", output)

@force_not_colorized
def test_non_string_suggestion_candidates(self):
commands = ("import runpy\n"
"runpy._run_module_code('blech', {0: '', 'bluch': ''}, '')\n"
"exit()\n")

output, exit_code = self.run_repl(commands)
self.assertEqual(exit_code, 0)
self.assertNotIn("all elements in 'candidates' must be strings", output)
self.assertIn("bluch", output)

def test_readline_history_file(self):
# skip, if readline module is not available
readline = import_module('readline')
Expand Down
29 changes: 27 additions & 2 deletions Lib/test/test_traceback.py
Original file line number Diff line number Diff line change
Expand Up @@ -4188,6 +4188,15 @@ def __dir__(self):
self.assertNotIn("blech", actual)
self.assertNotIn("oh no!", actual)

def test_attribute_error_with_non_string_candidates(self):
class T:
bluch = 1

instance = T()
instance.__dict__[0] = 1
actual = self.get_suggestion(instance, 'blich')
self.assertIn("bluch", actual)

def test_attribute_error_with_bad_name(self):
def raise_attribute_error_with_bad_name():
raise AttributeError(name=12, obj=23)
Expand Down Expand Up @@ -4223,8 +4232,8 @@ def make_module(self, code):

return mod_name

def get_import_from_suggestion(self, mod_dict, name):
modname = self.make_module(mod_dict)
def get_import_from_suggestion(self, code, name):
modname = self.make_module(code)

def callable():
try:
Expand Down Expand Up @@ -4301,6 +4310,13 @@ def test_import_from_suggestions_underscored(self):
self.assertIn("'_bluch'", self.get_import_from_suggestion(code, '_luch'))
self.assertNotIn("'_bluch'", self.get_import_from_suggestion(code, 'bluch'))

def test_import_from_suggestions_non_string(self):
modWithNonStringAttr = textwrap.dedent("""\
globals()[0] = 1
bluch = 1
""")
self.assertIn("'bluch'", self.get_import_from_suggestion(modWithNonStringAttr, 'blech'))

def test_import_from_suggestions_do_not_trigger_for_long_attributes(self):
code = "blech = None"

Expand Down Expand Up @@ -4397,6 +4413,15 @@ def func():
actual = self.get_suggestion(func)
self.assertIn("'ZeroDivisionError'?", actual)

def test_name_error_suggestions_with_non_string_candidates(self):
def func():
abc = 1
custom_globals = globals().copy()
custom_globals[0] = 1
print(eval("abv", custom_globals, locals()))
actual = self.get_suggestion(func)
self.assertIn("abc", actual)

def test_name_error_suggestions_do_not_trigger_for_long_names(self):
def func():
somethingverywronghehehehehehe = None
Expand Down
13 changes: 11 additions & 2 deletions Lib/traceback.py
Original file line number Diff line number Diff line change
Expand Up @@ -1595,7 +1595,11 @@ def _compute_suggestion_error(exc_value, tb, wrong_name):
if isinstance(exc_value, AttributeError):
obj = exc_value.obj
try:
d = dir(obj)
try:
d = dir(obj)
except TypeError: # Attributes are unsortable, e.g. int and str
d = list(obj.__class__.__dict__.keys()) + list(obj.__dict__.keys())
d = sorted([x for x in d if isinstance(x, str)])
hide_underscored = (wrong_name[:1] != '_')
if hide_underscored and tb is not None:
while tb.tb_next is not None:
Expand All @@ -1610,7 +1614,11 @@ def _compute_suggestion_error(exc_value, tb, wrong_name):
elif isinstance(exc_value, ImportError):
try:
mod = __import__(exc_value.name)
d = dir(mod)
try:
d = dir(mod)
except TypeError: # Attributes are unsortable, e.g. int and str
d = list(mod.__dict__.keys())
d = sorted([x for x in d if isinstance(x, str)])
if wrong_name[:1] != '_':
d = [x for x in d if x[:1] != '_']
except Exception:
Expand All @@ -1628,6 +1636,7 @@ def _compute_suggestion_error(exc_value, tb, wrong_name):
+ list(frame.f_globals)
+ list(frame.f_builtins)
)
d = [x for x in d if isinstance(x, str)]

# Check first if we are in a method and the instance
# has the wrong name as attribute
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix argument checking of :meth:`~agen.athrow`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Avoid exiting the new REPL and offer suggestions even if there are non-string
candidates when errors occur.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Make concurrent iterations over :class:`itertools.cycle` safe under free-threading.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Add :func:`math.isnormal` and :func:`math.issubnormal` functions. Patch by
Sergey B Kirpichev.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Accept leading zeros in precision and width fields for
:class:`~fractions.Fraction` formatting, for example ``format(Fraction(1,
3), '.016f')``.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
+Accept leading zeros in precision and width fields for
+:class:`~decimal.Decimal` formatting, for example ``format(Decimal(1.25),
'.016f')``.
Loading
Loading