Skip to content
Open
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
21 changes: 21 additions & 0 deletions Doc/deprecations/pending-removal-in-3.17.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,24 @@ Pending removal in Python 3.17
but it has been retained for backward compatibility, with removal scheduled for Python
3.17. Users should use documented introspection helpers like :func:`typing.get_origin`
and :func:`typing.get_args` instead of relying on private implementation details.

* The ``__version__`` attribute has been deprecated in these standard library
modules and will be removed in Python 3.17.
Use :py:data:`sys.version_info` instead.

- :mod:`argparse`
- :mod:`csv`
- :mod:`!ctypes.macholib`
- :mod:`ipaddress`
- :mod:`json`
- :mod:`logging` (``__date__`` also deprecated)
- :mod:`optparse`
- :mod:`pickle`
- :mod:`platform`
- :mod:`re`
- :mod:`socketserver`
- :mod:`tabnanny`
- :mod:`tkinter.font`
- :mod:`tkinter.ttk`

(Contributed by Hugo van Kemenade in :gh:`76007`.)
31 changes: 31 additions & 0 deletions Doc/whatsnew/3.15.rst
Original file line number Diff line number Diff line change
Expand Up @@ -550,9 +550,40 @@ hashlib

(Contributed by Bénédikt Tran in :gh:`134978`.)

__version__
-----------

* The ``__version__`` attribute has been deprecated in these standard library
modules and will be removed in Python 3.17.
Use :py:data:`sys.version_info` instead.

- :mod:`argparse`
- :mod:`csv`
- :mod:`!ctypes.macholib`
- :mod:`ipaddress`
- :mod:`json`
- :mod:`logging` (``__date__`` also deprecated)
- :mod:`optparse`
- :mod:`pickle`
- :mod:`platform`
- :mod:`re`
- :mod:`socketserver`
- :mod:`tabnanny`
- :mod:`tkinter.font`
- :mod:`tkinter.ttk`

(Contributed by Hugo van Kemenade in :gh:`76007`.)

.. Add deprecations above alphabetically, not here at the end.

.. include:: ../deprecations/pending-removal-in-3.16.rst

.. include:: ../deprecations/pending-removal-in-3.17.rst
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So this will show the same list twice in this page?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, that's how we're already doing it for other ones (I'm not sure if we should, but that's another discussion).


.. include:: ../deprecations/pending-removal-in-3.19.rst

.. include:: ../deprecations/pending-removal-in-future.rst

Removed
=======

Expand Down
10 changes: 9 additions & 1 deletion Lib/argparse.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@
still considered an implementation detail.)
"""

__version__ = '1.1'
__all__ = [
'ArgumentParser',
'ArgumentError',
Expand Down Expand Up @@ -2773,3 +2772,12 @@ def error(self, message):
def _warning(self, message):
args = {'prog': self.prog, 'message': message}
self._print_message(_('%(prog)s: warning: %(message)s\n') % args, _sys.stderr)


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

_deprecated("__version__", remove=(3, 17))
return "1.1" # Do not change
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
11 changes: 9 additions & 2 deletions Lib/csv.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,6 @@ class excel:
"unregister_dialect", "DictReader", "DictWriter",
"unix_dialect"]

__version__ = "1.0"


class Dialect:
"""Describe a CSV dialect.
Expand Down Expand Up @@ -511,3 +509,12 @@ def has_header(self, sample):
hasHeader -= 1

return hasHeader > 0


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

_deprecated("__version__", remove=(3, 17))
return "1.0" # Do not change
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
8 changes: 7 additions & 1 deletion Lib/ctypes/macholib/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,10 @@
And also Apple's documentation.
"""

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

_deprecated("__version__", remove=(3, 17))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PEP 387 says:

It is preferred, though, to wait 5 years before removal (e.g., warn starting in Python 3.10, removal in 3.15; this happens to coincide with the current lifetime of a minor release of Python).

Suggested change
_deprecated("__version__", remove=(3, 17))
_deprecated("__version__", remove=(3, 20))

Or is there a reason to rush this?

return "1.0" # Do not change
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
12 changes: 9 additions & 3 deletions Lib/ipaddress.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,6 @@

"""

__version__ = '1.0'


import functools

IPV4LENGTH = 32
Expand Down Expand Up @@ -2419,3 +2416,12 @@ class _IPv6Constants:

IPv6Address._constants = _IPv6Constants
IPv6Network._constants = _IPv6Constants


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

_deprecated("__version__", remove=(3, 17))
return "1.0" # Do not change
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
10 changes: 9 additions & 1 deletion Lib/json/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,6 @@
$ echo '{ 1.2:3.4}' | python -m json
Expecting property name enclosed in double quotes: line 1 column 3 (char 2)
"""
__version__ = '2.0.9'
__all__ = [
'dump', 'dumps', 'load', 'loads',
'JSONDecoder', 'JSONDecodeError', 'JSONEncoder',
Expand Down Expand Up @@ -357,3 +356,12 @@ def loads(s, *, cls=None, object_hook=None, parse_float=None,
if parse_constant is not None:
kw['parse_constant'] = parse_constant
return cls(**kw).decode(s)


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

_deprecated("__version__", remove=(3, 17))
return "2.0.9" # Do not change
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
16 changes: 13 additions & 3 deletions Lib/logging/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,6 @@

__author__ = "Vinay Sajip <vinay_sajip@red-dove.com>"
__status__ = "production"
# The following module attributes are no longer updated.
__version__ = "0.5.1.2"
__date__ = "07 February 2010"

#---------------------------------------------------------------------------
# Miscellaneous module data
Expand Down Expand Up @@ -2341,3 +2338,16 @@ def captureWarnings(capture):
if _warnings_showwarning is not None:
warnings.showwarning = _warnings_showwarning
_warnings_showwarning = None


def __getattr__(name):
if name in ("__version__", "__date__"):
from warnings import _deprecated

_deprecated(name, remove=(3, 17))
return { # Do not change
"__version__": "0.5.1.2",
"__date__": "07 February 2010",
}[name]

raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
11 changes: 9 additions & 2 deletions Lib/optparse.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@
(options, args) = parser.parse_args()
"""

__version__ = "1.5.3"

__all__ = ['Option',
'make_option',
'SUPPRESS_HELP',
Expand Down Expand Up @@ -1669,3 +1667,12 @@ def _match_abbrev(s, wordmap):
# which will become a factory function when there are many Option
# classes.
make_option = Option


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

_deprecated("__version__", remove=(3, 17))
return "1.5.3" # Do not change
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
1 change: 0 additions & 1 deletion Lib/pickle.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@

Misc variables:

__version__
format_version
compatible_formats

Expand Down
11 changes: 9 additions & 2 deletions Lib/platform.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,6 @@

"""

__version__ = '1.1.0'

import collections
import os
import re
Expand Down Expand Up @@ -1436,5 +1434,14 @@ def _main(args: list[str] | None = None):
print(platform(aliased, terse))


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

_deprecated("__version__", remove=(3, 17))
return "1.1.0" # Do not change
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")


if __name__ == "__main__":
_main()
11 changes: 9 additions & 2 deletions Lib/re/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,8 +137,6 @@
"UNICODE", "NOFLAG", "RegexFlag", "PatternError"
]

__version__ = "2.2.1"

@enum.global_enum
@enum._simple_enum(enum.IntFlag, boundary=enum.KEEP)
class RegexFlag:
Expand Down Expand Up @@ -426,3 +424,12 @@ def scan(self, string):
append(action)
i = j
return result, string[i:]


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

_deprecated("__version__", remove=(3, 17))
return "2.2.1" # Do not change
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
12 changes: 9 additions & 3 deletions Lib/socketserver.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,9 +120,6 @@ class will essentially render the service "deaf" while one request is

# Author of the BaseServer patch: Luke Kenneth Casson Leighton

__version__ = "0.4"


import socket
import selectors
import os
Expand Down Expand Up @@ -861,3 +858,12 @@ def setup(self):

def finish(self):
self.socket.sendto(self.wfile.getvalue(), self.client_address)


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

_deprecated("__version__", remove=(3, 17))
return "0.4" # Do not change
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
11 changes: 9 additions & 2 deletions Lib/tabnanny.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@
# XXX The API needs to undergo changes however; the current code is too
# XXX script-like. This will be addressed later.

__version__ = "6"

import os
import sys
import tokenize
Expand Down Expand Up @@ -334,5 +332,14 @@ def _process_tokens(tokens):
raise NannyNag(start[0], msg, line)


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

_deprecated("__version__", remove=(3, 17))
return "6" # Do not change
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")


if __name__ == '__main__':
main()
10 changes: 10 additions & 0 deletions Lib/test/test_argparse.py
Original file line number Diff line number Diff line change
Expand Up @@ -7356,6 +7356,16 @@ def __init__(self, prog):
'''))


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


def tearDownModule():
# Remove global references to avoid looking like we have refleaks.
RFile.seen = {}
Expand Down
11 changes: 11 additions & 0 deletions Lib/test/test_csv.py
Original file line number Diff line number Diff line change
Expand Up @@ -1603,5 +1603,16 @@ def test_disallow_instantiation(self):
with self.subTest(tp=tp):
check_disallow_instantiation(self, tp)


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


if __name__ == '__main__':
unittest.main()
12 changes: 12 additions & 0 deletions Lib/test/test_ctypes/test_macholib.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,5 +108,17 @@ def test_framework_info(self):
d('P', 'F.framework/Versions/A/F_debug', 'F', 'A', 'debug'))


class TestModule(unittest.TestCase):
def test_deprecated__version__(self):
import ctypes.macholib

with self.assertWarnsRegex(
DeprecationWarning,
"'__version__' is deprecated and slated for removal in Python 3.17",
) as cm:
getattr(ctypes.macholib, "__version__")
self.assertEqual(cm.filename, __file__)


if __name__ == "__main__":
unittest.main()
10 changes: 10 additions & 0 deletions Lib/test/test_ipaddress.py
Original file line number Diff line number Diff line change
Expand Up @@ -2821,5 +2821,15 @@ def testNetworkV6HashCollisions(self):
)


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


if __name__ == '__main__':
unittest.main()
10 changes: 10 additions & 0 deletions Lib/test/test_json/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,16 @@ def test_cjson(self):
'_json')


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


def load_tests(loader, _, pattern):
suite = unittest.TestSuite()
for mod in (json, json.encoder, json.decoder):
Expand Down
Loading
Loading