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
1 change: 1 addition & 0 deletions Doc/deprecations/pending-removal-in-3.20.rst
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,6 +8,7 @@ Pending removal in Python 3.20
- :mod:`argparse`
- :mod:`csv`
- :mod:`!ctypes.macholib`
- :mod:`decimal` (use :data:`decimal.SPEC_VERSION` instead)
- :mod:`imaplib`
- :mod:`ipaddress`
- :mod:`json`
Expand Down
11 changes: 10 additions & 1 deletion Doc/library/decimal.rst
Original file line numberDiff line numberDiff line change
Expand Up@@ -1569,7 +1569,16 @@ In addition to the three supplied contexts, new contexts can be created with the
Constants
---------

The constants in this section are only relevant for the C module. They
.. data:: SPEC_VERSION

The highest version of the General Decimal Arithmetic
Specification that this implementation complies with.
See https://speleotrove.com/decimal/decarith.html for the specification.

.. versionadded:: next


The following constants are only relevant for the C module. They
are also included in the pure Python version for compatibility.

+---------------------------------+---------------------+-------------------------------+
Expand Down
1 change: 1 addition & 0 deletions Doc/whatsnew/3.15.rst
Original file line numberDiff line numberDiff line change
Expand Up@@ -825,6 +825,7 @@ New deprecations
- :mod:`argparse`
- :mod:`csv`
- :mod:`!ctypes.macholib`
- :mod:`decimal` (use :data:`decimal.SPEC_VERSION` instead)
- :mod:`imaplib`
- :mod:`ipaddress`
- :mod:`json`
Expand Down
17 changes: 14 additions & 3 deletions Lib/_pydecimal.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -47,13 +47,16 @@
'HAVE_THREADS',

# C version: compile time choice that enables the coroutine local context
'HAVE_CONTEXTVAR'
'HAVE_CONTEXTVAR',

# Highest version of the spec this module complies with
'SPEC_VERSION',
]

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

import math as _math
Expand DownExpand Up@@ -6399,3 +6402,11 @@ def _format_number(is_negative, intpart, fracpart, exp, spec):
# _PyHASH_10INV is the inverse of 10 modulo the prime _PyHASH_MODULUS
_PyHASH_10INV = pow(10, _PyHASH_MODULUS - 2, _PyHASH_MODULUS)
del sys

def __getattr__(name):
if name == "__version__":
from warnings import _deprecated

_deprecated("__version__", remove=(3, 20))
return SPEC_VERSION
raise AttributeError(f"module{__name__!r} has no attribute{name!r}")
2 changes: 1 addition & 1 deletion Lib/decimal.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -100,8 +100,8 @@

try:
from _decimal import *
from _decimal import __version__ # noqa: F401
from _decimal import __libmpdec_version__ # noqa: F401
from _decimal import __getattr__ # noqa: F401
except ImportError:
import _pydecimal
import sys
Expand Down
19 changes: 18 additions & 1 deletion Lib/test/test_decimal.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -4474,7 +4474,7 @@ def test_module_attributes(self):
self.assertTrue(C.HAVE_THREADS is True or C.HAVE_THREADS is False)
self.assertTrue(P.HAVE_THREADS is True or P.HAVE_THREADS is False)

self.assertEqual(C.__version__, P.__version__)
self.assertEqual(C.SPEC_VERSION, P.SPEC_VERSION)

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


class TestModule:
def test_deprecated__version__(self):
with self.assertWarnsRegex(
DeprecationWarning,
"'__version__' is deprecated and slated for removal in Python 3.20",
) as cm:
getattr(self.decimal, "__version__")
self.assertEqual(cm.filename, __file__)


@requires_cdecimal
class CTestModule(TestModule, unittest.TestCase):
decimal = C
class PyTestModule(TestModule, unittest.TestCase):
decimal = P


def load_tests(loader, tests, pattern):
if TODO_TESTS is not None:
# Run only Arithmetic tests
Expand Down
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
:mod:`decimal`: Deprecate ``__version__`` and replace with
:data:`decimal.SPEC_VERSION`.
28 changes: 27 additions & 1 deletion Modules/_decimal/_decimal.c
Original file line numberDiff line numberDiff line change
Expand Up@@ -58,6 +58,9 @@

#include "clinic/_decimal.c.h"

#define MPD_SPEC_VERSION "1.70" // Highest version of the spec this complies with
// See https://speleotrove.com/decimal/decarith.html

/*[clinic input]
module _decimal
class _decimal.Decimal "PyObject *" "&dec_spec"
Expand DownExpand Up@@ -7566,12 +7569,35 @@ static PyType_Spec context_spec ={
};


static PyObject *
decimal_getattr(PyObject *self, PyObject *args)
{
PyObject *name;
if (!PyArg_UnpackTuple(args, "__getattr__", 1, 1, &name)){
return NULL;
}

if (PyUnicode_Check(name) && PyUnicode_EqualToUTF8(name, "__version__")){
if (PyErr_WarnEx(PyExc_DeprecationWarning,
"'__version__' is deprecated and slated for removal in Python 3.20",
1) < 0){
return NULL;
}
return PyUnicode_FromString(MPD_SPEC_VERSION);
}

PyErr_Format(PyExc_AttributeError, "module 'decimal' has no attribute %R", name);
return NULL;
}


static PyMethodDef _decimal_methods [] =
{
_DECIMAL_GETCONTEXT_METHODDEF
_DECIMAL_SETCONTEXT_METHODDEF
_DECIMAL_LOCALCONTEXT_METHODDEF
_DECIMAL_IEEECONTEXT_METHODDEF
{"__getattr__", decimal_getattr, METH_VARARGS, "Module __getattr__"},
{NULL, NULL, 1, NULL }
};

Expand DownExpand Up@@ -7891,7 +7917,7 @@ _decimal_exec(PyObject *m)
}

/* Add specification version number */
CHECK_INT(PyModule_AddStringConstant(m, "__version__", "1.70"));
CHECK_INT(PyModule_AddStringConstant(m, "SPEC_VERSION", MPD_SPEC_VERSION));
CHECK_INT(PyModule_AddStringConstant(m, "__libmpdec_version__", mpd_version()));

return 0;
Expand Down
Loading