summaryrefslogtreecommitdiffstats
path: root/Lib/test/test_pow.py
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/test/test_pow.py')
-rw-r--r--Lib/test/test_pow.py4
1 files changed, 2 insertions, 2 deletions
diff --git a/Lib/test/test_pow.py b/Lib/test/test_pow.py
index 859c373..60bb533 100644
--- a/Lib/test/test_pow.py
+++ b/Lib/test/test_pow.py
@@ -18,14 +18,14 @@ class PowTest(unittest.TestCase):
self.assertEquals(pow(2, i), pow2)
if i != 30 : pow2 = pow2*2
- for othertype in int, int:
+ for othertype in (int,):
for i in list(range(-10, 0)) + list(range(1, 10)):
ii = type(i)
for j in range(1, 11):
jj = -othertype(j)
pow(ii, jj)
- for othertype in int, int, float:
+ for othertype in int, float:
for i in range(1, 100):
zero = type(0)
exp = -othertype(i/10.0)
test/test_float.py?h=v3.12.0&id=a721abac299bb6529021000a71847486d531b41a'>Lib/test/test_float.py24
-rw-r--r--Lib/test/test_grammar.py89
-rw-r--r--Lib/test/test_int.py21
-rw-r--r--Lib/test/test_tokenize.py30
-rw-r--r--Lib/test/test_types.py1
-rw-r--r--Lib/tokenize.py17
-rw-r--r--Misc/NEWS6
-rw-r--r--Modules/_decimal/_decimal.c12
-rw-r--r--Objects/complexobject.c63
-rw-r--r--Objects/floatobject.c59
-rw-r--r--Objects/longobject.c169
-rw-r--r--Parser/tokenizer.c230
-rw-r--r--Python/ast.c27
-rw-r--r--Python/pystrtod.c66
22 files changed, 742 insertions, 204 deletions
diff --git a/Doc/library/decimal.rst b/Doc/library/decimal.rst
index ee746e9..e984edc 100644
--- a/Doc/library/decimal.rst
+++ b/Doc/library/decimal.rst
@@ -345,7 +345,7 @@ Decimal objects
*value* can be an integer, string, tuple, :class:`float`, or another :class:`Decimal`
object. If no *value* is given, returns ``Decimal('0')``. If *value* is a
string, it should conform to the decimal numeric string syntax after leading
- and trailing whitespace characters are removed::
+ and trailing whitespace characters, as well as underscores throughout, are removed::
sign ::= '+' | '-'
digit ::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'
@@ -394,6 +394,10 @@ Decimal objects
:class:`float` arguments raise an exception if the :exc:`FloatOperation`
trap is set. By default the trap is off.
+ .. versionchanged:: 3.6
+ Underscores are allowed for grouping, as with integral and floating-point
+ literals in code.
+
Decimal floating point objects share many properties with the other built-in
numeric types such as :class:`float` and :class:`int`. All of the usual math
operations and special methods apply. Likewise, decimal objects can be
@@ -1075,8 +1079,8 @@ In addition to the three supplied contexts, new contexts can be created with the
Decimal('4.44')
This method implements the to-number operation of the IBM specification.
- If the argument is a string, no leading or trailing whitespace is
- permitted.
+ If the argument is a string, no leading or trailing whitespace or
+ underscores are permitted.
.. method:: create_decimal_from_float(f)
diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst
index db04b10..c4fcd98 100644
--- a/Doc/library/functions.rst
+++ b/Doc/library/functions.rst
@@ -271,6 +271,9 @@ are always available. They are listed here in alphabetical order.
The complex type is described in :ref:`typesnumeric`.
+ .. versionchanged:: 3.6
+ Grouping digits with underscores as in code literals is allowed.
+
.. function:: delattr(object, name)
@@ -531,11 +534,14 @@ are always available. They are listed here in alphabetical order.
The float type is described in :ref:`typesnumeric`.
- .. index::
- single: __format__
- single: string; format() (built-in function)
+ .. versionchanged:: 3.6
+ Grouping digits with underscores as in code literals is allowed.
+.. index::
+ single: __format__
+ single: string; format() (built-in function)
+
.. function:: format(value[, format_spec])
Convert a *value* to a "formatted" representation, as controlled by
@@ -702,6 +708,10 @@ are always available. They are listed here in alphabetical order.
:meth:`base.__int__ <object.__int__>` instead of :meth:`base.__index__
<object.__index__>`.
+ .. versionchanged:: 3.6
+ Grouping digits with underscores as in code literals is allowed.
+
+
.. function:: isinstance(object, classinfo)
Return true if the *object* argument is an instance of the *classinfo*
diff --git a/Doc/reference/lexical_analysis.rst b/Doc/reference/lexical_analysis.rst
index 48f2043..a7c6a68 100644
--- a/Doc/reference/lexical_analysis.rst
+++ b/Doc/reference/lexical_analysis.rst
@@ -721,20 +721,24 @@ Integer literals
Integer literals are described by the following lexical definitions:
.. productionlist::
- integer: `decimalinteger` | `octinteger` | `hexinteger` | `bininteger`
- decimalinteger: `nonzerodigit` `digit`* | "0"+
+ integer: `decinteger` | `bininteger` | `octinteger` | `hexinteger`
+ decinteger: `nonzerodigit` (["_"] `digit`)* | "0"+ (["_"] "0")*
+ bininteger: "0" ("b" | "B") (["_"] `bindigit`)+
+ octinteger: "0" ("o" | "O") (["_"] `octdigit`)+
+ hexinteger: "0" ("x" | "X") (["_"] `hexdigit`)+
nonzerodigit: "1"..."9"
digit: "0"..."9"
- octinteger: "0" ("o" | "O") `octdigit`+
- hexinteger: "0" ("x" | "X") `hexdigit`+
- bininteger: "0" ("b" | "B") `bindigit`+
+ bindigit: "0" | "1"
octdigit: "0"..."7"
hexdigit: `digit` | "a"..."f" | "A"..."F"
- bindigit: "0" | "1"
There is no limit for the length of integer literals apart from what can be
stored in available memory.
+Underscores are ignored for determining the numeric value of the literal. They
+can be used to group digits for enhanced readability. One underscore can occur
+between digits, and after base specifiers like ``0x``.
+
Note that leading zeros in a non-zero decimal number are not allowed. This is
for disambiguation with C-style octal literals, which Python used before version
3.0.
@@ -743,6 +747,10 @@ Some examples of integer literals::
7 2147483647 0o177 0b100110111
3 79228162514264337593543950336 0o377 0xdeadbeef
+ 100_000_000_000 0b_1110_0101
+
+.. versionchanged:: 3.6
+ Underscores are now allowed for grouping purposes in literals.
.. _floating:
@@ -754,23 +762,28 @@ Floating point literals are described by the following lexical definitions:
.. productionlist::
floatnumber: `pointfloat` | `exponentfloat`
- pointfloat: [`intpart`] `fraction` | `intpart` "."
- exponentfloat: (`intpart` | `pointfloat`) `exponent`
- intpart: `digit`+
- fraction: "." `digit`+
- exponent: ("e" | "E") ["+" | "-"] `digit`+
+ pointfloat: [`digitpart`] `fraction` | `digitpart` "."
+ exponentfloat: (`digitpart` | `pointfloat`) `exponent`
+ digitpart: `digit` (["_"] `digit`)*
+ fraction: "." `digitpart`
+ exponent: ("e" | "E") ["+" | "-"] `digitpart`
Note that the integer and exponent parts are always interpreted using radix 10.
For example, ``077e010`` is legal, and denotes the same number as ``77e10``. The
-allowed range of floating point literals is implementation-dependent. Some
-examples of floating point literals::
+allowed range of floating point literals is implementation-dependent. As in
+integer literals, underscores are supported for digit grouping.
+
+Some examples of floating point literals::
- 3.14 10. .001 1e100 3.14e-10 0e0
+ 3.14 10. .001 1e100 3.14e-10 0e0 3.14_15_93
Note that numeric literals do not include a sign; a phrase like ``-1`` is
actually an expression composed of the unary operator ``-`` and the literal
``1``.
+.. versionchanged:: 3.6
+ Underscores are now allowed for grouping purposes in literals.
+
.. _imaginary:
@@ -780,7 +793,7 @@ Imaginary literals
Imaginary literals are described by the following lexical definitions:
.. productionlist::
- imagnumber: (`floatnumber` | `intpart`) ("j" | "J")
+ imagnumber: (`floatnumber` | `digitpart`) ("j" | "J")
An imaginary literal yields a complex number with a real part of 0.0. Complex
numbers are represented as a pair of floating point numbers and have the same
@@ -788,7 +801,7 @@ restrictions on their range. To create a complex number with a nonzero real
part, add a floating point number to it, e.g., ``(3+4j)``. Some examples of
imaginary literals::
- 3.14j 10.j 10j .001j 1e100j 3.14e-10j
+ 3.14j 10.j 10j .001j 1e100j 3.14e-10j 3.14_15_93j
.. _operators:
diff --git a/Doc/whatsnew/3.6.rst b/Doc/whatsnew/3.6.rst
index f15bf4d..9a16486 100644
--- a/Doc/whatsnew/3.6.rst
+++ b/Doc/whatsnew/3.6.rst
@@ -124,6 +124,29 @@ Windows improvements:
New Features
============
+.. _pep-515:
+
+PEP 515: Underscores in Numeric Literals
+========================================
+
+Prior to PEP 515, there was no support for writing long numeric
+literals with some form of separator to improve readability. For
+instance, how big is ``1000000000000000```? With :pep:`515`, though,
+you can use underscores to separate digits as desired to make numeric
+literals easier to read: ``1_000_000_000_000_000``. Underscores can be
+used with other numeric literals beyond integers, e.g.
+``0x_FF_FF_FF_FF``.
+
+Single underscores are allowed between digits and after any base
+specifier. More than a single underscore in a row, leading, or
+trailing underscores are not allowed.
+
+.. seealso::
+
+ :pep:`523` - Underscores in Numeric Literals
+ PEP written by Georg Brandl & Serhiy Storchaka.
+
+
.. _pep-523:
PEP 523: Adding a frame evaluation API to CPython
diff --git a/Include/pystrtod.h b/Include/pystrtod.h
index 23fd1c6..c1e84de 100644
--- a/Include/pystrtod.h
+++ b/Include/pystrtod.h
@@ -19,6 +19,10 @@ PyAPI_FUNC(char *) PyOS_double_to_string(double val,
int *type);
#ifndef Py_LIMITED_API
+PyAPI_FUNC(PyObject *) _Py_string_to_number_with_underscores(
+ const char *str, Py_ssize_t len, const char *what, PyObject *obj, void *arg,
+ PyObject *(*innerfunc)(const char *, Py_ssize_t, void *));
+
PyAPI_FUNC(double) _Py_parse_inf_or_nan(const char *p, char **endptr);
#endif
diff --git a/Lib/_pydecimal.py b/Lib/_pydecimal.py
index 21e875c..6318a49 100644
--- a/Lib/_pydecimal.py
+++ b/Lib/_pydecimal.py
@@ -589,7 +589,7 @@ class Decimal(object):
# From a string
# REs insist on real strings, so we can too.
if isinstance(value, str):
- m = _parser(value.strip())
+ m = _parser(value.strip().replace("_", ""))
if m is None:
if context is None:
context = getcontext()
@@ -4125,7 +4125,7 @@ class Context(object):
This will make it round up for that operation.
"""
rounding = self.rounding
- self.rounding= type
+ self.rounding = type
return rounding
def create_decimal(self, num='0'):
@@ -4134,10 +4134,10 @@ class Context(object):
This method implements the to-number operation of the
IBM Decimal specification."""
- if isinstance(num, str) and num != num.strip():
+ if isinstance(num, str) and (num != num.strip() or '_' in num):
return self._raise_error(ConversionSyntax,
- "no trailing or leading whitespace is "
- "permitted.")
+ "trailing or leading whitespace and "
+ "underscores are not permitted.")
d = Decimal(num, context=self)
if d._isnan() and len(d._int) > self.prec - self.clamp:
diff --git a/Lib/test/test_complex.py b/Lib/test/test_complex.py
index 0ef9a7a..6633a7a 100644
--- a/Lib/test/test_complex.py
+++ b/Lib/test/test_complex.py
@@ -1,5 +1,7 @@
import unittest
from test import support
+from test.test_grammar import (VALID_UNDERSCORE_LITERALS,
+ INVALID_UNDERSCORE_LITERALS)
from random import random
from math import atan2, isnan, copysign
@@ -377,6 +379,18 @@ class ComplexTest(unittest.TestCase):
self.assertAlmostEqual(complex(complex1(1j)), 2j)
self.assertRaises(TypeError, complex, complex2(1j))
+ def test_underscores(self):
+ # check underscores
+ for lit in VALID_UNDERSCORE_LITERALS:
+ if not any(ch in lit for ch in 'xXoObB'):
+ self.assertEqual(complex(lit), eval(lit))
+ self.assertEqual(complex(lit), complex(lit.replace('_', '')))
+ for lit in INVALID_UNDERSCORE_LITERALS:
+ if lit in ('0_7', '09_99'): # octals are not recognized here
+ continue
+ if not any(ch in lit for ch in 'xXoObB'):
+ self.assertRaises(ValueError, complex, lit)
+
def test_hash(self):
for x in range(-30, 30):
self.assertEqual(hash(x), hash(complex(x, 0)))
diff --git a/Lib/test/test_decimal.py b/Lib/test/test_decimal.py
index 7492f54..617a37e 100644
--- a/Lib/test/test_decimal.py
+++ b/Lib/test/test_decimal.py
@@ -554,6 +554,10 @@ class ExplicitConstructionTest(unittest.TestCase):
self.assertEqual(str(Decimal(' -7.89')), '-7.89')
self.assertEqual(str(Decimal(" 3.45679 ")), '3.45679')
+ # underscores
+ self.assertEqual(str(Decimal('1_3.3e4_0')), '1.33E+41')
+ self.assertEqual(str(Decimal('1_0_0_0')), '1000')
+
# unicode whitespace
for lead in ["", ' ', '\u00a0', '\u205f']:
for trail in ["", ' ', '\u00a0', '\u205f']:
@@ -578,6 +582,9 @@ class ExplicitConstructionTest(unittest.TestCase):
# embedded NUL
self.assertRaises(InvalidOperation, Decimal, "12\u00003")
+ # underscores don't prevent errors
+ self.assertRaises(InvalidOperation, Decimal, "1_2_\u00003")
+
@cpython_only
def test_from_legacy_strings(self):
import _testcapi
@@ -772,6 +779,9 @@ class ExplicitConstructionTest(unittest.TestCase):
self.assertRaises(InvalidOperation, nc.create_decimal, "xyz")
self.assertRaises(ValueError, nc.create_decimal, (1, "xyz", -25))
self.assertRaises(TypeError, nc.create_decimal, "1234", "5678")
+ # no whitespace and underscore stripping is done with this method
+ self.assertRaises(InvalidOperation, nc.create_decimal, " 1234")
+ self.assertRaises(InvalidOperation, nc.create_decimal, "12_34")
# too many NaN payload digits
nc.prec = 3
diff --git a/Lib/test/test_float.py b/Lib/test/test_float.py
index 68b212e..ac8473d 100644
--- a/Lib/test/test_float.py
+++ b/Lib/test/test_float.py
@@ -1,4 +1,3 @@
-
import fractions
import operator
import os
@@ -9,6 +8,8 @@ import time
import unittest
from test import support
+from test.test_grammar import (VALID_UNDERSCORE_LITERALS,
+ INVALID_UNDERSCORE_LITERALS)
from math import isinf, isnan, copysign, ldexp
INF = float("inf")
@@ -60,6 +61,27 @@ class GeneralFloatCases(unittest.TestCase):
float(b'.' + b'1'*1000)
float('.' + '1'*1000)
+ def test_underscores(self):
+ for lit in VALID_UNDERSCORE_LITERALS:
+ if not any(ch in lit for ch in 'jJxXoObB'):
+ self.assertEqual(float(lit), eval(lit))
+ self.assertEqual(float(lit), float(lit.replace('_', '')))
+ for lit in INVALID_UNDERSCORE_LITERALS:
+ if lit in ('0_7', '09_99'): # octals are not recognized here
+ continue
+ if not any(ch in lit for ch in 'jJxXoObB'):
+ self.assertRaises(ValueError, float, lit)
+ # Additional test cases; nan and inf are never valid as literals,
+ # only in the float() constructor, but we don't allow underscores
+ # in or around them.
+ self.assertRaises(ValueError, float, '_NaN')
+ self.assertRaises(ValueError, float, 'Na_N')
+ self.assertRaises(ValueError, float, 'IN_F')
+ self.assertRaises(ValueError, float, '-_INF')
+ self.assertRaises(ValueError, float, '-INF_')
+ # Check that we handle bytes values correctly.
+ self.assertRaises(ValueError, float, b'0_.\xff9')
+
def test_non_numeric_input_types(self):
# Test possible non-numeric types for the argument x, including
# subclasses of the explicitly documented accepted types.
diff --git a/Lib/test/test_grammar.py b/Lib/test/test_grammar.py