From 8af4c5fd7bbd35ea68ef532c554059f3598420dd Mon Sep 17 00:00:00 2001
From: DimitrisJim
Date: Sun, 11 Jun 2023 17:27:59 +0300
Subject: [PATCH 1/8] Upgrade cmd.py and test_cmd.py from Python 3.11.
---
Lib/cmd.py | 10 +++++-----
Lib/test/test_cmd.py | 45 +++++++++++++++++++++++++++++++++-----------
2 files changed, 39 insertions(+), 16 deletions(-)
diff --git a/Lib/cmd.py b/Lib/cmd.py
index 859e91096..88ee7d3dd 100644
--- a/Lib/cmd.py
+++ b/Lib/cmd.py
@@ -310,10 +310,10 @@ class Cmd:
names = self.get_names()
cmds_doc = []
cmds_undoc = []
- help = {}
+ topics = set()
for name in names:
if name[:5] == 'help_':
- help[name[5:]]=1
+ topics.add(name[5:])
names.sort()
# There can be duplicates if routines overridden
prevname = ''
@@ -323,16 +323,16 @@ class Cmd:
continue
prevname = name
cmd=name[3:]
- if cmd in help:
+ if cmd in topics:
cmds_doc.append(cmd)
- del help[cmd]
+ topics.remove(cmd)
elif getattr(self, name).__doc__:
cmds_doc.append(cmd)
else:
cmds_undoc.append(cmd)
self.stdout.write("%s\n"%str(self.doc_leader))
self.print_topics(self.doc_header, cmds_doc, 15,80)
- self.print_topics(self.misc_header, list(help.keys()),15,80)
+ self.print_topics(self.misc_header, sorted(topics),15,80)
self.print_topics(self.undoc_header, cmds_undoc, 15,80)
def print_topics(self, header, cmds, cmdlen, maxcol):
diff --git a/Lib/test/test_cmd.py b/Lib/test/test_cmd.py
index c9ffad485..319801c71 100644
--- a/Lib/test/test_cmd.py
+++ b/Lib/test/test_cmd.py
@@ -6,10 +6,10 @@ Original by Michael Schneider
import cmd
import sys
+import doctest
import unittest
import io
from test import support
-from test.support import import_helper
class samplecmdclass(cmd.Cmd):
"""
@@ -70,7 +70,7 @@ class samplecmdclass(cmd.Cmd):
>>> mycmd.complete_help("12")
[]
>>> sorted(mycmd.complete_help(""))
- ['add', 'exit', 'help', 'shell']
+ ['add', 'exit', 'help', 'life', 'meaning', 'shell']
Test for the function do_help():
>>> mycmd.do_help("testet")
@@ -79,12 +79,20 @@ class samplecmdclass(cmd.Cmd):
help text for add
>>> mycmd.onecmd("help add")
help text for add
+ >>> mycmd.onecmd("help meaning") # doctest: +NORMALIZE_WHITESPACE
+ Try and be nice to people, avoid eating fat, read a good book every
+ now and then, get some walking in, and try to live together in peace
+ and harmony with people of all creeds and nations.
>>> mycmd.do_help("")
Documented commands (type help ):
========================================
add help
+ Miscellaneous help topics:
+ ==========================
+ life meaning
+
Undocumented commands:
======================
exit shell
@@ -115,17 +123,22 @@ class samplecmdclass(cmd.Cmd):
This test includes the preloop(), postloop(), default(), emptyline(),
parseline(), do_help() functions
>>> mycmd.use_rawinput=0
- >>> mycmd.cmdqueue=["", "add", "add 4 5", "help", "help add","exit"]
- >>> mycmd.cmdloop()
+
+ >>> mycmd.cmdqueue=["add", "add 4 5", "", "help", "help add", "exit"]
+ >>> mycmd.cmdloop() # doctest: +REPORT_NDIFF
Hello from preloop
- help text for add
*** invalid number of arguments
9
+ 9
Documented commands (type help ):
========================================
add help
+ Miscellaneous help topics:
+ ==========================
+ life meaning
+
Undocumented commands:
======================
exit shell
@@ -165,6 +178,17 @@ class samplecmdclass(cmd.Cmd):
print("help text for add")
return
+ def help_meaning(self):
+ print("Try and be nice to people, avoid eating fat, read a "
+ "good book every now and then, get some walking in, "
+ "and try to live together in peace and harmony with "
+ "people of all creeds and nations.")
+ return
+
+ def help_life(self):
+ print("Always look on the bright side of life")
+ return
+
def do_exit(self, arg):
return True
@@ -220,13 +244,12 @@ class TestAlternateInput(unittest.TestCase):
"(Cmd) *** Unknown syntax: EOF\n"))
-def test_main(verbose=None):
- from test import test_cmd
- support.run_doctest(test_cmd, verbose)
- support.run_unittest(TestAlternateInput)
+def load_tests(loader, tests, pattern):
+ tests.addTest(doctest.DocTestSuite())
+ return tests
def test_coverage(coverdir):
- trace = import_helper.import_module('trace')
+ trace = support.import_module('trace')
tracer=trace.Trace(ignoredirs=[sys.base_prefix, sys.base_exec_prefix,],
trace=0, count=1)
tracer.run('import importlib; importlib.reload(cmd); test_main()')
@@ -240,4 +263,4 @@ if __name__ == "__main__":
elif "-i" in sys.argv:
samplecmdclass().cmdloop()
else:
- test_main()
+ unittest.main()
From 3d76e1e1db5ed438cd4d9534ceb4c75289ec0b23 Mon Sep 17 00:00:00 2001
From: DimitrisJim
Date: Sun, 11 Jun 2023 22:34:27 +0300
Subject: [PATCH 2/8] Upgrade aifc.py from Python 3.11.
---
Lib/aifc.py | 65 ++++++++++++++++++++++++++++++++++++++++-------------
1 file changed, 49 insertions(+), 16 deletions(-)
diff --git a/Lib/aifc.py b/Lib/aifc.py
index 1916e7ef8..5254987e2 100644
--- a/Lib/aifc.py
+++ b/Lib/aifc.py
@@ -138,7 +138,11 @@ import struct
import builtins
import warnings
-__all__ = ["Error", "open", "openfp"]
+__all__ = ["Error", "open"]
+
+
+warnings._deprecated(__name__, remove=(3, 13))
+
class Error(Exception):
pass
@@ -251,7 +255,9 @@ def _write_float(f, x):
_write_ulong(f, himant)
_write_ulong(f, lomant)
-from chunk import Chunk
+with warnings.catch_warnings():
+ warnings.simplefilter("ignore", DeprecationWarning)
+ from chunk import Chunk
from collections import namedtuple
_aifc_params = namedtuple('_aifc_params',
@@ -447,21 +453,33 @@ class Aifc_read:
#
def _alaw2lin(self, data):
- import audioop
+ with warnings.catch_warnings():
+ warnings.simplefilter('ignore', category=DeprecationWarning)
+ import audioop
return audioop.alaw2lin(data, 2)
def _ulaw2lin(self, data):
- import audioop
+ with warnings.catch_warnings():
+ warnings.simplefilter('ignore', category=DeprecationWarning)
+ import audioop
return audioop.ulaw2lin(data, 2)
def _adpcm2lin(self, data):
- import audioop
+ with warnings.catch_warnings():
+ warnings.simplefilter('ignore', category=DeprecationWarning)
+ import audioop
if not hasattr(self, '_adpcmstate'):
# first time
self._adpcmstate = None
data, self._adpcmstate = audioop.adpcm2lin(data, 2, self._adpcmstate)
return data
+ def _sowt2lin(self, data):
+ with warnings.catch_warnings():
+ warnings.simplefilter('ignore', category=DeprecationWarning)
+ import audioop
+ return audioop.byteswap(data, 2)
+
def _read_comm_chunk(self, chunk):
self._nchannels = _read_short(chunk)
self._nframes = _read_long(chunk)
@@ -497,6 +515,8 @@ class Aifc_read:
self._convert = self._ulaw2lin
elif self._comptype in (b'alaw', b'ALAW'):
self._convert = self._alaw2lin
+ elif self._comptype in (b'sowt', b'SOWT'):
+ self._convert = self._sowt2lin
else:
raise Error('unsupported compression type')
self._sampwidth = 2
@@ -659,7 +679,7 @@ class Aifc_write:
if self._nframeswritten:
raise Error('cannot change parameters after starting to write')
if comptype not in (b'NONE', b'ulaw', b'ULAW',
- b'alaw', b'ALAW', b'G722'):
+ b'alaw', b'ALAW', b'G722', b'sowt', b'SOWT'):
raise Error('unsupported compression type')
self._comptype = comptype
self._compname = compname
@@ -680,7 +700,7 @@ class Aifc_write:
if self._nframeswritten:
raise Error('cannot change parameters after starting to write')
if comptype not in (b'NONE', b'ulaw', b'ULAW',
- b'alaw', b'ALAW', b'G722'):
+ b'alaw', b'ALAW', b'G722', b'sowt', b'SOWT'):
raise Error('unsupported compression type')
self.setnchannels(nchannels)
self.setsampwidth(sampwidth)
@@ -764,28 +784,43 @@ class Aifc_write:
#
def _lin2alaw(self, data):
- import audioop
+ with warnings.catch_warnings():
+ warnings.simplefilter('ignore', category=DeprecationWarning)
+ import audioop
return audioop.lin2alaw(data, 2)
def _lin2ulaw(self, data):
- import audioop
+ with warnings.catch_warnings():
+ warnings.simplefilter('ignore', category=DeprecationWarning)
+ import audioop
return audioop.lin2ulaw(data, 2)
def _lin2adpcm(self, data):
- import audioop
+ with warnings.catch_warnings():
+ warnings.simplefilter('ignore', category=DeprecationWarning)
+ import audioop
if not hasattr(self, '_adpcmstate'):
self._adpcmstate = None
data, self._adpcmstate = audioop.lin2adpcm(data, 2, self._adpcmstate)
return data
+ def _lin2sowt(self, data):
+ with warnings.catch_warnings():
+ warnings.simplefilter('ignore', category=DeprecationWarning)
+ import audioop
+ return audioop.byteswap(data, 2)
+
def _ensure_header_written(self, datasize):
if not self._nframeswritten:
- if self._comptype in (b'ULAW', b'ulaw', b'ALAW', b'alaw', b'G722'):
+ if self._comptype in (b'ULAW', b'ulaw',
+ b'ALAW', b'alaw', b'G722',
+ b'sowt', b'SOWT'):
if not self._sampwidth:
self._sampwidth = 2
if self._sampwidth != 2:
raise Error('sample width must be 2 when compressing '
- 'with ulaw/ULAW, alaw/ALAW or G7.22 (ADPCM)')
+ 'with ulaw/ULAW, alaw/ALAW, sowt/SOWT '
+ 'or G7.22 (ADPCM)')
if not self._nchannels:
raise Error('# channels not specified')
if not self._sampwidth:
@@ -801,6 +836,8 @@ class Aifc_write:
self._convert = self._lin2ulaw
elif self._comptype in (b'alaw', b'ALAW'):
self._convert = self._lin2alaw
+ elif self._comptype in (b'sowt', b'SOWT'):
+ self._convert = self._lin2sowt
def _write_header(self, initlength):
if self._aifc and self._comptype != b'NONE':
@@ -920,10 +957,6 @@ def open(f, mode=None):
else:
raise Error("mode must be 'r', 'rb', 'w', or 'wb'")
-def openfp(f, mode=None):
- warnings.warn("aifc.openfp is deprecated since Python 3.7. "
- "Use aifc.open instead.", DeprecationWarning, stacklevel=2)
- return open(f, mode=mode)
if __name__ == '__main__':
import sys
From 1be262db40c2867249dc153ce1807f5269f97110 Mon Sep 17 00:00:00 2001
From: DimitrisJim
Date: Sun, 11 Jun 2023 23:46:59 +0300
Subject: [PATCH 3/8] Upgrade warnings.py from Python 3.11
---
Lib/warnings.py | 104 ++++++++++++++++++++++++++++++------------------
1 file changed, 65 insertions(+), 39 deletions(-)
diff --git a/Lib/warnings.py b/Lib/warnings.py
index 81f986477..7d8c44001 100644
--- a/Lib/warnings.py
+++ b/Lib/warnings.py
@@ -33,9 +33,8 @@ def _showwarnmsg_impl(msg):
pass
def _formatwarnmsg_impl(msg):
- s = ("%s:%s: %s: %s\n"
- % (msg.filename, msg.lineno, msg.category.__name__,
- msg.message))
+ category = msg.category.__name__
+ s = f"{msg.filename}:{msg.lineno}: {category}: {msg.message}\n"
if msg.line is None:
try:
@@ -55,11 +54,20 @@ def _formatwarnmsg_impl(msg):
if msg.source is not None:
try:
import tracemalloc
- tb = tracemalloc.get_object_traceback(msg.source)
+ # Logging a warning should not raise a new exception:
+ # catch Exception, not only ImportError and RecursionError.
except Exception:
- # When a warning is logged during Python shutdown, tracemalloc
- # and the import machinery don't work anymore
+ # don't suggest to enable tracemalloc if it's not available
+ tracing = True
tb = None
+ else:
+ tracing = tracemalloc.is_tracing()
+ try:
+ tb = tracemalloc.get_object_traceback(msg.source)
+ except Exception:
+ # When a warning is logged during Python shutdown, tracemalloc
+ # and the import machinery don't work anymore
+ tb = None
if tb is not None:
s += 'Object allocated at (most recent call last):\n'
@@ -77,6 +85,9 @@ def _formatwarnmsg_impl(msg):
if line:
line = line.strip()
s += ' %s\n' % line
+ elif not tracing:
+ s += (f'{category}: Enable tracemalloc to get the object '
+ f'allocation traceback\n')
return s
# Keep a reference to check if the function was replaced
@@ -113,7 +124,7 @@ def _formatwarnmsg(msg):
if fw is not _formatwarning_orig:
# warnings.formatwarning() was replaced
return fw(msg.message, msg.category,
- msg.filename, msg.lineno, line=msg.line)
+ msg.filename, msg.lineno, msg.line)
return _formatwarnmsg_impl(msg)
def filterwarnings(action, message="", category=Warning, module="", lineno=0,
@@ -200,7 +211,6 @@ def _processoptions(args):
# Helper for _processoptions()
def _setoption(arg):
- import re
parts = arg.split(':')
if len(parts) > 5:
raise _OptionError("too many fields (max 5): %r" % (arg,))
@@ -209,11 +219,13 @@ def _setoption(arg):
action, message, category, module, lineno = [s.strip()
for s in parts]
action = _getaction(action)
- message = re.escape(message)
category = _getcategory(category)
- module = re.escape(module)
+ if message or module:
+ import re
+ if message:
+ message = re.escape(message)
if module:
- module = module + '$'
+ module = re.escape(module) + r'\Z'
if lineno:
try:
lineno = int(lineno)
@@ -237,26 +249,21 @@ def _getaction(action):
# Helper for _setoption()
def _getcategory(category):
- import re
if not category:
return Warning
- if re.match("^[a-zA-Z0-9_]+$", category):
- try:
- cat = eval(category)
- except NameError:
- raise _OptionError("unknown warning category: %r" % (category,)) from None
+ if '.' not in category:
+ import builtins as m
+ klass = category
else:
- i = category.rfind(".")
- module = category[:i]
- klass = category[i+1:]
+ module, _, klass = category.rpartition('.')
try:
m = __import__(module, None, None, [klass])
except ImportError:
raise _OptionError("invalid module name: %r" % (module,)) from None
- try:
- cat = getattr(m, klass)
- except AttributeError:
- raise _OptionError("unknown warning category: %r" % (category,)) from None
+ try:
+ cat = getattr(m, klass)
+ except AttributeError:
+ raise _OptionError("unknown warning category: %r" % (category,)) from None
if not issubclass(cat, Warning):
raise _OptionError("invalid warning category: %r" % (category,))
return cat
@@ -303,28 +310,16 @@ def warn(message, category=None, stacklevel=1, source=None):
raise ValueError
except ValueError:
globals = sys.__dict__
+ filename = "sys"
lineno = 1
else:
globals = frame.f_globals
+ filename = frame.f_code.co_filename
lineno = frame.f_lineno
if '__name__' in globals:
module = globals['__name__']
else:
module = ""
- filename = globals.get('__file__')
- if filename:
- fnl = filename.lower()
- if fnl.endswith(".pyc"):
- filename = filename[:-1]
- else:
- if module == "__main__":
- try:
- filename = sys.argv[0]
- except AttributeError:
- # embedded interpreters don't have sys.argv, see bug #839151
- filename = '__main__'
- if not filename:
- filename = module
registry = globals.setdefault("__warningregistry__", {})
warn_explicit(message, category, filename, lineno, module, registry,
globals, source)
@@ -437,9 +432,13 @@ class catch_warnings(object):
named 'warnings' and imported under that name. This argument is only useful
when testing the warnings module itself.
+ If the 'action' argument is not None, the remaining arguments are passed
+ to warnings.simplefilter() as if it were called immediately on entering the
+ context.
"""
- def __init__(self, *, record=False, module=None):
+ def __init__(self, *, record=False, module=None,
+ action=None, category=Warning, lineno=0, append=False):
"""Specify whether to record warnings and if an alternative module
should be used other than sys.modules['warnings'].
@@ -450,6 +449,10 @@ class catch_warnings(object):
self._record = record
self._module = sys.modules['warnings'] if module is None else module
self._entered = False
+ if action is None:
+ self._filter = None
+ else:
+ self._filter = (action, category, lineno, append)
def __repr__(self):
args = []
@@ -469,6 +472,8 @@ class catch_warnings(object):
self._module._filters_mutated()
self._showwarning = self._module.showwarning
self._showwarnmsg_impl = self._module._showwarnmsg_impl
+ if self._filter is not None:
+ simplefilter(*self._filter)
if self._record:
log = []
self._module._showwarnmsg_impl = log.append
@@ -488,6 +493,27 @@ class catch_warnings(object):
self._module._showwarnmsg_impl = self._showwarnmsg_impl
+_DEPRECATED_MSG = "{name!r} is deprecated and slated for removal in Python {remove}"
+
+def _deprecated(name, message=_DEPRECATED_MSG, *, remove, _version=sys.version_info):
+ """Warn that *name* is deprecated or should be removed.
+
+ RuntimeError is raised if *remove* specifies a major/minor tuple older than
+ the current Python version or the same version but past the alpha.
+
+ The *message* argument is formatted with *name* and *remove* as a Python
+ version (e.g. "3.11").
+
+ """
+ remove_formatted = f"{remove[0]}.{remove[1]}"
+ if (_version[:2] > remove) or (_version[:2] == remove and _version[3] != "alpha"):
+ msg = f"{name!r} was slated for removal after Python {remove_formatted} alpha"
+ raise RuntimeError(msg)
+ else:
+ msg = message.format(name=name, remove=remove_formatted)
+ warn(msg, DeprecationWarning, stacklevel=3)
+
+
# Private utility function called by _PyErr_WarnUnawaitedCoroutine
def _warn_unawaited_coroutine(coro):
msg_lines = [
From 3150b4ded6b92c9dd2dc8cfcc542e784c95a7b92 Mon Sep 17 00:00:00 2001
From: DimitrisJim
Date: Mon, 12 Jun 2023 00:08:49 +0300
Subject: [PATCH 4/8] Update cgi.py from Python 3.11
---
Lib/cgi.py | 46 +++++++++++++++++++++++++++++++-------------
Lib/test/test_cgi.py | 19 ++++++++++--------
2 files changed, 44 insertions(+), 21 deletions(-)
diff --git a/Lib/cgi.py b/Lib/cgi.py
index c22c71b38..8787567be 100755
--- a/Lib/cgi.py
+++ b/Lib/cgi.py
@@ -13,6 +13,11 @@
This module defines a number of utilities for use by CGI scripts
written in Python.
+
+The global variable maxlen can be set to an integer indicating the maximum size
+of a POST request. POST requests larger than this size will result in a
+ValueError being raised during parsing. The default value of this variable is 0,
+meaning the request size is unlimited.
"""
# History
@@ -41,12 +46,16 @@ from email.message import Message
import html
import locale
import tempfile
+import warnings
__all__ = ["MiniFieldStorage", "FieldStorage", "parse", "parse_multipart",
"parse_header", "test", "print_exception", "print_environ",
"print_form", "print_directory", "print_arguments",
"print_environ_usage"]
+
+warnings._deprecated(__name__, remove=(3,13))
+
# Logging support
# ===============
@@ -77,9 +86,11 @@ def initlog(*allargs):
"""
global log, logfile, logfp
+ warnings.warn("cgi.log() is deprecated as of 3.10. Use logging instead",
+ DeprecationWarning, stacklevel=2)
if logfile and not logfp:
try:
- logfp = open(logfile, "a")
+ logfp = open(logfile, "a", encoding="locale")
except OSError:
pass
if not logfp:
@@ -115,7 +126,8 @@ log = initlog # The current logging function
# 0 ==> unlimited input
maxlen = 0
-def parse(fp=None, environ=os.environ, keep_blank_values=0, strict_parsing=0):
+def parse(fp=None, environ=os.environ, keep_blank_values=0,
+ strict_parsing=0, separator='&'):
"""Parse a query in the environment or from a file (default stdin)
Arguments, all optional:
@@ -134,6 +146,9 @@ def parse(fp=None, environ=os.environ, keep_blank_values=0, strict_parsing=0):
strict_parsing: flag indicating what to do with parsing errors.
If false (the default), errors are silently ignored.
If true, errors raise a ValueError exception.
+
+ separator: str. The symbol to use for separating the query arguments.
+ Defaults to &.
"""
if fp is None:
fp = sys.stdin
@@ -154,7 +169,7 @@ def parse(fp=None, environ=os.environ, keep_blank_values=0, strict_parsing=0):
if environ['REQUEST_METHOD'] == 'POST':
ctype, pdict = parse_header(environ['CONTENT_TYPE'])
if ctype == 'multipart/form-data':
- return parse_multipart(fp, pdict)
+ return parse_multipart(fp, pdict, separator=separator)
elif ctype == 'application/x-www-form-urlencoded':
clength = int(environ['CONTENT_LENGTH'])
if maxlen and clength > maxlen:
@@ -178,10 +193,10 @@ def parse(fp=None, environ=os.environ, keep_blank_values=0, strict_parsing=0):
qs = ""
environ['QUERY_STRING'] = qs # XXX Shouldn't, really
return urllib.parse.parse_qs(qs, keep_blank_values, strict_parsing,
- encoding=encoding)
+ encoding=encoding, separator=separator)
-def parse_multipart(fp, pdict, encoding="utf-8", errors="replace"):
+def parse_multipart(fp, pdict, encoding="utf-8", errors="replace", separator='&'):
"""Parse multipart input.
Arguments:
@@ -194,15 +209,18 @@ def parse_multipart(fp, pdict, encoding="utf-8", errors="replace"):
value is a list of values for that field. For non-file fields, the value
is a list of strings.
"""
- # RFC 2026, Section 5.1 : The "multipart" boundary delimiters are always
+ # RFC 2046, Section 5.1 : The "multipart" boundary delimiters are always
# represented as 7bit US-ASCII.
boundary = pdict['boundary'].decode('ascii')
ctype = "multipart/form-data; boundary={}".format(boundary)
headers = Message()
headers.set_type(ctype)
- headers['Content-Length'] = pdict['CONTENT-LENGTH']
+ try:
+ headers['Content-Length'] = pdict['CONTENT-LENGTH']
+ except KeyError:
+ pass
fs = FieldStorage(fp, headers=headers, encoding=encoding, errors=errors,
- environ={'REQUEST_METHOD': 'POST'})
+ environ={'REQUEST_METHOD': 'POST'}, separator=separator)
return {k: fs.getlist(k) for k in fs}
def _parseparam(s):
@@ -312,7 +330,7 @@ class FieldStorage:
def __init__(self, fp=None, headers=None, outerboundary=b'',
environ=os.environ, keep_blank_values=0, strict_parsing=0,
limit=None, encoding='utf-8', errors='replace',
- max_num_fields=None):
+ max_num_fields=None, separator='&'):
"""Constructor. Read multipart/* until last part.
Arguments, all optional:
@@ -360,6 +378,7 @@ class FieldStorage:
self.keep_blank_values = keep_blank_values
self.strict_parsing = strict_parsing
self.max_num_fields = max_num_fields
+ self.separator = separator
if 'REQUEST_METHOD' in environ:
method = environ['REQUEST_METHOD'].upper()
self.qs_on_post = None
@@ -586,7 +605,7 @@ class FieldStorage:
query = urllib.parse.parse_qsl(
qs, self.keep_blank_values, self.strict_parsing,
encoding=self.encoding, errors=self.errors,
- max_num_fields=self.max_num_fields)
+ max_num_fields=self.max_num_fields, separator=self.separator)
self.list = [MiniFieldStorage(key, value) for key, value in query]
self.skip_lines()
@@ -602,7 +621,7 @@ class FieldStorage:
query = urllib.parse.parse_qsl(
self.qs_on_post, self.keep_blank_values, self.strict_parsing,
encoding=self.encoding, errors=self.errors,
- max_num_fields=self.max_num_fields)
+ max_num_fields=self.max_num_fields, separator=self.separator)
self.list.extend(MiniFieldStorage(key, value) for key, value in query)
klass = self.FieldStorageClass or self.__class__
@@ -646,7 +665,7 @@ class FieldStorage:
else self.limit - self.bytes_read
part = klass(self.fp, headers, ib, environ, keep_blank_values,
strict_parsing, limit,
- self.encoding, self.errors, max_num_fields)
+ self.encoding, self.errors, max_num_fields, self.separator)
if max_num_fields is not None:
max_num_fields -= 1
@@ -736,7 +755,8 @@ class FieldStorage:
last_line_lfend = True
_read = 0
while 1:
- if self.limit is not None and _read >= self.limit:
+
+ if self.limit is not None and 0 <= self.limit <= _read:
break
line = self.fp.readline(1<<16) # bytes
self.bytes_read += len(line)
diff --git a/Lib/test/test_cgi.py b/Lib/test/test_cgi.py
index cc736572b..43164cff3 100644
--- a/Lib/test/test_cgi.py
+++ b/Lib/test/test_cgi.py
@@ -1,4 +1,3 @@
-import cgi
import os
import sys
import tempfile
@@ -6,6 +5,10 @@ import unittest
from collections import namedtuple
from io import StringIO, BytesIO
from test import support
+from test.support import warnings_helper
+
+cgi = warnings_helper.import_deprecated("cgi")
+
class HackedSysModule:
# The regression test will have real values in sys.argv, which
@@ -50,7 +53,7 @@ def do_test(buf, method):
return ComparableException(err)
parse_strict_test_cases = [
- ("", ValueError("bad query field: ''")),
+ ("", {}),
("&", ValueError("bad query field: ''")),
("&&", ValueError("bad query field: ''")),
# Should the next few really be valid?
@@ -123,8 +126,6 @@ class CgiTests(unittest.TestCase):
'file': [b'Testing 123.\n'], 'title': ['']}
self.assertEqual(result, expected)
- # TODO: RUSTPYTHON
- @unittest.expectedFailure
def test_parse_multipart_without_content_length(self):
POSTDATA = '''--JfISa01
Content-Disposition: form-data; name="submit-name"
@@ -174,6 +175,8 @@ Content-Length: 3
fs = cgi.FieldStorage(headers={'content-type':'text/plain'})
self.assertRaises(TypeError, bool, fs)
+ # TODO: RUSTPYTHON
+ @unittest.expectedFailure
def test_strict(self):
for orig, expect in parse_strict_test_cases:
# Test basic parsing
@@ -200,8 +203,6 @@ Content-Length: 3
else:
self.assertEqual(fs.getvalue(key), expect_val[0])
- # TODO: RUSTPYTHON
- @unittest.expectedFailure
def test_separator(self):
parse_semicolon = [
("x=1;y=2.0", {'x': ['1'], 'y': ['2.0']}),
@@ -226,6 +227,7 @@ Content-Length: 3
else:
self.assertEqual(fs.getvalue(key), expect_val[0])
+ @warnings_helper.ignore_warnings(category=DeprecationWarning)
def test_log(self):
cgi.log("Testing")
@@ -578,8 +580,9 @@ this is the content of the fake file
("form-data", {"name": "files", "filename": 'fo"o;bar'}))
def test_all(self):
- not_exported = {"logfile", "logfp", "initlog", "dolog", "nolog",
- "closelog", "log", "maxlen", "valid_boundary"}
+ not_exported = {
+ "logfile", "logfp", "initlog", "dolog", "nolog", "closelog", "log",
+ "maxlen", "valid_boundary"}
support.check__all__(self, cgi, not_exported=not_exported)
From 854d3e4d807db8c82f621aa37711a27e7c481ae5 Mon Sep 17 00:00:00 2001
From: DimitrisJim
Date: Mon, 12 Jun 2023 02:03:08 +0300
Subject: [PATCH 5/8] Update cgitb from Python 3.11
---
Lib/cgitb.py | 23 +++++++++++++++++------
Lib/test/test_cgitb.py | 15 +++++++++------
2 files changed, 26 insertions(+), 12 deletions(-)
diff --git a/Lib/cgitb.py b/Lib/cgitb.py
index 4f81271be..8ce0e833a 100644
--- a/Lib/cgitb.py
+++ b/Lib/cgitb.py
@@ -31,6 +31,11 @@ import tempfile
import time
import tokenize
import traceback
+import warnings
+from html import escape as html_escape
+
+warnings._deprecated(__name__, remove=(3, 13))
+
def reset():
"""Return a string that resets the CGI and browser to a known state."""
@@ -105,10 +110,16 @@ def html(einfo, context=5):
etype = etype.__name__
pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable
date = time.ctime(time.time())
- head = '' + pydoc.html.heading(
- '%s' %
- strong(pydoc.html.escape(str(etype))),
- '#ffffff', '#6622aa', pyver + '
' + date) + '''
+ head = f'''
+
+
+
+
+
+{html_escape(str(etype))} |
+
+{pyver} {date} |
+
A problem occurred in a Python script. Here is the sequence of
function calls leading up to the error, in the order they occurred.
'''
@@ -181,8 +192,8 @@ function calls leading up to the error, in the order they occurred.
'''
diff --git a/Lib/test/test_cgitb.py b/Lib/test/test_cgitb.py
index 5cbb054a3..501c7fcce 100644
--- a/Lib/test/test_cgitb.py
+++ b/Lib/test/test_cgitb.py
@@ -1,8 +1,9 @@
from test.support.os_helper import temp_dir
from test.support.script_helper import assert_python_failure
+from test.support.warnings_helper import import_deprecated
import unittest
import sys
-import cgitb
+cgitb = import_deprecated("cgitb")
class TestCgitb(unittest.TestCase):
@@ -31,7 +32,7 @@ class TestCgitb(unittest.TestCase):
def test_text(self):
try:
raise ValueError("Hello World")
- except ValueError as err:
+ except ValueError:
text = cgitb.text(sys.exc_info())
self.assertIn("ValueError", text)
self.assertIn("Hello World", text)
@@ -41,8 +42,9 @@ class TestCgitb(unittest.TestCase):
rc, out, err = assert_python_failure(
'-c',
('import cgitb; cgitb.enable(logdir=%s); '
- 'raise ValueError("Hello World")') % repr(tracedir))
- out = out.decode(sys.getfilesystemencoding())
+ 'raise ValueError("Hello World")') % repr(tracedir),
+ PYTHONIOENCODING='utf-8')
+ out = out.decode()
self.assertIn("ValueError", out)
self.assertIn("Hello World", out)
self.assertIn("<module>", out)
@@ -56,8 +58,9 @@ class TestCgitb(unittest.TestCase):
rc, out, err = assert_python_failure(
'-c',
('import cgitb; cgitb.enable(format="text", logdir=%s); '
- 'raise ValueError("Hello World")') % repr(tracedir))
- out = out.decode(sys.getfilesystemencoding())
+ 'raise ValueError("Hello World")') % repr(tracedir),
+ PYTHONIOENCODING='utf-8')
+ out = out.decode()
self.assertIn("ValueError", out)
self.assertIn("Hello World", out)
self.assertNotIn('', out)
From 7e3183ef160522e4c7cb41ac2c78690a343bf76a Mon Sep 17 00:00:00 2001
From: DimitrisJim
Date: Mon, 12 Jun 2023 12:30:52 +0300
Subject: [PATCH 6/8] Update chunk from Python 3.11
---
Lib/chunk.py | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/Lib/chunk.py b/Lib/chunk.py
index d94dd3980..618781efd 100644
--- a/Lib/chunk.py
+++ b/Lib/chunk.py
@@ -48,6 +48,10 @@ specifies whether or not chunks are aligned on 2-byte boundaries. The
default is 1, i.e. aligned.
"""
+import warnings
+
+warnings._deprecated(__name__, remove=(3, 13))
+
class Chunk:
def __init__(self, file, align=True, bigendian=True, inclheader=False):
import struct
@@ -64,7 +68,7 @@ class Chunk:
try:
self.chunksize = struct.unpack_from(strflag+'L', file.read(4))[0]
except struct.error:
- raise EOFError
+ raise EOFError from None
if inclheader:
self.chunksize = self.chunksize - 8 # subtract header
self.size_read = 0
From 89323dadc22cd8beca5e7df645d3b5de79e08b21 Mon Sep 17 00:00:00 2001
From: DimitrisJim
Date: Mon, 12 Jun 2023 14:42:10 +0300
Subject: [PATCH 7/8] Update codeop from Python 3.11
---
Lib/codeop.py | 89 ++++------
Lib/test/test_opcode.py | 356 +++++++++++++++++++++++++++++++++++++++
Lib/test/test_opcodes.py | 137 ---------------
3 files changed, 385 insertions(+), 197 deletions(-)
create mode 100644 Lib/test/test_opcode.py
delete mode 100644 Lib/test/test_opcodes.py
diff --git a/Lib/codeop.py b/Lib/codeop.py
index e29c0b38c..2213b69f2 100644
--- a/Lib/codeop.py
+++ b/Lib/codeop.py
@@ -10,30 +10,6 @@ and:
syntax error (OverflowError and ValueError can be produced by
malformed literals).
-Approach:
-
-First, check if the source consists entirely of blank lines and
-comments; if so, replace it with 'pass', because the built-in
-parser doesn't always do the right thing for these.
-
-Compile three times: as is, with \n, and with \n\n appended. If it
-compiles as is, it's complete. If it compiles with one \n appended,
-we expect more. If it doesn't compile either way, we compare the
-error we get when compiling with \n or \n\n appended. If the errors
-are the same, the code is broken. But if the errors are different, we
-expect more. Not intuitive; not even guaranteed to hold in future
-releases; but this matches the compiler's behavior from Python 1.4
-through 2.2, at least.
-
-Caveat:
-
-It is possible (but not likely) that the parser stops parsing with a
-successful outcome before reaching the end of the source; in this
-case, trailing symbols may be ignored instead of causing an error.
-For example, a backslash followed by two newlines may be followed by
-arbitrary garbage. This will be fixed once the API for the parser is
-better.
-
The two interfaces are:
compile_command(source, filename, symbol):
@@ -64,54 +40,50 @@ _features = [getattr(__future__, fname)
__all__ = ["compile_command", "Compile", "CommandCompiler"]
-PyCF_DONT_IMPLY_DEDENT = 0x200 # Matches pythonrun.h
-
+# The following flags match the values from Include/cpython/compile.h
+# Caveat emptor: These flags are undocumented on purpose and depending
+# on their effect outside the standard library is **unsupported**.
+PyCF_DONT_IMPLY_DEDENT = 0x200
+PyCF_ALLOW_INCOMPLETE_INPUT = 0x4000
def _maybe_compile(compiler, source, filename, symbol):
- # Check for source consisting of only blank lines and comments
+ # Check for source consisting of only blank lines and comments.
for line in source.split("\n"):
line = line.strip()
if line and line[0] != '#':
- break # Leave it alone
+ break # Leave it alone.
else:
if symbol != "eval":
source = "pass" # Replace it with a 'pass' statement
- err = err1 = err2 = None
- code = code1 = code2 = None
-
- try:
- code = compiler(source, filename, symbol)
- except SyntaxError:
- pass
-
- # Catch syntax warnings after the first compile
- # to emit warnings (SyntaxWarning, DeprecationWarning) at most once.
+ # Disable compiler warnings when checking for incomplete input.
with warnings.catch_warnings():
- warnings.simplefilter("error")
-
+ warnings.simplefilter("ignore", (SyntaxWarning, DeprecationWarning))
try:
- code1 = compiler(source + "\n", filename, symbol)
- except SyntaxError as e:
- err1 = e
+ compiler(source, filename, symbol)
+ except SyntaxError: # Let other compile() errors propagate.
+ try:
+ compiler(source + "\n", filename, symbol)
+ return None
+ except SyntaxError as e:
+ if "incomplete input" in str(e):
+ return None
+ # fallthrough
- try:
- code2 = compiler(source + "\n\n", filename, symbol)
- except SyntaxError as e:
- err2 = e
+ return compiler(source, filename, symbol)
- try:
- if code:
- return code
- if not code1 and repr(err1) == repr(err2):
- raise err1
- finally:
- err1 = err2 = None
+def _is_syntax_error(err1, err2):
+ rep1 = repr(err1)
+ rep2 = repr(err2)
+ if "was never closed" in rep1 and "was never closed" in rep2:
+ return False
+ if rep1 == rep2:
+ return True
+ return False
def _compile(source, filename, symbol):
- return compile(source, filename, symbol, PyCF_DONT_IMPLY_DEDENT)
-
+ return compile(source, filename, symbol, PyCF_DONT_IMPLY_DEDENT | PyCF_ALLOW_INCOMPLETE_INPUT)
def compile_command(source, filename="", symbol="single"):
r"""Compile a command and determine whether it is incomplete.
@@ -134,15 +106,13 @@ def compile_command(source, filename="", symbol="single"):
"""
return _maybe_compile(_compile, source, filename, symbol)
-
class Compile:
"""Instances of this class behave much like the built-in compile
function, but if one is used to compile text containing a future
statement, it "remembers" and compiles all subsequent program texts
with the statement in force."""
-
def __init__(self):
- self.flags = PyCF_DONT_IMPLY_DEDENT
+ self.flags = PyCF_DONT_IMPLY_DEDENT | PyCF_ALLOW_INCOMPLETE_INPUT
def __call__(self, source, filename, symbol):
codeob = compile(source, filename, symbol, self.flags, True)
@@ -151,7 +121,6 @@ class Compile:
self.flags |= feature.compiler_flag
return codeob
-
class CommandCompiler:
"""Instances of this class have __call__ methods identical in
signature to compile_command; the difference is that if the
diff --git a/Lib/test/test_opcode.py b/Lib/test/test_opcode.py
new file mode 100644
index 000000000..170eb1cb1
--- /dev/null
+++ b/Lib/test/test_opcode.py
@@ -0,0 +1,356 @@
+"""
+ Test cases for codeop.py
+ Nick Mathewson
+"""
+import sys
+import unittest
+import warnings
+from test import support
+from test.support import warnings_helper
+
+from codeop import compile_command, PyCF_DONT_IMPLY_DEDENT
+import io
+
+if support.is_jython:
+
+ def unify_callables(d):
+ for n,v in d.items():
+ if hasattr(v, '__call__'):
+ d[n] = True
+ return d
+
+class CodeopTests(unittest.TestCase):
+
+ def assertValid(self, str, symbol='single'):
+ '''succeed iff str is a valid piece of code'''
+ if support.is_jython:
+ code = compile_command(str, "", symbol)
+ self.assertTrue(code)
+ if symbol == "single":
+ d,r = {},{}
+ saved_stdout = sys.stdout
+ sys.stdout = io.StringIO()
+ try:
+ exec(code, d)
+ exec(compile(str,"","single"), r)
+ finally:
+ sys.stdout = saved_stdout
+ elif symbol == 'eval':
+ ctx = {'a': 2}
+ d = { 'value': eval(code,ctx) }
+ r = { 'value': eval(str,ctx) }
+ self.assertEqual(unify_callables(r),unify_callables(d))
+ else:
+ expected = compile(str, "", symbol, PyCF_DONT_IMPLY_DEDENT)
+ self.assertEqual(compile_command(str, "", symbol), expected)
+
+ def assertIncomplete(self, str, symbol='single'):
+ '''succeed iff str is the start of a valid piece of code'''
+ self.assertEqual(compile_command(str, symbol=symbol), None)
+
+ def assertInvalid(self, str, symbol='single', is_syntax=1):
+ '''succeed iff str is the start of an invalid piece of code'''
+ try:
+ compile_command(str,symbol=symbol)
+ self.fail("No exception raised for invalid code")
+ except SyntaxError:
+ self.assertTrue(is_syntax)
+ except OverflowError:
+ self.assertTrue(not is_syntax)
+
+ # TODO: RUSTPYTHON
+ @unittest.expectedFailure
+ def test_valid(self):
+ av = self.assertValid
+
+ # special case
+ if not support.is_jython:
+ self.assertEqual(compile_command(""),
+ compile("pass", "", 'single',
+ PyCF_DONT_IMPLY_DEDENT))
+ self.assertEqual(compile_command("\n"),
+ compile("pass", "", 'single',
+ PyCF_DONT_IMPLY_DEDENT))
+ else:
+ av("")
+ av("\n")
+
+ av("a = 1")
+ av("\na = 1")
+ av("a = 1\n")
+ av("a = 1\n\n")
+ av("\n\na = 1\n\n")
+
+ av("def x():\n pass\n")
+ av("if 1:\n pass\n")
+
+ av("\n\nif 1: pass\n")
+ av("\n\nif 1: pass\n\n")
+
+ av("def x():\n\n pass\n")
+ av("def x():\n pass\n \n")
+ av("def x():\n pass\n \n")
+
+ av("pass\n")
+ av("3**3\n")
+
+ av("if 9==3:\n pass\nelse:\n pass\n")
+ av("if 1:\n pass\n if 1:\n pass\n else:\n pass\n")
+
+ av("#a\n#b\na = 3\n")
+ av("#a\n\n \na=3\n")
+ av("a=3\n\n")
+ av("a = 9+ \\\n3")
+
+ av("3**3","eval")
+ av("(lambda z: \n z**3)","eval")
+
+ av("9+ \\\n3","eval")
+ av("9+ \\\n3\n","eval")
+
+ av("\n\na**3","eval")
+ av("\n \na**3","eval")
+ av("#a\n#b\na**3","eval")
+
+ av("\n\na = 1\n\n")
+ av("\n\nif 1: a=1\n\n")
+
+ av("if 1:\n pass\n if 1:\n pass\n else:\n pass\n")
+ av("#a\n\n \na=3\n\n")
+
+ av("\n\na**3","eval")
+ av("\n \na**3","eval")
+ av("#a\n#b\na**3","eval")
+
+ av("def f():\n try: pass\n finally: [x for x in (1,2)]\n")
+ av("def f():\n pass\n#foo\n")
+ av("@a.b.c\ndef f():\n pass\n")
+
+ # TODO: RUSTPYTHON
+ @unittest.expectedFailure
+ def test_incomplete(self):
+ ai = self.assertIncomplete
+
+ ai("(a **")
+ ai("(a,b,")
+ ai("(a,b,(")
+ ai("(a,b,(")
+ ai("a = (")
+ ai("a = {")
+ ai("b + {")
+
+ ai("print([1,\n2,")
+ ai("print({1:1,\n2:3,")
+ ai("print((1,\n2,")
+
+ ai("if 9==3:\n pass\nelse:")
+ ai("if 9==3:\n pass\nelse:\n")
+ ai("if 9==3:\n pass\nelse:\n pass")
+ ai("if 1:")
+ ai("if 1:\n")
+ ai("if 1:\n pass\n if 1:\n pass\n else:")
+ ai("if 1:\n pass\n if 1:\n pass\n else:\n")
+ ai("if 1:\n pass\n if 1:\n pass\n else:\n pass")
+
+ ai("def x():")
+ ai("def x():\n")
+ ai("def x():\n\n")
+
+ ai("def x():\n pass")
+ ai("def x():\n pass\n ")
+ ai("def x():\n pass\n ")
+ ai("\n\ndef x():\n pass")
+
+ ai("a = 9+ \\")
+ ai("a = 'a\\")
+ ai("a = '''xy")
+
+ ai("","eval")
+ ai("\n","eval")
+ ai("(","eval")
+ ai("(9+","eval")
+ ai("9+ \\","eval")
+ ai("lambda z: \\","eval")
+
+ ai("if True:\n if True:\n if True: \n")
+
+ ai("@a(")
+ ai("@a(b")
+ ai("@a(b,")
+ ai("@a(b,c")
+ ai("@a(b,c,")
+
+ ai("from a import (")
+ ai("from a import (b")
+ ai("from a import (b,")
+ ai("from a import (b,c")
+ ai("from a import (b,c,")
+
+ ai("[")
+ ai("[a")
+ ai("[a,")
+ ai("[a,b")
+ ai("[a,b,")
+
+ ai("{")
+ ai("{a")
+ ai("{a:")
+ ai("{a:b")
+ ai("{a:b,")
+ ai("{a:b,c")
+ ai("{a:b,c:")
+ ai("{a:b,c:d")
+ ai("{a:b,c:d,")
+
+ ai("a(")
+ ai("a(b")
+ ai("a(b,")
+ ai("a(b,c")
+ ai("a(b,c,")
+
+ ai("a[")
+ ai("a[b")
+ ai("a[b,")
+ ai("a[b:")
+ ai("a[b:c")
+ ai("a[b:c:")
+ ai("a[b:c:d")
+
+ ai("def a(")
+ ai("def a(b")
+ ai("def a(b,")
+ ai("def a(b,c")
+ ai("def a(b,c,")
+
+ ai("(")
+ ai("(a")
+ ai("(a,")
+ ai("(a,b")
+ ai("(a,b,")
+
+ ai("if a:\n pass\nelif b:")
+ ai("if a:\n pass\nelif b:\n pass\nelse:")
+
+ ai("while a:")
+ ai("while a:\n pass\nelse:")
+
+ ai("for a in b:")
+ ai("for a in b:\n pass\nelse:")
+
+ ai("try:")
+ ai("try:\n pass\nexcept:")
+ ai("try:\n pass\nfinally:")
+ ai("try:\n pass\nexcept:\n pass\nfinally:")
+
+ ai("with a:")
+ ai("with a as b:")
+
+ ai("class a:")
+ ai("class a(")
+ ai("class a(b")
+ ai("class a(b,")
+ ai("class a():")
+
+ ai("[x for")
+ ai("[x for x in")
+ ai("[x for x in (")
+
+ ai("(x for")
+ ai("(x for x in")
+ ai("(x for x in (")
+
+ def test_invalid(self):
+ ai = self.assertInvalid
+ ai("a b")
+
+ ai("a @")
+ ai("a b @")
+ ai("a ** @")
+
+ ai("a = ")
+ ai("a = 9 +")
+
+ ai("def x():\n\npass\n")
+
+ ai("\n\n if 1: pass\n\npass")
+
+ ai("a = 9+ \\\n")
+ ai("a = 'a\\ ")
+ ai("a = 'a\\\n")
+
+ ai("a = 1","eval")
+ ai("]","eval")
+ ai("())","eval")
+ ai("[}","eval")
+ ai("9+","eval")
+ ai("lambda z:","eval")
+ ai("a b","eval")
+
+ ai("return 2.3")
+ ai("if (a == 1 and b = 2): pass")
+
+ ai("del 1")
+ ai("del (1,)")
+ ai("del [1]")
+ ai("del '1'")
+
+ ai("[i for i in range(10)] = (1, 2, 3)")
+
+ def test_invalid_exec(self):
+ ai = self.assertInvalid
+ ai("raise = 4", symbol="exec")
+ ai('def a-b', symbol='exec')
+ ai('await?', symbol='exec')
+ ai('=!=', symbol='exec')
+ ai('a await raise b', symbol='exec')
+ ai('a await raise b?+1', symbol='exec')
+
+ def test_filename(self):
+ self.assertEqual(compile_command("a = 1\n", "abc").co_filename,
+ compile("a = 1\n", "abc", 'single').co_filename)
+ self.assertNotEqual(compile_command("a = 1\n", "abc").co_filename,
+ compile("a = 1\n", "def", 'single').co_filename)
+
+ # TODO: RUSTPYTHON
+ @unittest.expectedFailure
+ def test_warning(self):
+ # Test that the warning is only returned once.
+ with warnings_helper.check_warnings(
+ (".*literal", SyntaxWarning),
+ (".*invalid", DeprecationWarning),
+ ) as w:
+ compile_command(r"'\e' is 0")
+ self.assertEqual(len(w.warnings), 2)
+
+ # bpo-41520: check SyntaxWarning treated as an SyntaxError
+ with warnings.catch_warnings(), self.assertRaises(SyntaxError):
+ warnings.simplefilter('error', SyntaxWarning)
+ compile_command('1 is 1', symbol='exec')
+
+ # Check DeprecationWarning treated as an SyntaxError
+ with warnings.catch_warnings(), self.assertRaises(SyntaxError):
+ warnings.simplefilter('error', DeprecationWarning)
+ compile_command(r"'\e'", symbol='exec')
+
+ # TODO: RUSTPYTHON
+ @unittest.expectedFailure
+ def test_incomplete_warning(self):
+ with warnings.catch_warnings(record=True) as w:
+ warnings.simplefilter('always')
+ self.assertIncomplete("'\\e' + (")
+ self.assertEqual(w, [])
+
+ # TODO: RUSTPYTHON
+ @unittest.expectedFailure
+ def test_invalid_warning(self):
+ with warnings.catch_warnings(record=True) as w:
+ warnings.simplefilter('always')
+ self.assertInvalid("'\\e' 1")
+ self.assertEqual(len(w), 1)
+ self.assertEqual(w[0].category, DeprecationWarning)
+ self.assertRegex(str(w[0].message), 'invalid escape sequence')
+ self.assertEqual(w[0].filename, '')
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/Lib/test/test_opcodes.py b/Lib/test/test_opcodes.py
deleted file mode 100644
index e880c3f1a..000000000
--- a/Lib/test/test_opcodes.py
+++ /dev/null
@@ -1,137 +0,0 @@
-# Python test set -- part 2, opcodes
-
-import unittest
-from test import ann_module, support
-
-class OpcodeTest(unittest.TestCase):
-
- def test_try_inside_for_loop(self):
- n = 0
- for i in range(10):
- n = n+i
- try: 1/0
- except NameError: pass
- except ZeroDivisionError: pass
- except TypeError: pass
- try: pass
- except: pass
- try: pass
- finally: pass
- n = n+i
- if n != 90:
- self.fail('try inside for')
-
- def test_setup_annotations_line(self):
- # check that SETUP_ANNOTATIONS does not create spurious line numbers
- try:
- with open(ann_module.__file__, encoding="utf-8") as f:
- txt = f.read()
- co = compile(txt, ann_module.__file__, 'exec')
- self.assertEqual(co.co_firstlineno, 1)
- except OSError:
- pass
-
- def test_default_annotations_exist(self):
- class C: pass
- self.assertEqual(C.__annotations__, {})
-
- def test_use_existing_annotations(self):
- ns = {'__annotations__': {1: 2}}
- exec('x: int', ns)
- self.assertEqual(ns['__annotations__'], {'x': int, 1: 2})
-
- def test_do_not_recreate_annotations(self):
- # Don't rely on the existence of the '__annotations__' global.
- with support.swap_item(globals(), '__annotations__', {}):
- del globals()['__annotations__']
- class C:
- del __annotations__
- with self.assertRaises(NameError):
- x: int
-
- def test_raise_class_exceptions(self):
-
- class AClass(Exception): pass
- class BClass(AClass): pass
- class CClass(Exception): pass
- class DClass(AClass):
- def __init__(self, ignore):
- pass
-
- try: raise AClass()
- except: pass
-
- try: raise AClass()
- except AClass: pass
-
- try: raise BClass()
- except AClass: pass
-
- try: raise BClass()
- except CClass: self.fail()
- except: pass
-
- a = AClass()
- b = BClass()
-
- try:
- raise b
- except AClass as v:
- self.assertEqual(v, b)
- else:
- self.fail("no exception")
-
- # not enough arguments
- ##try: raise BClass, a
- ##except TypeError: pass
- ##else: self.fail("no exception")
-
- try: raise DClass(a)
- except DClass as v:
- self.assertIsInstance(v, DClass)
- else:
- self.fail("no exception")
-
- def test_compare_function_objects(self):
-
- f = eval('lambda: None')
- g = eval('lambda: None')
- self.assertNotEqual(f, g)
-
- f = eval('lambda a: a')
- g = eval('lambda a: a')
- self.assertNotEqual(f, g)
-
- f = eval('lambda a=1: a')
- g = eval('lambda a=1: a')
- self.assertNotEqual(f, g)
-
- f = eval('lambda: 0')
- g = eval('lambda: 1')
- self.assertNotEqual(f, g)
-
- f = eval('lambda: None')
- g = eval('lambda a: None')
- self.assertNotEqual(f, g)
-
- f = eval('lambda a: None')
- g = eval('lambda b: None')
- self.assertNotEqual(f, g)
-
- f = eval('lambda a: None')
- g = eval('lambda a=None: None')
- self.assertNotEqual(f, g)
-
- f = eval('lambda a=0: None')
- g = eval('lambda a=1: None')
- self.assertNotEqual(f, g)
-
- def test_modulo_of_string_subclasses(self):
- class MyString(str):
- def __mod__(self, value):
- return 42
- self.assertEqual(MyString() % 3, 42)
-
-
-if __name__ == '__main__':
- unittest.main()
From 436be2b96aef95bac54e9c250c44d395cdf9c627 Mon Sep 17 00:00:00 2001
From: DimitrisJim
Date: Mon, 12 Jun 2023 15:28:55 +0300
Subject: [PATCH 8/8] Upgrade colorsys from Python 3.11
---
Lib/colorsys.py | 28 +++++++++++++++++-----------
1 file changed, 17 insertions(+), 11 deletions(-)
diff --git a/Lib/colorsys.py b/Lib/colorsys.py
index 12b432537..9bdc83e37 100644
--- a/Lib/colorsys.py
+++ b/Lib/colorsys.py
@@ -1,10 +1,14 @@
"""Conversion functions between RGB and other color systems.
+
This modules provides two functions for each color system ABC:
+
rgb_to_abc(r, g, b) --> a, b, c
abc_to_rgb(a, b, c) --> r, g, b
+
All inputs and outputs are triples of floats in the range [0.0...1.0]
(with the exception of I and Q, which covers a slightly larger range).
Inputs outside the valid range may cause exceptions or invalid outputs.
+
Supported color systems:
RGB: Red, Green, Blue components
YIQ: Luminance, Chrominance (used by composite video signals)
@@ -71,17 +75,18 @@ def yiq_to_rgb(y, i, q):
def rgb_to_hls(r, g, b):
maxc = max(r, g, b)
minc = min(r, g, b)
- # XXX Can optimize (maxc+minc) and (maxc-minc)
- l = (minc+maxc)/2.0
+ sumc = (maxc+minc)
+ rangec = (maxc-minc)
+ l = sumc/2.0
if minc == maxc:
return 0.0, l, 0.0
if l <= 0.5:
- s = (maxc-minc) / (maxc+minc)
+ s = rangec / sumc
else:
- s = (maxc-minc) / (2.0-maxc-minc)
- rc = (maxc-r) / (maxc-minc)
- gc = (maxc-g) / (maxc-minc)
- bc = (maxc-b) / (maxc-minc)
+ s = rangec / (2.0-sumc)
+ rc = (maxc-r) / rangec
+ gc = (maxc-g) / rangec
+ bc = (maxc-b) / rangec
if r == maxc:
h = bc-gc
elif g == maxc:
@@ -120,13 +125,14 @@ def _v(m1, m2, hue):
def rgb_to_hsv(r, g, b):
maxc = max(r, g, b)
minc = min(r, g, b)
+ rangec = (maxc-minc)
v = maxc
if minc == maxc:
return 0.0, 0.0, v
- s = (maxc-minc) / maxc
- rc = (maxc-r) / (maxc-minc)
- gc = (maxc-g) / (maxc-minc)
- bc = (maxc-b) / (maxc-minc)
+ s = rangec / maxc
+ rc = (maxc-r) / rangec
+ gc = (maxc-g) / rangec
+ bc = (maxc-b) / rangec
if r == maxc:
h = bc-gc
elif g == maxc: