Skip to content

Commit 0e72e6a

Browse files
authored
Merge branch 'main' into patch-1
2 parents e28eef9 + 00026d1 commit 0e72e6a

File tree

8 files changed

+74
-7
lines changed

8 files changed

+74
-7
lines changed

Doc/deprecations/pending-removal-in-3.20.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ Pending removal in Python 3.20
88
- :mod:`argparse`
99
- :mod:`csv`
1010
- :mod:`!ctypes.macholib`
11+
- :mod:`decimal` (use :data:`decimal.SPEC_VERSION` instead)
1112
- :mod:`imaplib`
1213
- :mod:`ipaddress`
1314
- :mod:`json`

Doc/library/decimal.rst

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1569,7 +1569,16 @@ In addition to the three supplied contexts, new contexts can be created with the
15691569
Constants
15701570
---------
15711571

1572-
The constants in this section are only relevant for the C module. They
1572+
.. data:: SPEC_VERSION
1573+
1574+
The highest version of the General Decimal Arithmetic
1575+
Specification that this implementation complies with.
1576+
See https://speleotrove.com/decimal/decarith.html for the specification.
1577+
1578+
.. versionadded:: next
1579+
1580+
1581+
The following constants are only relevant for the C module. They
15731582
are also included in the pure Python version for compatibility.
15741583

15751584
+---------------------------------+---------------------+-------------------------------+

Doc/whatsnew/3.15.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -851,6 +851,7 @@ New deprecations
851851
- :mod:`argparse`
852852
- :mod:`csv`
853853
- :mod:`!ctypes.macholib`
854+
- :mod:`decimal` (use :data:`decimal.SPEC_VERSION` instead)
854855
- :mod:`imaplib`
855856
- :mod:`ipaddress`
856857
- :mod:`json`

Lib/_pydecimal.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,16 @@
4747
'HAVE_THREADS',
4848

4949
# C version: compile time choice that enables the coroutine local context
50-
'HAVE_CONTEXTVAR'
50+
'HAVE_CONTEXTVAR',
51+
52+
# Highest version of the spec this module complies with
53+
'SPEC_VERSION',
5154
]
5255

5356
__xname__ = __name__ # sys.modules lookup (--without-threads)
5457
__name__ = 'decimal' # For pickling
55-
__version__ = '1.70' # Highest version of the spec this complies with
56-
# See http://speleotrove.com/decimal/
58+
SPEC_VERSION = '1.70' # Highest version of the spec this complies with
59+
# See https://speleotrove.com/decimal/decarith.html
5760
__libmpdec_version__ = "2.4.2" # compatible libmpdec version
5861

5962
import math as _math
@@ -6399,3 +6402,11 @@ def _format_number(is_negative, intpart, fracpart, exp, spec):
63996402
# _PyHASH_10INV is the inverse of 10 modulo the prime _PyHASH_MODULUS
64006403
_PyHASH_10INV = pow(10, _PyHASH_MODULUS - 2, _PyHASH_MODULUS)
64016404
del sys
6405+
6406+
def __getattr__(name):
6407+
if name == "__version__":
6408+
from warnings import _deprecated
6409+
6410+
_deprecated("__version__", remove=(3, 20))
6411+
return SPEC_VERSION
6412+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")

Lib/decimal.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,8 @@
100100

101101
try:
102102
from _decimal import *
103-
from _decimal import __version__ # noqa: F401
104103
from _decimal import __libmpdec_version__ # noqa: F401
104+
from _decimal import __getattr__ # noqa: F401
105105
except ImportError:
106106
import _pydecimal
107107
import sys

Lib/test/test_decimal.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4474,7 +4474,7 @@ def test_module_attributes(self):
44744474
self.assertTrue(C.HAVE_THREADS is True or C.HAVE_THREADS is False)
44754475
self.assertTrue(P.HAVE_THREADS is True or P.HAVE_THREADS is False)
44764476

4477-
self.assertEqual(C.__version__, P.__version__)
4477+
self.assertEqual(C.SPEC_VERSION, P.SPEC_VERSION)
44784478

44794479
self.assertLessEqual(set(dir(C)), set(dir(P)))
44804480
self.assertEqual([n for n in dir(C) if n[:2] != '__'], sorted(P.__all__))
@@ -5929,6 +5929,23 @@ def doit(ty):
59295929
doit('Context')
59305930

59315931

5932+
class TestModule:
5933+
def test_deprecated__version__(self):
5934+
with self.assertWarnsRegex(
5935+
DeprecationWarning,
5936+
"'__version__' is deprecated and slated for removal in Python 3.20",
5937+
) as cm:
5938+
getattr(self.decimal, "__version__")
5939+
self.assertEqual(cm.filename, __file__)
5940+
5941+
5942+
@requires_cdecimal
5943+
class CTestModule(TestModule, unittest.TestCase):
5944+
decimal = C
5945+
class PyTestModule(TestModule, unittest.TestCase):
5946+
decimal = P
5947+
5948+
59325949
def load_tests(loader, tests, pattern):
59335950
if TODO_TESTS is not None:
59345951
# Run only Arithmetic tests
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
:mod:`decimal`: Deprecate ``__version__`` and replace with
2+
:data:`decimal.SPEC_VERSION`.

Modules/_decimal/_decimal.c

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@
5858

5959
#include "clinic/_decimal.c.h"
6060

61+
#define MPD_SPEC_VERSION "1.70" // Highest version of the spec this complies with
62+
// See https://speleotrove.com/decimal/decarith.html
63+
6164
/*[clinic input]
6265
module _decimal
6366
class _decimal.Decimal "PyObject *" "&dec_spec"
@@ -7566,12 +7569,35 @@ static PyType_Spec context_spec = {
75667569
};
75677570

75687571

7572+
static PyObject *
7573+
decimal_getattr(PyObject *self, PyObject *args)
7574+
{
7575+
PyObject *name;
7576+
if (!PyArg_UnpackTuple(args, "__getattr__", 1, 1, &name)) {
7577+
return NULL;
7578+
}
7579+
7580+
if (PyUnicode_Check(name) && PyUnicode_EqualToUTF8(name, "__version__")) {
7581+
if (PyErr_WarnEx(PyExc_DeprecationWarning,
7582+
"'__version__' is deprecated and slated for removal in Python 3.20",
7583+
1) < 0) {
7584+
return NULL;
7585+
}
7586+
return PyUnicode_FromString(MPD_SPEC_VERSION);
7587+
}
7588+
7589+
PyErr_Format(PyExc_AttributeError, "module 'decimal' has no attribute %R", name);
7590+
return NULL;
7591+
}
7592+
7593+
75697594
static PyMethodDef _decimal_methods [] =
75707595
{
75717596
_DECIMAL_GETCONTEXT_METHODDEF
75727597
_DECIMAL_SETCONTEXT_METHODDEF
75737598
_DECIMAL_LOCALCONTEXT_METHODDEF
75747599
_DECIMAL_IEEECONTEXT_METHODDEF
7600+
{"__getattr__", decimal_getattr, METH_VARARGS, "Module __getattr__"},
75757601
{ NULL, NULL, 1, NULL }
75767602
};
75777603

@@ -7891,7 +7917,7 @@ _decimal_exec(PyObject *m)
78917917
}
78927918

78937919
/* Add specification version number */
7894-
CHECK_INT(PyModule_AddStringConstant(m, "__version__", "1.70"));
7920+
CHECK_INT(PyModule_AddStringConstant(m, "SPEC_VERSION", MPD_SPEC_VERSION));
78957921
CHECK_INT(PyModule_AddStringConstant(m, "__libmpdec_version__", mpd_version()));
78967922

78977923
return 0;

0 commit comments

Comments
 (0)